Skip to content

fix(tui): refresh the context cap when switching models without a session - #2978

Open
Win-Hao wants to merge 2 commits into
MoonshotAI:mainfrom
Win-Hao:fix/model-switch-context-cap
Open

fix(tui): refresh the context cap when switching models without a session#2978
Win-Hao wants to merge 2 commits into
MoonshotAI:mainfrom
Win-Hao:fix/model-switch-context-cap

Conversation

@Win-Hao

@Win-Hao Win-Hao commented Aug 16, 2026

Copy link
Copy Markdown

Related Issue

Resolves #2977

Problem

新用户在默认模型配置为 k2.7 时,在首次通过 OAuth 登陆完后,使用 /model 切换模型到 k3(1M),footer 的上下文 ui 不会更新,而是显示上一个模型的上限。显示的既不是坏值也不是报错,而是上一个模型的合法上限,首次使用会让用户觉得很疑惑,质疑是 k3 没有 1M 上下文,还是自己切模型没有成功,普通用户首次使用时会因此停在窗口很长一段时间。

footer 这一栏原样渲染 appState.maxContextTokenscomponents/chrome/footer.ts:341),自身不做任何推导。写这个字段的地方一共四处,其中只有 hydrateLazyConfigDefaultskimi-tui.ts:1790)能在没有会话时生效,且只在启动、/reload、登录后触发。

#2458 起,v2 引擎改为会话懒加载,第一条消息发送之前 session === undefined。此时 /model 命令走 performModelSwitch 的无会话分支(commands/config.ts:515)进入 AuthFlowController.activateModelAfterLogincontrollers/auth-flow.ts:89-101),该分支只写 modelthinkingEffortperformModelSwitch 收尾的 setAppState 也没有写上限。有会话时这条路是通的:session.setModel() 会让引擎发出带 maxContextTokensagent.status.updatedagent-core-v2 profile/profileService.ts:743-765),TUI 在 session-event-handler.ts:712 收下并应用。无会话时既没有这条事件,也没有别的地方补。

影响 0.33.0 至 0.36.1。

What changed

performModelSwitch 在没有会话时补写 maxContextTokens。取值先经 effectiveModelForHost 解析(应用该 alias 的 overrides,与模型选择器展示用的是同一份 effective 记录),再按 maxInputSize ?? maxContextSize 取——与引擎 emitStatusUpdated 报的 max_input_tokens ?? max_context_tokens 口径一致。这样对于"总窗口 1M、输入上限 512k"这类模型,切换后不会先显示较宽的总窗口、等会话建立后又突然掉下来。

hydrateLazyConfigDefaults(启动 / /reload / 登录后的无会话预填)原本读的是原始 alias 的 maxContextSize,这次一并改为同样的解析口径。否则只改切换路径,反而会让启动预填与切换之后的值互相不一致。

这次写入特意用 session === undefined 做了守卫:有会话时这个字段归引擎的 agent.status.updated 管,在这里无条件写会跟权威值打架。若 alias 解析不出来则回落为 0——这是 formatContextStatus 约定的"未知"标记,会退化成只显示百分比,好过继续留着上一个模型的数字。

模型选择器有两个确认入口:Enter 把选择持久化为默认模型(onSelect),Alt+S 只对本次会话生效(onSessionOnlySelect)。两者都汇入 performModelSwitch,唯一的差别是 persist 标志,而这个标志要到状态写入之后才被读取,因此一处改动同时覆盖两条路径。persist: false 的语义没有被触碰——本次改动只往 appState 里增加了一个用于显示的字段,不涉及配置持久化。

回归测试加在 test/tui/kimi-tui-message-flow.test.ts,该套件已经拥有 /model 选择的场景(持久化与 Alt+S 两条),并且已有无会话(engineV2: true)的驱动装置,所以复用它而不是另起一套 host rig。三个用例分别覆盖:Enter 路径、Alt+S 路径、以及输入上限优先于总窗口。三个用例在 origin/main 上分别以 expected 262144 to be 1048576expected 262144 to be 1048576expected 262144 to be 524288 失败,在本分支上通过。

验证:apps/kimi-codetest/tui 共 139 个文件 / 1990 个用例;全仓 pnpm test 共 1134 个文件 / 18721 个用例(唯一一次失败是 apps/vscode 里一个无关的 ENOTEMPTY 临时目录清理竞态,单独重跑通过,且该包并不依赖 CLI 应用);tsc --noEmit 无错误;oxlint --type-aware 对改动文件无新增 warning。changeset:@moonshot-ai/kimi-code patch。

另外做了实机验证:在本地 dev 构建下,未创建会话时用 /model 切换模型,footer 的上下文 ui 能正确更新;并按"总窗口 1M、输入上限 512k"配了一个模型,确认切换后直接显示 512k,而不是先 1M、发出第一条消息后再掉到 512k。

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

…sion

Switching models with /model before the first message left the footer's
context readout on the previous model's limit until the TUI was restarted:
a new user signing in on k2.7 (256k) and switching to k3 (1M) kept seeing
0/256k.

The footer renders appState.maxContextTokens verbatim, and since MoonshotAI#2458 the
v2 engine creates the session lazily, so the session-less branch of
performModelSwitch is the only path that changes the model without an
agent.status.updated event to carry the new cap - and it never set the
field. Derive it from the picked alias there, guarded on the missing
session so the engine keeps owning the value once one exists. Both picker
confirm paths (Enter, Alt+S) funnel through the same code and each gets a
regression test.
@changeset-bot

changeset-bot Bot commented Aug 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c6b9115

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a73a84677

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +546 to +547
patch.maxContextTokens =
host.state.appState.availableModels[effectiveAlias]?.maxContextSize ?? 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prefer the effective input cap when updating the footer

When the selected alias has maxInputSize below maxContextSize, or overrides either value, this copies the raw total window rather than the effective prompt cap. The v2 runtime instead reports effectiveModel.maxInputSize ?? effectiveModel.maxContextSize (packages/agent-core-v2/src/agent/profile/profileService.ts:748-762), so a model such as a 400k-window/272k-input model will show 400k before the first prompt and then abruptly drop to 272k once the session emits status. Resolve the alias through effectiveModelForHost and prefer its maxInputSize here.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已采纳,修在 c6b9115

确认过 ModelAlias 上确实有 maxInputSizepackages/agent-core/src/config/schema.ts:47,注释里举的正是 400k 窗口 / 272k 输入那个例子),而 effectiveModelAlias 会合并 overridespackages/agent-core/src/config/model.ts:13-14),maxContextSize 也在可覆盖字段里——所以读原始 alias 这两点都不对。现在改为先过 effectiveModelForHost,再按 maxInputSize ?? maxContextSize 取,与 profileService.emitStatusUpdated 的口径一致。

另外 hydrateLazyConfigDefaults(启动 / /reload / 登录后的无会话预填)原本也是读原始 alias 的 maxContextSize,只改切换路径会让预填与切换之间反而不一致,所以一并改成同样的解析口径。

新增用例 prefers the declared input cap over the total window 锁住这一点:配一个总窗口 1M、输入上限 512k 的模型,在 origin/main 上以 expected 262144 to be 524288 失败。

@@ -0,0 +1,124 @@
/**

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Extend the existing model-switch test suite

This introduces a separate model-switch test file even though apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts already owns the /model selection scenarios, including persisted and Alt+S paths around lines 5967 and 6025. Move these regression cases into that existing suite rather than adding another host rig and test file that must be maintained in parallel.

AGENTS.md reference: AGENTS.md:L59-L59

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已采纳,修在 c6b9115:删掉这个新文件,用例并入 test/tui/kimi-tui-message-flow.test.ts

指得对——该套件不仅已经拥有 /model 的持久化与 Alt+S 场景,还有现成的无会话(engineV2: true)驱动装置,所以复用 makeDriver 并通过 driver.handleUserInput("/model large") + 真实按键(\r / ESC s)驱动,比另起一套 host rig 更贴近真实路径。

现在共三个用例,均在 origin/main 上失败:

  • refreshes the context cap when /model switches before a session existsexpected 262144 to be 1048576
  • refreshes the context cap on a session-only /model switch before a session existsexpected 262144 to be 1048576
  • prefers the declared input cap over the total windowexpected 262144 to be 524288

… readout

The session-less write added in the previous commit read the raw alias, so it
bypassed `overrides` and ignored `maxInputSize`. The runtime reports
`maxInputSize ?? maxContextSize`, so a model declaring a narrower input cap
than its total window (1M window / 512k input) showed the wider number until a
session existed and then dropped to the narrower one. Resolve the alias through
`effectiveModelForHost` and prefer the input cap, and apply the same resolution
in `hydrateLazyConfigDefaults` so the startup seed and the switch agree.

Move the two regression cases into `kimi-tui-message-flow.test.ts`, which
already owns the `/model` selection scenarios and has a session-less driver
rig, instead of maintaining a second host rig alongside it; add a third case
pinning the input-cap preference.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

在首次使用kimi-code的tui时用 /model 切换模型到K3,底部 的上下文上限ui不刷新,仍显示上一个模型的值

1 participant