diff --git a/.changeset/status-line-provider.md b/.changeset/status-line-provider.md new file mode 100644 index 0000000000..b4dc915fc9 --- /dev/null +++ b/.changeset/status-line-provider.md @@ -0,0 +1,6 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Add a configurable status line slot for the active model provider. Add `provider` before `model` +in `[status_line].items` to display it. diff --git a/apps/kimi-code/src/tui/components/chrome/footer.ts b/apps/kimi-code/src/tui/components/chrome/footer.ts index 4bb8a75f9b..f4e24e99c8 100644 --- a/apps/kimi-code/src/tui/components/chrome/footer.ts +++ b/apps/kimi-code/src/tui/components/chrome/footer.ts @@ -362,6 +362,7 @@ export class FooterComponent implements Component { const slots: Record = { mode: [], goal: [], + provider: [], model: [], tasks: [], cwd: [], @@ -386,11 +387,14 @@ export class FooterComponent implements Component { if (goalBadge !== null) slots['goal'] = [goalBadge]; const model = modelDisplayName(state); + const rawCurrentModel = state.availableModels[state.model]; + const currentModel = + rawCurrentModel === undefined ? undefined : effectiveModelAlias(rawCurrentModel); + if (currentModel?.provider) { + slots['provider'] = [chalk.hex(colors.text)(currentModel.provider)]; + } if (model) { const effort = state.thinkingEffort; - const rawCurrentModel = state.availableModels[state.model]; - const currentModel = - rawCurrentModel === undefined ? undefined : effectiveModelAlias(rawCurrentModel); // Only effort-capable models (those declaring support_efforts) show the // concrete effort; legacy boolean models keep the plain "thinking" suffix. const hasEfforts = (currentModel?.supportEfforts?.length ?? 0) > 0; diff --git a/apps/kimi-code/src/tui/config.ts b/apps/kimi-code/src/tui/config.ts index 36f43ba07b..6012795743 100644 --- a/apps/kimi-code/src/tui/config.ts +++ b/apps/kimi-code/src/tui/config.ts @@ -30,7 +30,16 @@ export const UpgradePreferencesSchema = z.object({ autoInstall: z.boolean(), }); -export const STATUS_LINE_ITEMS = ['mode', 'goal', 'model', 'tasks', 'cwd', 'git', 'tips'] as const; +export const STATUS_LINE_ITEMS = [ + 'mode', + 'goal', + 'provider', + 'model', + 'tasks', + 'cwd', + 'git', + 'tips', +] as const; export type StatusLineItem = (typeof STATUS_LINE_ITEMS)[number]; export const StatusLineFileConfigSchema = z.object({ diff --git a/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts b/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts index a6be39adfb..e3d9e95ba3 100644 --- a/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts +++ b/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts @@ -60,6 +60,25 @@ function plain(text: string): string { } describe('FooterComponent status_line items', () => { + it('renders the active model provider as a configurable slot', () => { + const state: AppState = { + ...baseState, + model: 'custom-model', + availableModels: { + 'custom-model': { + provider: 'custom-provider', + model: 'upstream-model', + displayName: 'Model Name', + maxContextSize: 128_000, + }, + }, + statusLine: { items: ['provider', 'model'], command: null }, + }; + const footer = new FooterComponent(state); + + expect(plain(footer.render(120)[0]!).trimEnd()).toBe('custom-provider Model Name'); + }); + it('renders only the chosen slots in the given order', () => { const state: AppState = { ...baseState, diff --git a/apps/kimi-code/test/tui/config.test.ts b/apps/kimi-code/test/tui/config.test.ts index 664fda616f..b25326d6e2 100644 --- a/apps/kimi-code/test/tui/config.test.ts +++ b/apps/kimi-code/test/tui/config.test.ts @@ -164,12 +164,12 @@ describe('TUI config status_line', () => { it('parses items and command', () => { const config = parseTuiConfig(` [status_line] -items = ["model", "git", "cwd"] +items = ["provider", "model", "git", "cwd"] command = "~/.kimi-code/statusline.sh" `); expect(config.statusLine).toEqual({ - items: ['model', 'git', 'cwd'], + items: ['provider', 'model', 'git', 'cwd'], command: '~/.kimi-code/statusline.sh', }); }); diff --git a/docs/en/configuration/config-files.md b/docs/en/configuration/config-files.md index b671922578..0771f5f31a 100644 --- a/docs/en/configuration/config-files.md +++ b/docs/en/configuration/config-files.md @@ -392,7 +392,7 @@ Alongside `config.toml`, the CLI keeps terminal-UI and client preferences in a c | `[notifications].enabled` | `boolean` | `true` | Whether desktop notifications are sent | | `[notifications].notification_condition` | `string` | `unfocused` | When to notify: `unfocused` (only when the terminal is not focused) or `always` | | `[upgrade].auto_install` | `boolean` | `true` | Whether new versions are installed automatically | -| `[status_line].items` | `string[]` | `[]` | Built-in slots to show on the first footer line and their order: `mode`, `goal`, `model`, `tasks`, `cwd`, `git`, `tips`. Unset keeps the default layout; unknown ids are skipped with a warning | +| `[status_line].items` | `string[]` | `[]` | Built-in slots to show on the first footer line and their order: `mode`, `goal`, `provider`, `model`, `tasks`, `cwd`, `git`, `tips`. The optional `provider` slot shows the active model's provider before or after any other slot. Unset keeps the default layout; unknown ids are skipped with a warning | | `[status_line].command` | `string` | `""` | Custom status line command. Its first stdout line replaces the first footer line, with a JSON snapshot (model, cwd, git branch, permission mode, plan mode, context usage, session id, version) passed on stdin. Runs are capped at 300ms and throttled to once per second; failures fall back to the built-in layout | ```toml diff --git a/docs/zh/configuration/config-files.md b/docs/zh/configuration/config-files.md index 478959acf6..dded46ad8f 100644 --- a/docs/zh/configuration/config-files.md +++ b/docs/zh/configuration/config-files.md @@ -392,7 +392,7 @@ MCP server 的声明配置写在 `~/.kimi-code/mcp.json` 或项目内 `.kimi-cod | `[notifications].enabled` | `boolean` | `true` | 是否发送桌面通知 | | `[notifications].notification_condition` | `string` | `unfocused` | 何时通知:`unfocused`(仅终端失去焦点时)或 `always`(总是) | | `[upgrade].auto_install` | `boolean` | `true` | 是否自动安装新版本 | -| `[status_line].items` | `string[]` | `[]` | 底部状态栏第一行展示哪些内置槽位及其顺序:`mode`、`goal`、`model`、`tasks`、`cwd`、`git`、`tips`。缺省保持默认布局;未知 id 跳过并告警 | +| `[status_line].items` | `string[]` | `[]` | 底部状态栏第一行展示哪些内置槽位及其顺序:`mode`、`goal`、`provider`、`model`、`tasks`、`cwd`、`git`、`tips`。可选的 `provider` 槽位会按配置顺序显示当前模型的提供商。缺省保持默认布局;未知 id 跳过并告警 | | `[status_line].command` | `string` | `""` | 自定义状态栏命令。其 stdout 第一行替换状态栏第一行,stdin 会收到 JSON 快照(model、cwd、git 分支、permission 模式、plan 模式、上下文用量、session id、版本)。运行上限 300ms、每秒最多一次;失败时回退内置布局 | ```toml