Merge pull request #10094 from IamCoder18/fix/agent-manager-model-sync

fix: agent-manager model sync on config change
This commit is contained in:
Marius
2026-06-09 09:48:18 +02:00
committed by GitHub
3 changed files with 79 additions and 4 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Fix agent-manager model sync on config change
@@ -85,7 +85,7 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
const cached = vscode.getState<Record<string, unknown>>()
const [prompt, setPrompt] = createSignal((cached?.advancedDialogPrompt as string) ?? "")
const [versions, setVersions] = createSignal<VersionCount>(1)
const [model, setModel] = createSignal<{ providerID: string; modelID: string } | null>(session.selected())
const [model, setModel] = createSignal<{ providerID: string; modelID: string } | null>(session.configModel())
const [compareMode, setCompareMode] = createSignal(false)
const [modelAllocations, setModelAllocations] = createSignal<ModelAllocations>(new Map())
const [agent, setAgent] = createSignal(session.selectedAgent())
@@ -121,7 +121,7 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
// True when the user has changed the model from the session/config default
const overridden = createMemo(() => {
const sel = model()
const cfg = session.selected()
const cfg = session.configModel()
if (!sel || !cfg) return false
return sel.providerID !== cfg.providerID || sel.modelID !== cfg.modelID
})
@@ -441,7 +441,7 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
<Button
variant="ghost"
size="small"
onClick={() => setModel(session.selected())}
onClick={() => setModel(session.configModel())}
aria-label={t("prompt.action.resetModel")}
>
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
@@ -4,7 +4,17 @@
* Also owns global (extension-lifetime) model selection (provider context is catalog-only).
*/
import { createContext, useContext, createSignal, createMemo, createEffect, onMount, onCleanup, batch } from "solid-js"
import {
createContext,
useContext,
createSignal,
createMemo,
createEffect,
onMount,
onCleanup,
batch,
untrack,
} from "solid-js"
import type { ParentComponent, Accessor } from "solid-js"
import { createStore, produce, reconcile } from "solid-js/store"
import { useVSCode } from "./vscode"
@@ -171,6 +181,7 @@ interface SessionContextValue {
// Model selection (global, extension-lifetime)
selected: (sessionID?: string) => ModelSelection | null
configModel: (sessionID?: string) => ModelSelection | null
selectModel: (providerID: string, modelID: string, sessionID?: string) => void
hasModelOverride: (sessionID?: string) => boolean
clearModelOverride: (sessionID?: string) => void
@@ -786,6 +797,64 @@ export const SessionProvider: ParentComponent = (props) => {
vscode.postMessage({ type: "requestFavorites" })
onCleanup(unsubFavorites)
// Clear model overrides that match the previous config model (not intentional user overrides).
// When config.model changes, old overrides that were just default values should be cleared
// so sessions fall through to resolveModel() and pick up the new config model.
const [lastConfigModel, setLastConfigModel] = createSignal<ModelSelection | null>(getGlobalModel())
createEffect(() => {
const newConfigModel = getGlobalModel()
// Use untrack to read previous value without making this effect re-trigger on its own updates
const oldConfigModel = untrack(() => lastConfigModel())
if (oldConfigModel) {
// Also clear when newConfigModel is null (user removed model from config)
if (newConfigModel) {
const modelChanged =
oldConfigModel.providerID !== newConfigModel.providerID || oldConfigModel.modelID !== newConfigModel.modelID
if (modelChanged) {
// Clear overrides that match the OLD config model - these were likely defaults,
// not intentional user overrides. Overrides that differ from both old and new
// config are preserved (intentional user selections).
setStore(
"sessionOverrides",
produce((overrides) => {
for (const sid of Object.keys(overrides)) {
const override = overrides[sid]
if (
override &&
override.providerID === oldConfigModel.providerID &&
override.modelID === oldConfigModel.modelID
) {
delete overrides[sid]
}
}
}),
)
}
} else {
// newConfigModel is null - clear all overrides that matched the old config model
// since the config no longer specifies a model. This ensures sessions fall through
// to provider defaults rather than using a stale removed model.
setStore(
"sessionOverrides",
produce((overrides) => {
for (const sid of Object.keys(overrides)) {
const override = overrides[sid]
if (
override &&
override.providerID === oldConfigModel.providerID &&
override.modelID === oldConfigModel.modelID
) {
delete overrides[sid]
}
}
}),
)
}
}
// Update the tracked config model
setLastConfigModel(newConfigModel)
})
function handleError(message: Extract<ExtensionMessage, { type: "error" }>) {
if (!message.sessionID || message.sessionID === currentSessionID()) setLoading(false)
if (message.sessionID) patchPage(message.sessionID, { loadingInitial: false, loadingOlder: false })
@@ -2479,6 +2548,7 @@ export const SessionProvider: ParentComponent = (props) => {
scopedQuestions,
scopedSuggestions,
selected,
configModel,
selectModel,
hasModelOverride,
clearModelOverride,