From 9821729c756643eeb79a2d514d3698d73677ad70 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sat, 25 Jul 2026 23:23:33 +0200 Subject: [PATCH] fix(claude): preserve parsed context variants --- .../agent/providers/claude/model-manifest.ts | 14 ++++++++------ .../server/agent/providers/claude/models.test.ts | 12 ++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/server/src/server/agent/providers/claude/model-manifest.ts b/packages/server/src/server/agent/providers/claude/model-manifest.ts index 9c81a1d508..ec9efdb1f6 100644 --- a/packages/server/src/server/agent/providers/claude/model-manifest.ts +++ b/packages/server/src/server/agent/providers/claude/model-manifest.ts @@ -245,7 +245,9 @@ function compareVersions(left: string, right: string): number { } export function parseClaudeCodeVersion(value: string): [number, number, number] | null { - const match = value.match(/\b(\d+)\.(\d+)\.(\d+)\b/); + const match = + value.match(/\b(\d+)\.(\d+)\.(\d+)\s+\(Claude Code\)/i) ?? + value.match(/\b(\d+)\.(\d+)\.(\d+)\b/); return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null; } @@ -305,7 +307,7 @@ export function normalizeClaudeManifestModelId(value: string | null | undefined) } const singleSegmentMatch = trimmed.match( - /^(?:claude[-_ ])?(fable|opus|sonnet|haiku)[-_ ]+(\d+)(\[1m\])?(?:[-_ ]+\d{8})?$/i, + /^(?:claude[-_ ])?(fable|opus|sonnet|haiku)[-_ ]+(\d+)(?:\[1m\])?(?:[-_ ]+\d{8})?(?:\[1m\])?$/i, ); if (singleSegmentMatch) { return normalizeSingleSegmentClaudeModelId( @@ -316,7 +318,7 @@ export function normalizeClaudeManifestModelId(value: string | null | undefined) } const runtimeMatch = trimmed.match( - /^(?:claude[-_ ])?(opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(\[1m\])?(?:[-_ ]+\d{8})?$/i, + /^(?:claude[-_ ])?(opus|sonnet|haiku)[-_ ]+(\d+)[-.](\d+)(?:\[1m\])?(?:[-_ ]+\d{8})?(?:\[1m\])?$/i, ); if (!runtimeMatch) { return null; @@ -326,7 +328,7 @@ export function normalizeClaudeManifestModelId(value: string | null | undefined) runtimeMatch[1], runtimeMatch[2], runtimeMatch[3], - Boolean(runtimeMatch[4]), + trimmed.toLowerCase().includes("[1m]"), ); } @@ -353,7 +355,7 @@ export function normalizeClaudeRuntimeModelId(value: string | null | undefined): const normalizedModelId = normalizeSingleSegmentClaudeModelId( singleSegmentMatch[1], singleSegmentMatch[2], - Boolean(singleSegmentMatch[3]), + trimmed.toLowerCase().includes("[1m]"), ); if (normalizedModelId) { return normalizedModelId; @@ -371,7 +373,7 @@ export function normalizeClaudeRuntimeModelId(value: string | null | undefined): runtimeMatch[1], runtimeMatch[2], runtimeMatch[3], - Boolean(runtimeMatch[4]), + trimmed.toLowerCase().includes("[1m]"), ); } diff --git a/packages/server/src/server/agent/providers/claude/models.test.ts b/packages/server/src/server/agent/providers/claude/models.test.ts index f960c8e2df..c3e62b1dc3 100644 --- a/packages/server/src/server/agent/providers/claude/models.test.ts +++ b/packages/server/src/server/agent/providers/claude/models.test.ts @@ -10,6 +10,7 @@ import { CLAUDE_ULTRACODE_THINKING_OPTION_ID, claudeManifestModelSupportsFastMode, normalizeClaudeManifestModelId, + parseClaudeCodeVersion, resolveClaudeDisabledThinkingForModel, } from "./model-manifest.js"; import { findClaudeModel, getClaudeModels, normalizeClaudeRuntimeModelId } from "./models.js"; @@ -365,6 +366,11 @@ describe("normalizeClaudeRuntimeModelId", () => { expect(normalizeClaudeRuntimeModelId("claude-opus-4-6-20260101")).toBe("claude-opus-4-6"); expect(normalizeClaudeRuntimeModelId("claude-sonnet-4-6-20260101")).toBe("claude-sonnet-4-6"); expect(normalizeClaudeRuntimeModelId("claude-haiku-4-5-20251001")).toBe("claude-haiku-4-5"); + expect(normalizeClaudeRuntimeModelId("claude-opus-5-20260724[1m]")).toBe("claude-opus-5[1m]"); + expect(normalizeClaudeRuntimeModelId("claude-fable-5-20260301[1m]")).toBe("claude-fable-5[1m]"); + expect(normalizeClaudeRuntimeModelId("claude-sonnet-5-20260101[1m]")).toBe( + "claude-sonnet-5[1m]", + ); }); it("preserves [1m] suffix from runtime model strings", () => { @@ -399,6 +405,12 @@ describe("normalizeClaudeRuntimeModelId", () => { }); }); +describe("parseClaudeCodeVersion", () => { + it("prefers the Claude Code version over a wrapper banner", () => { + expect(parseClaudeCodeVersion("wrapper 1.0.0\n2.1.219 (Claude Code)")).toEqual([2, 1, 219]); + }); +}); + describe("findClaudeModel", () => { it("resolves runtime model IDs to catalog entries", () => { expect(findClaudeModel("claude-sonnet-5-20260101")?.id).toBe("claude-sonnet-5");