From a8fb526e9ca26db0cfa2a4bd9d69f5d48f30a8b7 Mon Sep 17 00:00:00 2001 From: Will Gordon Date: Thu, 30 Jul 2026 14:46:45 -0400 Subject: [PATCH] refactor(sse): extract shared Claude effort-model predicate --- open-sse/utils/claudeEffortVariants.ts | 16 ++++++++++++---- tests/unit/claude-effort-variants.test.ts | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/open-sse/utils/claudeEffortVariants.ts b/open-sse/utils/claudeEffortVariants.ts index a5c549fe55..78dcad34c0 100644 --- a/open-sse/utils/claudeEffortVariants.ts +++ b/open-sse/utils/claudeEffortVariants.ts @@ -64,6 +64,17 @@ export function formatClaudeEffortLabel(level: string): string { return level.charAt(0).toUpperCase() + level.slice(1); } +/** + * Whether `bareModelId` (no provider prefix, no effort suffix) is a real, + * effort-capable Claude-family model — the single source of truth used both to + * decide whether the catalog should advertise an effort variant AND whether + * dispatch-time stripping should unwind one back to this model. + */ +export function isKnownClaudeEffortBaseModel(bareModelId: string): boolean { + const spec = getModelSpec(bareModelId); + return spec?.supportsThinking === true && CLAUDE_NAME_RE.test(bareModelId); +} + /** * Whether the catalog should advertise reasoning-effort variants for this entry. * @@ -84,10 +95,7 @@ export function shouldExposeClaudeEffortVariants( if (CLAUDE_EFFORT_SUFFIX_RE.test(id)) return false; const name = bareModelName(id); - const spec = getModelSpec(name); - if (!spec) return false; - - return spec.supportsThinking === true && CLAUDE_NAME_RE.test(name); + return isKnownClaudeEffortBaseModel(name); } /** diff --git a/tests/unit/claude-effort-variants.test.ts b/tests/unit/claude-effort-variants.test.ts index d07da37045..27330e85de 100644 --- a/tests/unit/claude-effort-variants.test.ts +++ b/tests/unit/claude-effort-variants.test.ts @@ -6,6 +6,7 @@ import { CLAUDE_XHIGH_EFFORT_LEVEL, formatClaudeEffortLabel, shouldExposeClaudeEffortVariants, + isKnownClaudeEffortBaseModel, claudeEffortLevelsFor, appendClaudeEffortVariants, } from "../../open-sse/utils/claudeEffortVariants.ts"; @@ -63,6 +64,26 @@ test("non-string / empty / non-object ids never match", () => { assert.equal(shouldExposeClaudeEffortVariants({ id: 42 as never }), false); }); +// ── isKnownClaudeEffortBaseModel ───────────────────────────────────────────── + +test("isKnownClaudeEffortBaseModel returns true for a real effort-capable Claude model", () => { + assert.equal(isKnownClaudeEffortBaseModel("claude-fable-5"), true); +}); + +test("isKnownClaudeEffortBaseModel returns false for a non-Claude model", () => { + assert.equal(isKnownClaudeEffortBaseModel("gpt-4o"), false); +}); + +test("isKnownClaudeEffortBaseModel returns false for an unregistered model id", () => { + assert.equal(isKnownClaudeEffortBaseModel("totally-unregistered-model-xyz"), false); +}); + +test("isKnownClaudeEffortBaseModel returns false for a non-Claude model that also supports thinking (SC-1)", () => { + // gpt-5.5 has supportsThinking:true in MODEL_SPECS (like 36+ other non-Claude models) — + // the /claude/i name check is the only thing excluding it, not the thinking flag alone. + assert.equal(isKnownClaudeEffortBaseModel("gpt-5.5"), false); +}); + // ── claudeEffortLevelsFor ──────────────────────────────────────────────────── test("xHigh is added only for models that support it", () => {