diff --git a/packages/core/src/sync/providers/anthropic.ts b/packages/core/src/sync/providers/anthropic.ts index a09b0810a..bbec8939b 100644 --- a/packages/core/src/sync/providers/anthropic.ts +++ b/packages/core/src/sync/providers/anthropic.ts @@ -99,7 +99,8 @@ export const anthropic = { translateModel(model, context) { const existing = context.existing(model.id); if (existing !== undefined) { - return { id: model.id, model: buildAnthropicModel(model, existing) }; + const baseModel = context.authored(model.id)?.base_model; + return { id: model.id, model: buildAnthropicModel(model, existing, baseModel) }; } const baseModel = `anthropic/${model.id}`; diff --git a/packages/core/test/sync.test.ts b/packages/core/test/sync.test.ts index 7d7c528a7..0bceaf060 100644 --- a/packages/core/test/sync.test.ts +++ b/packages/core/test/sync.test.ts @@ -5,6 +5,7 @@ import path from "node:path"; import { formatToml, preserveReasoningOptions, syncProvider, type SyncProvider } from "../src/sync/index.js"; import { + anthropic, buildAnthropicModel, parseAnthropicPricing, type AnthropicModel, @@ -131,6 +132,42 @@ test("labels Anthropic aliases as latest", () => { expect(model.name).toBe("Claude Sonnet 5 (latest)"); }); +test("Anthropic sync preserves base model inheritance", () => { + const resolved = { + base_model: "anthropic/claude-opus-4-5", + name: "Claude Opus 4.5 (latest)", + description: "Flagship Claude model", + release_date: "2025-11-24", + last_updated: "2025-11-24", + attachment: true, + reasoning: true, + tool_call: true, + knowledge: "2025-05", + open_weights: false, + cost: { input: 5, output: 25 }, + limit: { context: 200_000, output: 64_000 }, + modalities: { input: ["text" as const, "image" as const], output: ["text" as const] }, + }; + const translated = anthropic.translateModel(anthropicModel({ + id: "claude-opus-4-5", + canonical_id: "claude-opus-4-5-20251101", + display_name: "Claude Opus 4.5", + created_at: "2025-11-24T00:00:00Z", + max_input_tokens: 200_000, + max_tokens: 64_000, + }), { + existing: () => resolved, + authored: () => ({ base_model: "anthropic/claude-opus-4-5" }), + }); + + expect(translated?.model).toMatchObject({ + base_model: "anthropic/claude-opus-4-5", + name: "Claude Opus 4.5 (latest)", + }); + expect(translated?.model).not.toHaveProperty("knowledge"); + expect(translated?.model).not.toHaveProperty("release_date"); +}); + test("filters customer-owned OpenAI models from availability tracking", () => { expect(parseOpenAIModels({ object: "list",