From cb1fdb3b1b824c6f91cb05dc568bd37f6bf494f5 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Mon, 1 Jun 2026 15:56:48 +0200 Subject: [PATCH 1/2] fix(cli): allow clearing agent variant overrides --- .changeset/calm-agent-variant-clear.md | 5 ++ packages/opencode/src/config/agent.ts | 3 +- .../test/kilocode/config/config.test.ts | 81 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 .changeset/calm-agent-variant-clear.md diff --git a/.changeset/calm-agent-variant-clear.md b/.changeset/calm-agent-variant-clear.md new file mode 100644 index 00000000000..9d29ee4c074 --- /dev/null +++ b/.changeset/calm-agent-variant-clear.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Allow clearing agent model and variant overrides from settings. diff --git a/packages/opencode/src/config/agent.ts b/packages/opencode/src/config/agent.ts index a725ee32f32..c352bd048fa 100644 --- a/packages/opencode/src/config/agent.ts +++ b/packages/opencode/src/config/agent.ts @@ -30,7 +30,8 @@ const Color = Schema.Union([ const AgentSchema = Schema.StructWithRest( Schema.Struct({ model: Schema.optional(Schema.NullOr(ConfigModelID)), // kilocode_change - nullable for delete sentinel - variant: Schema.optional(Schema.String).annotate({ + // kilocode_change - nullable for delete sentinel + variant: Schema.optional(Schema.NullOr(Schema.String)).annotate({ description: "Default model variant for this agent (applies only when using the agent's configured model).", }), temperature: Schema.optional(Schema.NullOr(Schema.Finite)), // kilocode_change - nullable for delete sentinel diff --git a/packages/opencode/test/kilocode/config/config.test.ts b/packages/opencode/test/kilocode/config/config.test.ts index 32327bbdc8b..bcf3651f6aa 100644 --- a/packages/opencode/test/kilocode/config/config.test.ts +++ b/packages/opencode/test/kilocode/config/config.test.ts @@ -47,6 +47,8 @@ const layer = Config.layer.pipe( const load = () => Effect.runPromise(Config.Service.use((svc) => svc.get()).pipe(Effect.scoped, Effect.provide(layer))) const clear = () => Effect.runPromise(Config.Service.use((svc) => svc.invalidate()).pipe(Effect.scoped, Effect.provide(layer))) +const saveGlobal = (config: Config.Info) => + Effect.runPromise(Config.Service.use((svc) => svc.updateGlobal(config)).pipe(Effect.scoped, Effect.provide(layer))) async function writeConfig(dir: string, config: object, name = "kilo.json") { await Filesystem.write(path.join(dir, name), JSON.stringify(config)) @@ -202,3 +204,82 @@ describe("kilocode indexing config", () => { expect(input.modelDimension).toBeUndefined() }) }) + +describe("agent config", () => { + test("accepts delete sentinels for agent model and variant overrides", () => { + const patch = Config.Info.zod.parse({ agent: { explore: { model: null, variant: null } } }) + const merged = KilocodeConfig.mergeConfig( + { + agent: { + explore: { + model: "kilo/anthropic/claude-sonnet-4-6", + variant: "high", + }, + }, + }, + patch, + ) + + expect(patch.agent?.explore?.model).toBeNull() + expect(patch.agent?.explore?.variant).toBeNull() + expect(merged.agent).toBeUndefined() + }) + + test("removes an agent variant override without removing its model", () => { + const patch = Config.Info.zod.parse({ agent: { explore: { variant: null } } }) + const merged = KilocodeConfig.mergeConfig( + { + agent: { + explore: { + model: "kilo/anthropic/claude-sonnet-4-6", + variant: "high", + }, + }, + }, + patch, + ) + + expect(patch.agent?.explore?.variant).toBeNull() + expect(merged.agent?.explore).toEqual({ model: "kilo/anthropic/claude-sonnet-4-6" }) + }) + + test("removes agent model and variant overrides from global JSONC config", async () => { + await using globalTmp = await tmpdir() + const file = path.join(globalTmp.path, "kilo.jsonc") + const prev = Global.Path.config + ;(Global.Path as { config: string }).config = globalTmp.path + await clear() + await disposeAllInstances() + + try { + await Filesystem.write( + file, + [ + "{", + " // Preserve this comment while clearing overrides.", + ' "agent": {', + ' "explore": {', + ' "model": "kilo/anthropic/claude-sonnet-4-6",', + ' "variant": "high",', + ' "description": "Keep me"', + " }", + " }", + "}", + ].join("\n"), + ) + const patch = Config.Info.zod.parse({ agent: { explore: { model: null, variant: null } } }) + + await saveGlobal(patch) + + const written = await Bun.file(file).text() + expect(written).toContain("// Preserve this comment while clearing overrides.") + expect(written).not.toContain('"model"') + expect(written).not.toContain('"variant"') + expect(written).toContain('"description": "Keep me"') + } finally { + ;(Global.Path as { config: string }).config = prev + await clear() + await disposeAllInstances() + } + }) +}) From 2a264819f4f933dbe3e0b434896854322dcbb39c Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Mon, 1 Jun 2026 15:57:20 +0200 Subject: [PATCH 2/2] fix(cli): annotate nullable agent variant schema --- packages/opencode/src/config/agent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/config/agent.ts b/packages/opencode/src/config/agent.ts index c352bd048fa..a7ec3922c08 100644 --- a/packages/opencode/src/config/agent.ts +++ b/packages/opencode/src/config/agent.ts @@ -30,10 +30,11 @@ const Color = Schema.Union([ const AgentSchema = Schema.StructWithRest( Schema.Struct({ model: Schema.optional(Schema.NullOr(ConfigModelID)), // kilocode_change - nullable for delete sentinel - // kilocode_change - nullable for delete sentinel + // kilocode_change start - nullable for delete sentinel variant: Schema.optional(Schema.NullOr(Schema.String)).annotate({ description: "Default model variant for this agent (applies only when using the agent's configured model).", }), + // kilocode_change end temperature: Schema.optional(Schema.NullOr(Schema.Finite)), // kilocode_change - nullable for delete sentinel top_p: Schema.optional(Schema.NullOr(Schema.Finite)), // kilocode_change - nullable for delete sentinel prompt: Schema.optional(Schema.NullOr(Schema.String)), // kilocode_change - nullable for delete sentinel