MoonshotAI / MoonshotAI/kimi-code
fix(tui): /provider 命令 UI 文案承诺 refresh 但未实现入口,且 refresh 端点对无 source 的 provider 是 no-op
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
现象
TUI 里 /provider 命令打开的 Provider Manager,文案明明写着可以 refresh,但 UI 上找不到任何 refresh 操作,只能 add / delete。手动调 kap-server 的 POST /api/v1/providers:refresh 端点,对没存 source 的 provider 也是空打(orchestrator 直接跳过、零网络请求),UI state 也不会更新。要让模型列表真正刷新,只能删掉再重新 add("reconnect")才行,绕了一大圈。
复现步骤里详细列了三条独立的失败路径。
版本
kimi --version输出(0.29.0)- kap-server:
http://127.0.0.1:58627,单实例 daemon 模式 - 触发问题的 provider(本机环境样例,不代表所有用户):
minimax-cn-coding-plan(type: anthropic,无source字段)opencode-go(type: openai,无source字段)managed:kimi-code(type: kimi,OAuth-managed)
平台
macOS(arch64),loopback daemon。
期望行为
/providerUI 里有一个显式的 refresh 操作(按键 + 底部 hint 提示),点了之后真的去拉远端模型列表并刷新 UI。POST /api/v1/providers:refresh(含:refresh_oauth和单 provider 的{id}:refresh)对所有已配置 provider 都能产生预期效果:对内置 managed / OAuth / 自定义 registry 的 provider 拉远端/models;对其他类型的 provider 至少给出明确说明("此 provider 无可刷新的远端来源"),而不是静默 no-op。- 远端刷新后 TUI 端的
availableProviders/availableModels内存 state 应当跟着 reload,不管 orchestrator 的changed列表是否为空。
复现步骤
步骤 1 — UX 文案与实现不一致
打开 TUI,输入 /provider:
- 顶部 hint 实际显示:
↑↓ navigate · D delete · Esc cancel(apps/kimi-code/src/tui/components/dialogs/provider-manager.ts:48) - 命令注册描述却写着:
Manage AI providers (add / delete / refresh)(apps/kimi-code/src/tui/commands/registry.ts:197)
→ "refresh" 在命令描述里被承诺,但 UI 既没有 R 键也没有对应 callback(ProviderManagerOptions 接口只有 onAdd / onDeleteSource / onClose,handleInput 只识别方向键 / Enter / D / Esc)。
步骤 2 — 后台 refresh 对 UI 不可见,且对多数 provider 是 no-op
apps/kimi-code/src/tui/kimi-tui.ts:731-735:
await this.authFlow.refreshAvailableModels();
void this.refreshProviderModelsInBackground();
后台 fire-and-forget 调用 AuthFlowController.refreshProviderModels()(scope=all)。但底层 refreshProviderModels()(packages/oauth/src/refreshProviderModels.ts:377-766)的 4 个分支是:
source.kind === 'apiJson'(自定义 registry)- Managed Kimi Code OAuth
- Open Platform
- Managed Kimi Code endpoint API-key(强匹配
type=kimi且base_url命中 managed endpoint)
minimax-cn-coding-plan / opencode-go 这类普通带 apiKey 的 anthropic/openai provider,4 个分支一个都不命中,orchestrator 直接跳过、零网络请求。
步骤 3 — 即使真的改了 config.toml,TUI 也不刷 UI state
apps/kimi-code/src/tui/controllers/auth-flow.ts:168-187:
private async refreshProviderModelsWithScope(scope) {
const result = await refreshAllProviderModels(...);
if (result.changed.length > 0) {
await this.refreshAvailableModels(); // 只有 changed 才 setAppState
}
return result;
}
→ 假设一个 provider 真的能刷新(比如 managed:kimi-code),但 orchestrator 判断"没有变化"时,TUI 端的 availableProviders / availableModels 内存 state 也不会被 reload。
步骤 4 — Reconnect 之所以有效,是因为它绕过上面所有判定
走 apps/kimi-code/src/tui/commands/provider.ts:248:
await host.authFlow.refreshConfigAfterLogin();
refreshConfigAfterLogin()(auth-flow.ts:118-139)无条件 setAppState({ availableModels, availableProviders, ... }),不依赖 result.changed 判定,强制覆盖内存 state。同时 applyCatalogProvider() 把整个 model alias 列表重写一遍,所以 UI 立刻对了。
端点复现
TOK=$(cat ~/.kimi-code/server.token)
curl -sS -X POST -H "Authorization: Bearer $TOK" \
http://127.0.0.1:58627/api/v1/providers:refresh | python3 -m json.tool
实际响应里 minimax-cn-coding-plan 和 opencode-go 要么 status: "unchanged",要么根本不在 results 列表里 —— 因为 orchestrator 没尝试刷它们。
根因小结
| 层 | 问题 |
|---|---|
/provider UI |
命令描述文案承诺 refresh,但 ProviderManagerComponent 没绑 R 键,没 onRefresh callback |
| refresh orchestrator | 只覆盖 4 类可识别 provider,对无 source 的 provider 静默 no-op |
| TUI state 同步 | refreshProviderModelsWithScope 只在 changed.length > 0 时调 refreshAvailableModels(),UI state 容易过期 |
| "reconnect" 路径 | 绕过所有上述判定,强制 setAppState,所以看起来"work" |
建议方向(仅供参考,等 maintainer 拍板)
最小修复(仅 UX 一致性 + state 同步):
ProviderManagerComponent加R键、onRefreshcallback、HEADER_HINT加· R refreshProviderManagerOptions接口加onRefresh: (providerIds) => void- 命令侧接到
authFlow.refreshProviderModels({ providerIds }),无论changed与否都跑一次refreshAvailableModels()
根本修复(同时解决 orchestrator 不认的问题):
applyCatalogProvider()(packages/node-sdk/src/catalog.ts:130)写入provider.source = { kind: 'modelsDev', url },保留 provenancerefreshProviderModels.ts新增source.kind === 'modelsDev'分支:按 URL 分组 fetch 整个 catalog,只 apply 对应 provider(避免 N 个 provider 重复请求 N 次)- 旧配置迁移要谨慎 —— 历史 import 项没 source,不建议按 provider id 盲猜是 models.dev 来的;让用户首次显式 refresh 时再补 provenance
第 4–6 条跟 catalog 的 provenance 缺失相关,可以参考现存的相关讨论(如 issue #1966 关于 custom registry api.json 的扩展)。
备注
- 我没在 v2 engine 上复现这条问题(
packages/agent-core-v2的IProviderDiscoveryService也走同一套refreshProviderModels),但 web UI 通过apps/kimi-web/src/App.vue:420-422调同一个 REST 端点,理论上同样会受影响。 - 按 CONTRIBUTING.md "Discuss first" 原则,先开 issue,等 maintainer 反馈后再开 PR。
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/kimi-code/src/tui/components/dialogs/provider-manager.ts, commands/registry.ts, and commands/provider.ts to trace the provider UI and refresh entry point. Then read apps/kimi-code/src/tui/controllers/auth-flow.ts, packages/oauth/src/refreshProviderModels.ts, and packages/node-sdk/src/catalog.ts, using the documented curl request to inspect endpoint results. Done means the refresh action, provider handling, and TUI available-model state behave consistently for supported and unsupported providers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100