From dacd5197c8cc6c34f8417f9380768c1891082d27 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 2 Sep 2026 17:20:32 +0200 Subject: [PATCH 1/2] fix(ai): bump impersonated Claude Code version to 2.1.257 for Fable 5.x The Anthropic API now gates Fable 5.x models on Claude Code >= 2.1.251 and rejects the previously pinned 2.1.75 identity for OAuth requests. Fixes #1962 --- .../res-1257-fable-claude-code-version.md | 1 + packages/ai/src/providers/anthropic.ts | 3 +- packages/ai/test/anthropic-oauth.test.ts | 28 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 packages/ai/.changes/res-1257-fable-claude-code-version.md diff --git a/packages/ai/.changes/res-1257-fable-claude-code-version.md b/packages/ai/.changes/res-1257-fable-claude-code-version.md new file mode 100644 index 0000000000..452c5f5cb5 --- /dev/null +++ b/packages/ai/.changes/res-1257-fable-claude-code-version.md @@ -0,0 +1 @@ +- Fixed Claude Fable 5.x failing over Anthropic OAuth with "Claude Code 2.1.75 does not support this model" by bumping the impersonated Claude Code version to 2.1.257 ([#1962](https://github.com/PrimeIntellect-ai/prime-agent/issues/1962)) diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index 55596aa0c3..59000b96d3 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -77,7 +77,8 @@ function getCacheControl( } // Stealth mode: Mimic Claude Code's tool naming exactly -const claudeCodeVersion = "2.1.75"; +// Fable 5.x requires Claude Code >= 2.1.251; the API rejects older versions. +const claudeCodeVersion = "2.1.257"; // Claude Code 2.x tool names (canonical casing) // Source: https://cchistory.mariozechner.at/data/prompts-2.1.11.md diff --git a/packages/ai/test/anthropic-oauth.test.ts b/packages/ai/test/anthropic-oauth.test.ts index f8e066c669..b7f2d2b891 100644 --- a/packages/ai/test/anthropic-oauth.test.ts +++ b/packages/ai/test/anthropic-oauth.test.ts @@ -1,4 +1,6 @@ import { afterEach, describe, expect, it, vi } from "vitest"; +import { getModel } from "../src/models.js"; +import { streamAnthropic } from "../src/providers/anthropic.js"; import { loginAnthropic, refreshAnthropicToken } from "../src/utils/oauth/anthropic.js"; function jsonResponse(body: unknown, status: number = 200): Response { @@ -97,3 +99,29 @@ describe.sequential("Anthropic OAuth", () => { expect(fetchMock).toHaveBeenCalledOnce(); }); }); + +describe.sequential("Anthropic OAuth request identity", () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it("sends the Claude Code version in the user-agent for OAuth tokens", async () => { + let userAgent: string | null = null; + const fetchMock = vi.fn(async (input: unknown, init?: RequestInit): Promise => { + const headers = new Headers(input instanceof Request ? input.headers : init?.headers); + userAgent = headers.get("user-agent"); + return jsonResponse({ type: "error", error: { type: "invalid_request_error", message: "nope" } }, 400); + }); + vi.stubGlobal("fetch", fetchMock); + + const stream = streamAnthropic( + getModel("anthropic", "claude-fable-5"), + { messages: [{ role: "user", content: "hi", timestamp: Date.now() }] }, + { apiKey: "sk-ant-oat01-test" }, + ); + await stream.result(); + + // Fable 5.x requires Claude Code >= 2.1.251; the API rejects older versions. + expect(userAgent).toBe("claude-cli/2.1.257"); + }); +}); From 6dcc4575cf5f6208f6c950b947710f53f5c8b3c7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 2 Sep 2026 17:30:31 +0200 Subject: [PATCH 2/2] chore(ai): drop the identity-header test and rationale comment per review --- packages/ai/src/providers/anthropic.ts | 1 - packages/ai/test/anthropic-oauth.test.ts | 28 ------------------------ 2 files changed, 29 deletions(-) diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index 59000b96d3..a3fcb41521 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -77,7 +77,6 @@ function getCacheControl( } // Stealth mode: Mimic Claude Code's tool naming exactly -// Fable 5.x requires Claude Code >= 2.1.251; the API rejects older versions. const claudeCodeVersion = "2.1.257"; // Claude Code 2.x tool names (canonical casing) diff --git a/packages/ai/test/anthropic-oauth.test.ts b/packages/ai/test/anthropic-oauth.test.ts index b7f2d2b891..f8e066c669 100644 --- a/packages/ai/test/anthropic-oauth.test.ts +++ b/packages/ai/test/anthropic-oauth.test.ts @@ -1,6 +1,4 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { getModel } from "../src/models.js"; -import { streamAnthropic } from "../src/providers/anthropic.js"; import { loginAnthropic, refreshAnthropicToken } from "../src/utils/oauth/anthropic.js"; function jsonResponse(body: unknown, status: number = 200): Response { @@ -99,29 +97,3 @@ describe.sequential("Anthropic OAuth", () => { expect(fetchMock).toHaveBeenCalledOnce(); }); }); - -describe.sequential("Anthropic OAuth request identity", () => { - afterEach(() => { - vi.unstubAllGlobals(); - }); - - it("sends the Claude Code version in the user-agent for OAuth tokens", async () => { - let userAgent: string | null = null; - const fetchMock = vi.fn(async (input: unknown, init?: RequestInit): Promise => { - const headers = new Headers(input instanceof Request ? input.headers : init?.headers); - userAgent = headers.get("user-agent"); - return jsonResponse({ type: "error", error: { type: "invalid_request_error", message: "nope" } }, 400); - }); - vi.stubGlobal("fetch", fetchMock); - - const stream = streamAnthropic( - getModel("anthropic", "claude-fable-5"), - { messages: [{ role: "user", content: "hi", timestamp: Date.now() }] }, - { apiKey: "sk-ant-oat01-test" }, - ); - await stream.result(); - - // Fable 5.x requires Claude Code >= 2.1.251; the API rejects older versions. - expect(userAgent).toBe("claude-cli/2.1.257"); - }); -});