diff --git a/.changeset/kimi-code-model-alias-shorthand.md b/.changeset/kimi-code-model-alias-shorthand.md new file mode 100644 index 0000000000..d21e0f2242 --- /dev/null +++ b/.changeset/kimi-code-model-alias-shorthand.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Allow `/model ` to match managed Kimi Code models by shorthand. For example, `/model k3` now resolves to `kimi-code/k3`. diff --git a/apps/kimi-code/src/tui/commands/config.ts b/apps/kimi-code/src/tui/commands/config.ts index 58f1c27acb..eb56813e41 100644 --- a/apps/kimi-code/src/tui/commands/config.ts +++ b/apps/kimi-code/src/tui/commands/config.ts @@ -22,6 +22,7 @@ import { UpdatePreferenceSelectorComponent } from '../components/dialogs/update- import { DEFAULT_TUI_CONFIG, saveTuiConfig, type TuiConfig } from '../config'; import type { ThemeName } from '#/tui/theme'; import { currentTheme, isBuiltInTheme, lightColors, loadCustomThemeMerged } from '#/tui/theme'; +import { DEFAULT_OAUTH_PROVIDER_NAME } from '#/constant/app'; import { NO_ACTIVE_SESSION_MESSAGE } from '../constant/kimi-tui'; import { formatErrorMessage } from '../utils/event-payload'; import { thinkingEffortToConfig } from '../utils/thinking-config'; @@ -237,14 +238,23 @@ export async function handleThemeCommand(host: SlashCommandHost, args: string): } export async function handleModelCommand(host: SlashCommandHost, args: string): Promise { - const alias = args.trim(); + const input = args.trim(); + let alias = input; await refreshModelsForPicker(host); if (alias.length === 0) { showModelPicker(host); return; } - if (host.state.appState.availableModels[alias] === undefined) { - host.showError(`Unknown model alias: ${alias}`); + const availableModels = host.state.appState.availableModels; + if (availableModels[alias] === undefined && !alias.includes('/')) { + const managedPrefix = DEFAULT_OAUTH_PROVIDER_NAME.slice('managed:'.length); + const managedAlias = `${managedPrefix}/${alias}`; + if (availableModels[managedAlias] !== undefined) { + alias = managedAlias; + } + } + if (availableModels[alias] === undefined) { + host.showError(`Unknown model alias: ${input}`); return; } showModelPicker(host, alias); diff --git a/apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts b/apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts index 13ee90ceba..5ae89a69cb 100644 --- a/apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts +++ b/apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts @@ -5126,6 +5126,42 @@ command = "vim" expect(refreshProviderModels).not.toHaveBeenCalled(); }); + it('resolves /model shorthand to the managed Kimi Code alias', async () => { + const session = makeSession(); + const { driver } = await makeDriver(session, { + getConfig: vi.fn(async () => ({ + models: { + k2: { + provider: 'managed:kimi-code', + model: 'kimi-k2', + maxContextSize: 100, + displayName: 'Kimi K2', + capabilities: ['thinking'], + }, + 'kimi-code/k3': { + provider: 'managed:kimi-code', + model: 'kimi-k3', + maxContextSize: 100, + displayName: 'K3', + capabilities: ['thinking'], + }, + }, + defaultModel: 'k2', + thinking: { enabled: false }, + })), + }); + + driver.handleUserInput('/model k3'); + + await vi.waitFor(() => { + const picker = driver.state.editorContainer.children[0]; + expect(picker).toBeInstanceOf(TabbedModelSelectorComponent); + const output = stripSgr((picker as TabbedModelSelectorComponent).render(120).join('\n')); + expect(output).toMatch(/❯ K3\s+Kimi Code/); + }); + expect(session.setModel).not.toHaveBeenCalled(); + }); + it('opens /model picker after 2s when OAuth refresh is still pending', async () => { const { driver } = await makeDriver(makeSession(), { getConfig: vi.fn(async () => ({