Skip to content
1 change: 1 addition & 0 deletions changelog.d/features/14546-claude-opus-5-5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **feat(providers):** add Claude Opus 5.5 (`claude-opus-5-5`) to the Anthropic API, Claude OAuth, Bedrock and Vertex catalogs — native 1M context, 128K output, five effort tiers (default `medium`), $4/$20 pricing, Fast Mode, Opus 5 fallback; disabled thinking, manual budgets and forced `tool_choice` are normalized before dispatch since Opus 5.5 rejects them. The `cc/` Opus CLI default stays `claude-opus-5`, because `claude`/`anthropic` connections synced before the launch reject Opus 5.5 until their model list is refreshed (Refs #14612) ([#14546](https://github.com/diegosouzapw/OmniRoute/pull/14546)).
3 changes: 2 additions & 1 deletion open-sse/config/claudeCodeCompatibleIdentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ export const CLAUDE_CODE_COMPATIBLE_USER_AGENT = getClaudeCodeUserAgent("sdk-cli
export { getClaudeCodeUserAgent };
export const CLAUDE_CODE_COMPATIBLE_STAINLESS_PACKAGE_VERSION = CLAUDE_CODE_SDK_PACKAGE_VERSION;
export const CLAUDE_CODE_COMPATIBLE_STAINLESS_RUNTIME_VERSION = CLAUDE_CODE_RUNTIME_VERSION;
const CONTEXT_1M_NATIVE_MODELS = ["claude-fable-5-1", "claude-opus-5"];
const CONTEXT_1M_NATIVE_MODELS = ["claude-fable-5-1", "claude-opus-5-5", "claude-opus-5"];

export function modelHasNativeContext1m(model: string | null | undefined): boolean {
const normalizedModel = String(model || "")
.trim()
.toLowerCase()
.replace(/^.*?(?=claude-)/, "")
.replace(/(\d)\.(\d)/g, "$1-$2")
.replace(/-\d{8}$/, "");

return CONTEXT_1M_NATIVE_MODELS.some(
Expand Down
11 changes: 11 additions & 0 deletions open-sse/config/providers/registry/anthropic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ export const anthropicProvider: RegistryEntry = {
supportsXHighEffort: true,
unsupportedParams: ["temperature", "top_p", "top_k"],
},
{
id: "claude-opus-5-5",
name: "Claude Opus 5.5",
contextLength: 1000000,
maxOutputTokens: 128000,
supportsReasoning: true,
supportedThinkingEfforts: ["low", "medium", "high", "xhigh", "max"],
supportsXHighEffort: true,
supportsVision: true,
unsupportedParams: ["temperature", "top_p", "top_k"],
},
{
id: "claude-opus-5",
name: "Claude Opus 5",
Expand Down
12 changes: 12 additions & 0 deletions open-sse/config/providers/registry/bedrock/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ export const bedrockProvider: RegistryEntry = {
contextLength: 1000000,
maxOutputTokens: 128000,
},
{
id: "anthropic.claude-opus-5-5",
name: "Claude Opus 5.5 (Bedrock)",
toolCalling: true,
supportsReasoning: true,
supportedThinkingEfforts: ["low", "medium", "high", "xhigh", "max"],
supportsXHighEffort: true,
supportsVision: true,
contextLength: 1000000,
maxOutputTokens: 128000,
unsupportedParams: ["temperature", "top_p", "top_k"],
},
{
id: "anthropic.claude-sonnet-4-6",
name: "Claude Sonnet 4.6 (Bedrock)",
Expand Down
12 changes: 12 additions & 0 deletions open-sse/config/providers/registry/claude/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ export const claudeProvider: RegistryEntry = {
supportsXHighEffort: true,
unsupportedParams: ["temperature", "top_p", "top_k"],
},
// Listed after Opus 5 so the cc/ Opus default stays on a model stale live catalogs still accept (#14612).
{
id: "claude-opus-5-5",
name: "Claude Opus 5.5",
contextLength: 1000000,
maxOutputTokens: 128000,
supportsReasoning: true,
supportedThinkingEfforts: ["low", "medium", "high", "xhigh", "max"],
supportsXHighEffort: true,
supportsVision: true,
unsupportedParams: ["temperature", "top_p", "top_k"],
},
{
id: "claude-opus-4-8",
name: "Claude Opus 4.8",
Expand Down
1 change: 1 addition & 0 deletions open-sse/config/providers/registry/vertex/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const vertexProvider: RegistryEntry = {
...VERTEX_XAI_MODELS,
{ id: "claude-fable-5-1", name: "Claude Fable 5.1 (Vertex)", targetFormat: "claude" },
{ id: "claude-fable-5", name: "Claude Fable 5 (Vertex)", targetFormat: "claude" },
{ id: "claude-opus-5-5", name: "Claude Opus 5.5 (Vertex)", targetFormat: "claude" },
{ id: "claude-opus-5", name: "Claude Opus 5 (Vertex)", targetFormat: "claude" },
{ id: "claude-sonnet-5", name: "Claude Sonnet 5 (Vertex)", targetFormat: "claude" },
{ id: "claude-sonnet-5-5", name: "Claude Sonnet 5.5 (Vertex)", targetFormat: "claude" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const vertex_partnerProvider: RegistryEntry = {
...VERTEX_XAI_MODELS,
{ id: "claude-fable-5-1", name: "Claude Fable 5.1", targetFormat: "claude" },
{ id: "claude-fable-5", name: "Claude Fable 5", targetFormat: "claude" },
{ id: "claude-opus-5-5", name: "Claude Opus 5.5", targetFormat: "claude" },
{ id: "claude-opus-5", name: "Claude Opus 5", targetFormat: "claude" },
{ id: "claude-sonnet-5", name: "Claude Sonnet 5", targetFormat: "claude" },
{ id: "claude-sonnet-5-5", name: "Claude Sonnet 5.5", targetFormat: "claude" },
Expand Down
1 change: 1 addition & 0 deletions open-sse/services/modelFamilyFallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const FAMILY_FALLBACK_TEMPLATES: Record<string, readonly string[]> = {
"claude-fable-5": ["claude-opus-4-8", "claude-opus-4-7", "claude-sonnet-5"],

// Claude Opus family
"claude-opus-5-5": ["claude-opus-5", "claude-opus-4-8", "claude-sonnet-5"],
"claude-opus-5": ["claude-opus-4-8", "claude-opus-4-7", "claude-sonnet-5"],
"claude-opus-4-8": ["claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-5"],
"claude-opus-4-7": ["claude-opus-4-6", "claude-opus-4-5-20251101", "claude-sonnet-5"],
Expand Down
1 change: 1 addition & 0 deletions open-sse/services/providerCostData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const KNOWN_MODEL_PRICING: Record<string, ModelPricing> = {
"gpt-4o-mini": { inputCostPer1M: 0.15, outputCostPer1M: 0.6, isFree: false },
"claude-fable-5-1": { inputCostPer1M: 10.0, outputCostPer1M: 50.0, isFree: false },
"claude-fable-5": { inputCostPer1M: 15.0, outputCostPer1M: 75.0, isFree: false },
"claude-opus-5-5": { inputCostPer1M: 4.0, outputCostPer1M: 20.0, isFree: false },
"claude-opus-5": { inputCostPer1M: 5.0, outputCostPer1M: 25.0, isFree: false },
"claude-opus-4-8": { inputCostPer1M: 15.0, outputCostPer1M: 75.0, isFree: false },
"claude-opus-4-7": { inputCostPer1M: 15.0, outputCostPer1M: 75.0, isFree: false },
Expand Down
1 change: 1 addition & 0 deletions src/lib/db/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export async function getSettings() {
enabled: false,
supportedModels: [
"claude-fable-5",
"claude-opus-5-5",
"claude-opus-5",
"claude-opus-4-8",
"claude-opus-4-7",
Expand Down
1 change: 1 addition & 0 deletions src/lib/providers/claudeFastMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type JsonRecord = Record<string, unknown>;
*/
export const CLAUDE_FAST_MODE_DEFAULT_MODELS = [
"claude-fable-5",
"claude-opus-5-5",
"claude-opus-5",
"claude-opus-4-8",
"claude-opus-4-7",
Expand Down
1 change: 1 addition & 0 deletions src/lib/providers/staticModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const STATIC_MODEL_PROVIDERS: Record<string, () => Array<{ id: string; name: str
claude: () => [
{ id: "claude-fable-5-1", name: "Claude Fable 5.1" },
{ id: "claude-fable-5", name: "Claude Fable 5" },
{ id: "claude-opus-5-5", name: "Claude Opus 5.5" },
{ id: "claude-opus-5", name: "Claude Opus 5" },
{ id: "claude-opus-4-8", name: "Claude Opus 4.8" },
{ id: "claude-opus-4-7", name: "Claude Opus 4.7" },
Expand Down
16 changes: 16 additions & 0 deletions src/shared/constants/modelSpecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,22 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
aliases: BEDROCK_CLAUDE_ALIASES("claude-fable-5"),
},

// ── Claude Opus 5.5 ─────────────────────────────────────────────
"claude-opus-5-5": {
maxOutputTokens: 128000,
contextWindow: 1000000,
defaultThinkingBudget: 32000,
thinkingBudgetCap: 120000,
supportsThinking: true,
supportsTools: true,
supportsVision: true,
rejectsThinkingDisabled: true,
adaptiveThinkingOnly: true,
rejectsForcedToolChoice: true,
defaultReasoningEffort: "medium",
aliases: BEDROCK_CLAUDE_ALIASES("claude-opus-5-5", "claude-opus-5.5"),
},

// ── Claude Opus 5 ───────────────────────────────────────────────
"claude-opus-5": {
maxOutputTokens: 128000,
Expand Down
2 changes: 2 additions & 0 deletions src/shared/constants/pricing/frontier-labs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
GPT_5_6_TERRA_PRICING,
CLAUDE_FABLE_5_1_PRICING,
CLAUDE_FABLE_5_PRICING,
CLAUDE_OPUS_5_5_PRICING,
CLAUDE_OPUS_5_PRICING,
CLAUDE_OPUS_4_PRICING,
CLAUDE_SONNET_4_PRICING,
Expand Down Expand Up @@ -218,6 +219,7 @@ export const DEFAULT_PRICING_FRONTIER = {
// to cover hyphen-notation IDs (claude-opus-4-6) used by some clients
"claude-fable-5-1": CLAUDE_FABLE_5_1_PRICING,
"claude-fable-5": CLAUDE_FABLE_5_PRICING,
"claude-opus-5-5": CLAUDE_OPUS_5_5_PRICING,
"claude-opus-5": CLAUDE_OPUS_5_PRICING,
"claude-sonnet-5": CLAUDE_SONNET_5_PRICING,
"claude-sonnet-5-5": CLAUDE_SONNET_5_PRICING,
Expand Down
2 changes: 2 additions & 0 deletions src/shared/constants/pricing/oauth-subscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import {
GPT_6_ASTRA_PRICING,
CLAUDE_FABLE_5_1_PRICING,
CLAUDE_OPUS_5_5_PRICING,
CLAUDE_OPUS_5_PRICING,
GEMINI_3_7_FLASH_PROMO_PRICING,
GPT_5_3_CODEX_PRICING,
Expand Down Expand Up @@ -49,6 +50,7 @@ export const DEFAULT_PRICING_OAUTH = {
reasoning: 50.0,
cache_creation: 12.5,
},
"claude-opus-5-5": CLAUDE_OPUS_5_5_PRICING,
"claude-opus-5": CLAUDE_OPUS_5_PRICING,
"claude-opus-4-8": {
input: 5.0,
Expand Down
8 changes: 8 additions & 0 deletions src/shared/constants/pricing/shared-tiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ export const CLAUDE_FABLE_5_1_PRICING = {
cache_creation: 12.5,
};

export const CLAUDE_OPUS_5_5_PRICING = {
input: 4.0,
output: 20.0,
cached: 0.2,
reasoning: 20.0,
cache_creation: 5.0,
};

export const CLAUDE_OPUS_5_PRICING = {
input: 5.0,
output: 25.0,
Expand Down
23 changes: 13 additions & 10 deletions tests/unit/claude-codex-identity-version-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ test("Claude CLI version constants are in lockstep across all 4 sources", () =>
);
});

test("Claude CLI pin clears Anthropic's Opus 5.5 model gate (>= 2.1.280)", () => {
const [major, minor, patch] = canonical.CLAUDE_CODE_CLIENT_VERSION.split(".").map(Number);
const meetsGate = major > 2 || (major === 2 && (minor > 1 || (minor === 1 && patch >= 280)));
assert.ok(
meetsGate,
`claude-cli pin ${canonical.CLAUDE_CODE_CLIENT_VERSION} < 2.1.280 — Anthropic rejects claude-opus-5-5 with 400 "Claude Code ${canonical.CLAUDE_CODE_CLIENT_VERSION} does not support this model"`
);
});

test("Claude CLI wire versions match the captured 2.1.280 binary", () => {
assert.equal(canonical.CLAUDE_CODE_CLIENT_VERSION, "2.1.280");
assert.equal(canonical.CLAUDE_CODE_CLIENT_BUILD_REVISION, "1e2");
Expand Down Expand Up @@ -94,10 +103,7 @@ test("Codex client version locksteps Dockerfile @openai/codex", () => {
assert.equal(codexCfg.DEFAULT_CODEX_CLIENT_VERSION, pinned);
assert.equal(codexCfg.getCodexClientVersion(), pinned);
assert.equal(codexCfg.getCodexDefaultHeaders().Version, pinned);
assert.equal(
codexCfg.getCodexCliRsHeaders()["User-Agent"],
`codex_cli_rs/${pinned}`,
);
assert.equal(codexCfg.getCodexCliRsHeaders()["User-Agent"], `codex_cli_rs/${pinned}`);
});

test("Codex client version env override still wins", async () => {
Expand All @@ -110,7 +116,7 @@ test("Codex client version env override still wins", async () => {
test("test 7: live-empty GitHub catalog path does not call persist", () => {
const src = fs.readFileSync(
path.join(process.cwd(), "src/app/api/providers/[id]/models/route.ts"),
"utf8",
"utf8"
);
// The githubCatalogModels fallback must use buildResponse, not buildApiDiscoveryResponse.
const idx = src.indexOf("Codex live catalog unavailable — using GitHub model catalog");
Expand All @@ -137,16 +143,13 @@ test("Codex client version locksteps Dockerfile @openai/codex and env override",
assert.equal(codexCfg.DEFAULT_CODEX_CLIENT_VERSION, pinned);
assert.equal(codexCfg.getCodexClientVersion(), pinned);
assert.equal(codexCfg.getCodexDefaultHeaders().Version, pinned);
assert.equal(
codexCfg.getCodexCliRsHeaders()["User-Agent"],
`codex_cli_rs/${pinned}`,
);
assert.equal(codexCfg.getCodexCliRsHeaders()["User-Agent"], `codex_cli_rs/${pinned}`);
});

test("test 7: live-empty GitHub catalog path does not call persist", () => {
const src = fs.readFileSync(
path.join(process.cwd(), "src/app/api/providers/[id]/models/route.ts"),
"utf8",
"utf8"
);
// The githubCatalogModels fallback must use buildResponse, not buildApiDiscoveryResponse.
const idx = src.indexOf("Codex live catalog unavailable — using GitHub model catalog");
Expand Down
Loading
Loading