From ca1d67d71a7f5113fbf84acd6343cd7d5768fb30 Mon Sep 17 00:00:00 2001 From: Yannic Charlon <52761674+JustYannicc@users.noreply.github.com> Date: Sat, 17 Oct 2026 10:08:02 +0200 Subject: [PATCH 1/4] fix(server): preserve explicit effort for unknown Claude models --- apps/server/src/claudeModelOptions.test.ts | 11 +++++++++++ apps/server/src/provider/ClaudeModelCatalog.test.ts | 3 ++- apps/server/src/provider/ClaudeModelCatalog.ts | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/server/src/claudeModelOptions.test.ts b/apps/server/src/claudeModelOptions.test.ts index e03ac150652a..3efe219c6a92 100644 --- a/apps/server/src/claudeModelOptions.test.ts +++ b/apps/server/src/claudeModelOptions.test.ts @@ -49,6 +49,17 @@ describe("compileClaudeModelSelection", () => { ).toMatchObject({ effort: "high", promptEffort: "ultrathink" }); }); + it("keeps explicit effort for models missing from the local catalog", () => { + expect( + compileClaudeModelSelection( + selection("claude-pool-model-not-in-catalog", [{ id: "effort", value: "max" }]), + ).effort, + ).toBe("max"); + expect( + compileClaudeModelSelection(selection("claude-pool-model-not-in-catalog", [])).effort, + ).toBeUndefined(); + }); + it("compiles the thinking toggle for models that expose it", () => { expect( compileClaudeModelSelection(selection("claude-haiku-4-5", [{ id: "thinking", value: false }])) diff --git a/apps/server/src/provider/ClaudeModelCatalog.test.ts b/apps/server/src/provider/ClaudeModelCatalog.test.ts index f6389fab0316..cd45ed3ccdb5 100644 --- a/apps/server/src/provider/ClaudeModelCatalog.test.ts +++ b/apps/server/src/provider/ClaudeModelCatalog.test.ts @@ -215,7 +215,8 @@ describe("Claude model catalog", () => { ]); assert.strictEqual(resolveClaudeModelSlug(catalog, "synthetic"), "synthetic"); - assert.strictEqual(resolveClaudeCatalogEffort(catalog, "synthetic", "extreme"), undefined); + assert.strictEqual(resolveClaudeCatalogEffort(catalog, "synthetic", "extreme"), "extreme"); + assert.strictEqual(normalizeClaudeCatalogEffort(catalog, "extreme", "synthetic"), "extreme"); assert.strictEqual( resolveClaudeCatalogEffort(catalog, "claude-custom-tuned", "brutal"), diff --git a/apps/server/src/provider/ClaudeModelCatalog.ts b/apps/server/src/provider/ClaudeModelCatalog.ts index 5df8279c4d8d..fb4177844bf7 100644 --- a/apps/server/src/provider/ClaudeModelCatalog.ts +++ b/apps/server/src/provider/ClaudeModelCatalog.ts @@ -209,6 +209,8 @@ export function resolveClaudeCatalogEffort( model: string | null | undefined, raw: string | null | undefined, ): string | undefined { + if (!resolveClaudeCatalogModel(catalog, model)) return raw?.trim() || undefined; + const caps = getClaudeCatalogModelCapabilities(catalog, model); const descriptors = getProviderOptionDescriptors({ caps, From 4cd3e69150daa108fc3a4ed7c08b619c0d247d26 Mon Sep 17 00:00:00 2001 From: Yannic Charlon <52761674+JustYannicc@users.noreply.github.com> Date: Sat, 17 Oct 2026 10:23:39 +0200 Subject: [PATCH 2/4] test(server): expect explicit effort for unknown Claude alias --- apps/server/src/textGeneration/ClaudeTextGeneration.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts b/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts index e907580eeffc..f2b94aeb933e 100644 --- a/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts +++ b/apps/server/src/textGeneration/ClaudeTextGeneration.test.ts @@ -237,7 +237,7 @@ it.layer(layerClaudeTextGenerationTest)("ClaudeTextGeneration", (it) => { body: "", }, }), - argsMustContain: `--model ${SYNTHETIC_CLAUDE_COLLIDING_ALIAS} --settings`, + argsMustContain: `--model ${SYNTHETIC_CLAUDE_COLLIDING_ALIAS} --effort max --settings`, claudeConfig: { customModels: [SYNTHETIC_CLAUDE_COLLIDING_ALIAS] }, }, (textGeneration) => From 9ab8f07e7fbb64236085f951f60c7b97673f48e8 Mon Sep 17 00:00:00 2001 From: Yannic Charlon <52761674+JustYannicc@users.noreply.github.com> Date: Sat, 17 Oct 2026 11:11:21 +0200 Subject: [PATCH 3/4] fix(server): validate effort for uncatalogued Claude models --- apps/server/src/claudeModelOptions.test.ts | 8 ++++++++ .../src/provider/ClaudeModelCatalog.test.ts | 15 +++++++++++++-- apps/server/src/provider/ClaudeModelCatalog.ts | 5 ++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/server/src/claudeModelOptions.test.ts b/apps/server/src/claudeModelOptions.test.ts index 3efe219c6a92..1c4a8a6c99db 100644 --- a/apps/server/src/claudeModelOptions.test.ts +++ b/apps/server/src/claudeModelOptions.test.ts @@ -60,6 +60,14 @@ describe("compileClaudeModelSelection", () => { ).toBeUndefined(); }); + it("omits unsupported effort for models missing from the local catalog", () => { + expect( + compileClaudeModelSelection( + selection("claude-pool-model-not-in-catalog", [{ id: "effort", value: "brutal" }]), + ).effort, + ).toBeUndefined(); + }); + it("compiles the thinking toggle for models that expose it", () => { expect( compileClaudeModelSelection(selection("claude-haiku-4-5", [{ id: "thinking", value: false }])) diff --git a/apps/server/src/provider/ClaudeModelCatalog.test.ts b/apps/server/src/provider/ClaudeModelCatalog.test.ts index cd45ed3ccdb5..da61038215d8 100644 --- a/apps/server/src/provider/ClaudeModelCatalog.test.ts +++ b/apps/server/src/provider/ClaudeModelCatalog.test.ts @@ -192,6 +192,16 @@ describe("Claude model catalog", () => { assert.isFalse(hasValidClaudeManifestAdapters(malformed)); }); + it("preserves only SDK effort levels for uncatalogued models", () => { + const catalog = catalogFromManifest(manifest()); + for (const effort of ["low", "medium", "high", "xhigh", "max"]) { + assert.strictEqual(resolveClaudeCatalogEffort(catalog, "custom", ` ${effort} `), effort); + } + for (const effort of [undefined, null, "", " ", "brutal", "extreme", "HIGH", "ultrathink"]) { + assert.isUndefined(resolveClaudeCatalogEffort(catalog, "custom", effort)); + } + }); + it("appends custom models with their own descriptors and keeps bare slugs opaque", () => { const catalog = scopeClaudeModelCatalog(catalogFromManifest(manifest()), [ "synthetic", @@ -215,8 +225,9 @@ describe("Claude model catalog", () => { ]); assert.strictEqual(resolveClaudeModelSlug(catalog, "synthetic"), "synthetic"); - assert.strictEqual(resolveClaudeCatalogEffort(catalog, "synthetic", "extreme"), "extreme"); - assert.strictEqual(normalizeClaudeCatalogEffort(catalog, "extreme", "synthetic"), "extreme"); + assert.isUndefined(resolveClaudeCatalogEffort(catalog, "synthetic", "extreme")); + assert.strictEqual(resolveClaudeCatalogEffort(catalog, "synthetic", "max"), "max"); + assert.strictEqual(normalizeClaudeCatalogEffort(catalog, "max", "synthetic"), "max"); assert.strictEqual( resolveClaudeCatalogEffort(catalog, "claude-custom-tuned", "brutal"), diff --git a/apps/server/src/provider/ClaudeModelCatalog.ts b/apps/server/src/provider/ClaudeModelCatalog.ts index fb4177844bf7..feb829be388f 100644 --- a/apps/server/src/provider/ClaudeModelCatalog.ts +++ b/apps/server/src/provider/ClaudeModelCatalog.ts @@ -209,7 +209,10 @@ export function resolveClaudeCatalogEffort( model: string | null | undefined, raw: string | null | undefined, ): string | undefined { - if (!resolveClaudeCatalogModel(catalog, model)) return raw?.trim() || undefined; + if (!resolveClaudeCatalogModel(catalog, model)) { + const effort = raw?.trim(); + return effort && ["low", "medium", "high", "xhigh", "max"].includes(effort) ? effort : undefined; + } const caps = getClaudeCatalogModelCapabilities(catalog, model); const descriptors = getProviderOptionDescriptors({ From 4b7c281c506c3d40f0c0caf4693686a47a9bfd2c Mon Sep 17 00:00:00 2001 From: Yannic Charlon <52761674+JustYannicc@users.noreply.github.com> Date: Sat, 17 Oct 2026 11:15:35 +0200 Subject: [PATCH 4/4] style(server): format Claude effort validation --- apps/server/src/provider/ClaudeModelCatalog.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/server/src/provider/ClaudeModelCatalog.ts b/apps/server/src/provider/ClaudeModelCatalog.ts index feb829be388f..db409077756a 100644 --- a/apps/server/src/provider/ClaudeModelCatalog.ts +++ b/apps/server/src/provider/ClaudeModelCatalog.ts @@ -211,7 +211,9 @@ export function resolveClaudeCatalogEffort( ): string | undefined { if (!resolveClaudeCatalogModel(catalog, model)) { const effort = raw?.trim(); - return effort && ["low", "medium", "high", "xhigh", "max"].includes(effort) ? effort : undefined; + return effort && ["low", "medium", "high", "xhigh", "max"].includes(effort) + ? effort + : undefined; } const caps = getClaudeCatalogModelCapabilities(catalog, model);