-
Notifications
You must be signed in to change notification settings - Fork 1.9k
feat(modes): add per-mode Kilo Code model overrides #5252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- persist per-mode model selections via new `modeModelOverrides` global setting - add webview message to set/clear overrides and update extension state - apply override on mode switch only when Kilo Code gateway models are available - add Modes UI model selector backed by routerModels plus coverage updates
Extract per-mode Kilo Code model override UI into a dedicated component with searchable combobox, provider-aware enable/disable behavior, and updated tests for helper text and selection actions
When updating the override for the active mode, immediately update the active Kilo Code model (only when gateway models are available) so users don’t need to switch modes to see the change. Expose a provider getter and add coverage for the new behavior.
🦋 Changeset detectedLatest commit: 53c1655 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
Ensure per-mode Kilo Code model overrides take precedence when restoring tasks from history, even if the activated provider profile specifies a different model. Skip applying when gateway models are unavailable and log failures to avoid breaking restore flow.
Ensure custom modes schema validation failures surface an error message for all files, with fallbacks when i18n or VS Code APIs are unavailable, to avoid silent failures and reduce test flakiness. Update YAML edge case tests to use hoist-safe vscode mocks, mock i18n, and dynamically import CustomModesManager for deterministic assertions.
Ensure Kilo Code per-mode overrides are only applied when the Kilo Code provider is active and gateway models are available (with a best-effort refresh to avoid stale availability state). Re-apply the override when activating/switching provider profiles and validate the setModeModelOverride payload via a shared Zod schema. Also localize the mode model picker UI strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements per-mode model overrides for Kilo Code gateway models, allowing users to configure different models for different modes (e.g., code, architect) while maintaining the default model behavior when no override is set.
Changes:
- Added UI component and state management for selecting per-mode Kilo Code gateway models
- Implemented persistence and application logic for mode-specific model overrides with safety gates
- Added comprehensive test coverage for the new feature across UI and backend components
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| webview-ui/src/i18n/locales/*/kilocode.json | Added translations for mode model picker UI in 20 locales |
| webview-ui/src/components/kilocode/KiloModeModelPicker.tsx | New component for selecting per-mode Kilo Code gateway models |
| webview-ui/src/components/modes/ModesView.tsx | Integrated KiloModeModelPicker into modes settings UI |
| webview-ui/src/components/modes/tests/ModesView.spec.tsx | Added tests for mode model picker UI behavior |
| src/shared/WebviewMessage.ts | Added setModeModelOverride message type and payload schema |
| src/shared/ExtensionMessage.ts | Added modeModelOverrides to extension state |
| packages/types/src/global-settings.ts | Added modeModelOverrides to global settings schema |
| src/core/webview/ClineProvider.ts | Added gateway models availability tracking and model override application logic |
| src/core/webview/webviewMessageHandler.ts | Implemented setModeModelOverride message handler with immediate application |
| src/core/webview/tests/ClineProvider.sticky-mode.spec.ts | Added tests for mode override application during mode switch |
| src/tests/modeModelOverride-active-update.spec.ts | New test file for active mode model override updates |
| src/core/config/CustomModesManager.ts | Enhanced schema validation error handling (unrelated improvement) |
| src/core/config/tests/CustomModesManager.yamlEdgeCases.spec.ts | Updated tests to handle improved error messaging |
Code Review SummaryStatus: 6 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (42 files)
SummaryThis PR adds per-mode model override functionality for the Kilo Code gateway provider. The implementation is well-structured with:
The existing inline comments cover the identified issues. Most are minor suggestions or warnings that don't block the merge. |
Add stable data-testid attributes to KiloModeModelPicker helper text and update ModesView tests to assert via test IDs instead of strings.
Ensure mode model overrides are applied for any non-null payload value and explicitly return undefined for non-typical providers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 35 out of 35 changed files in this pull request and generated 1 comment.
- Update active model when the current mode’s model override is cleared (null) so the UI stays in sync without a mode switch - Ensure schema validation failures surface a single error toast with safe fallback behavior (keeps tests deterministic) - Normalize kilocode marker comments
Remove defensive null checks around router/kilocode model maps and call setKilocodeGatewayModelsAvailable directly to ensure availability is consistently updated.
Allow custom mode definitions (YAML/JSON) to specify an optional provider-agnostic `model` field and automatically derive persisted `modeModelOverrides` from merged custom modes, clearing overrides when a mode omits `model` while leaving non-custom slugs untouched.
Stop reapplying per-mode overrides when updating the current mode or activating provider profiles. Mirror modeModelOverrides from ExtensionContext.globalState into ContextProxy on startup so the webview renders the latest overrides immediately.
Do not delete existing mode model overrides when custom modes omit `mode.model`, and avoid unnecessary globalState writes during refresh. Also mirror `modeModelOverrides` into ContextProxy so the webview updates immediately after YAML-driven changes.
Allow KiloModeModelPicker to be controlled via selectedModelId/onSelectModelId so create-mode flow can defer persistence until submit. Persist the selected model override after mode creation and add test ids + coverage for the new dialog behavior.
|
I'm not too happy about code quality here - I'm open to ideas on how to make it better. |
Use optional chaining when calling `setKilocodeGatewayModelsAvailable` to avoid errors with partial provider mocks in unit tests.
| - **恢复文件和任务** - 恢复工作区文件并删除所有后续对话消息。当您希望将代码和对话完全重置回检查点的时间点时使用。此选项需要在对话框中进行确认,因为它无法撤消。 | ||
|
|
||
| <img src="/docs/img/checkpoints/checkpoints-9.png" alt="恢复文件和任务检查点的确认对话框" width="300" /> | ||
| <img src="/docs/img/checkpoints/checkpoints-9.png" alt="恢复文件和任务检查点的确认对话框" width="300" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to extend the docs for this not anyway for the user?
| this.context.globalState.get<Record<string, string>>("modeModelOverrides") ?? {} | ||
| await this.contextProxy.setValue("modeModelOverrides", overridesFromGlobalState) | ||
| } catch { | ||
| // non-fatal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we log this or handle explicitly? UI should not stay stale here, we should inform the user about the failure.
| // kilocode_change start: per-mode overrides are Kilo Code-specific | ||
| // Prevent accidentally writing a Kilo Code gateway model id into another provider's model-id field. | ||
| if (provider !== "kilocode") { | ||
| return | ||
| } | ||
| // kilocode_change end: per-mode overrides are Kilo Code-specific |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nested kilocode_change markers?
| const { name, id, ...providerSettingsFromProfile } = await this.providerSettingsManager.activateProfile(args) | ||
| let providerSettings = providerSettingsFromProfile | ||
| // kilocode_change: do NOT re-apply per-mode override here; it should only happen during mode switches. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should wrapp here kilocode_change properly
| provider.context.globalState.get<Record<string, string>>("modeModelOverrides") ?? {} | ||
| await updateGlobalState("modeModelOverrides", overridesFromGlobalState) | ||
| } catch { | ||
| // non-fatal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should log here.
| // CustomModesManager updates `context.globalState` directly (not through ContextProxy), so we need to | ||
| // mirror `modeModelOverrides` into ContextProxy so the webview can render it immediately. | ||
| try { | ||
| const overridesFromGlobalState = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks very similar to above, not sure if its possible to exact this logic out into a new file, then we just need a marker for the file and can delegate.
| updated[mode] = modelId | ||
| } | ||
|
|
||
| await updateGlobalState("modeModelOverrides", updated) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might not work with agent manager, but we can figure this out later. Each agent-runtime process maintains it's own state file in a tmp directory to stay ephemeral. If a mutation happens here this might be therefore fine, as we don't change it in the actively running session. So if users later have to restart the agent manager this should be fine for now.
| payload: { mode: "code", modelId: null }, | ||
| }) | ||
| }) | ||
| // kilocode_change end: per-mode model override UI behavior |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need a marker for each individual test?
| } as any | ||
| } | ||
|
|
||
| it("does not apply the per-mode override immediately when updating the current mode (only on mode switch)", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it not apply it immediately?
Context
This PR adds the ability to set a Kilo Code gateway model override per mode (e.g. different models for
code,architect, etc.).The goal is to make mode-switching more powerful for users who want different performance/cost/behavior characteristics depending on what they’re doing, while keeping the default model behavior unchanged unless an override is explicitly set.
Implementation
modeModelOverrides) that stores a mapping ofmodeSlug -> modelId.setModeModelOverride) to:modeModelOverridesin global state.Screenshots
https://www.loom.com/share/c9e2a007b3aa491697d336fb814371c7