mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(claude): omit context-1m beta for Sonnet (#2568)
Integrated into release/v3.8.2
This commit is contained in:
committed by
GitHub
parent
e23a93eb3b
commit
2fd5275833
@@ -285,18 +285,29 @@ export function parseUpstreamMetadataUserId(
|
||||
// ---------- anthropic-beta selector --------------------------------------
|
||||
|
||||
/**
|
||||
* Models that support the heavy-agent beta tier (context-1m, effort,
|
||||
* advanced-tool-use). Only Opus/Sonnet are eligible — Haiku with OAuth
|
||||
* authentication rejects `context-1m-2025-08-07` with
|
||||
* "This authentication style is incompatible with the long context beta header"
|
||||
* (issue #2454). Matches real Claude Desktop, which omits these flags for Haiku.
|
||||
* Models that support the heavy-agent beta tier (effort, advanced-tool-use).
|
||||
* Only Opus/Sonnet are eligible — Haiku with OAuth authentication rejects
|
||||
* heavy agent flags (issue #2454). Matches real Claude Code captures.
|
||||
*/
|
||||
const HEAVY_AGENT_BETA_MODEL_PREFIXES = ["claude-opus", "claude-sonnet"];
|
||||
/**
|
||||
* Models that support the context-1m beta tier. Only Opus is eligible;
|
||||
* Sonnet trips long-context credit gates under OAuth full-agent traffic.
|
||||
*/
|
||||
const CONTEXT_1M_BETA_MODEL_PREFIXES = ["claude-opus"];
|
||||
|
||||
function isHeavyAgentModel(model: unknown): boolean {
|
||||
function matchesModelPrefix(model: unknown, prefixes: string[]): boolean {
|
||||
if (typeof model !== "string") return false;
|
||||
const normalized = model.toLowerCase();
|
||||
return HEAVY_AGENT_BETA_MODEL_PREFIXES.some((prefix) => normalized.includes(prefix));
|
||||
return prefixes.some((prefix) => normalized.includes(prefix));
|
||||
}
|
||||
|
||||
function isHeavyAgentModel(model: unknown): boolean {
|
||||
return matchesModelPrefix(model, HEAVY_AGENT_BETA_MODEL_PREFIXES);
|
||||
}
|
||||
|
||||
function isContext1mModel(model: unknown): boolean {
|
||||
return matchesModelPrefix(model, CONTEXT_1M_BETA_MODEL_PREFIXES);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,9 +315,10 @@ function isHeavyAgentModel(model: unknown): boolean {
|
||||
* uses three patterns: minimal probe, structured-output, and full agent.
|
||||
* Sending the full set on every shape is itself a fingerprint.
|
||||
*
|
||||
* The heavy-agent flags (context-1m, effort, advanced-tool-use) are gated on
|
||||
* the model as well as the shape: Haiku must never receive `context-1m`, which
|
||||
* Anthropic rejects under OAuth authentication.
|
||||
* The heavy-agent flags are gated on the model as well as the shape. In direct
|
||||
* Claude Code captures, Sonnet receives effort/advanced-tool-use but not
|
||||
* context-1m; sending context-1m to Sonnet trips Anthropic's long-context credit
|
||||
* gate for accounts where direct Claude Code works.
|
||||
*/
|
||||
export function selectBetaFlags(
|
||||
body: Record<string, unknown> | null | undefined,
|
||||
@@ -325,24 +337,27 @@ export function selectBetaFlags(
|
||||
const isFullAgent = hasTools && hasSystem;
|
||||
const effectiveModel = model ?? (typeof b.model === "string" ? b.model : "");
|
||||
const isHeavyAgent = isFullAgent && isHeavyAgentModel(effectiveModel);
|
||||
const isContext1m = isFullAgent && isContext1mModel(effectiveModel);
|
||||
|
||||
const flags: string[] = [];
|
||||
if (isFullAgent) flags.push("claude-code-20250219");
|
||||
flags.push("oauth-2025-04-20");
|
||||
if (isHeavyAgent) flags.push("context-1m-2025-08-07");
|
||||
if (isContext1m) flags.push("context-1m-2025-08-07");
|
||||
flags.push(
|
||||
"interleaved-thinking-2025-05-14",
|
||||
"redact-thinking-2026-02-12",
|
||||
"thinking-token-count-2026-05-13",
|
||||
"context-management-2025-06-27",
|
||||
"prompt-caching-scope-2026-01-05"
|
||||
);
|
||||
if (hasStructuredOutput || isFullAgent) flags.push("advisor-tool-2026-03-01");
|
||||
if (hasStructuredOutput && !isFullAgent) flags.push("structured-outputs-2025-12-15");
|
||||
// extended-cache-ttl is sent for all full-agent shapes (incl. Haiku); the
|
||||
// heavier advanced-tool-use / effort flags are Opus/Sonnet-only.
|
||||
if (isFullAgent) flags.push("extended-cache-ttl-2025-04-11", "cache-diagnosis-2026-04-07");
|
||||
// heavier afk-mode / advanced-tool-use / effort flags are Opus/Sonnet-only.
|
||||
if (isFullAgent) {
|
||||
flags.push("extended-cache-ttl-2025-04-11", "cache-diagnosis-2026-04-07");
|
||||
}
|
||||
if (isHeavyAgent) {
|
||||
flags.push("advanced-tool-use-2025-11-20", "effort-2025-11-24");
|
||||
flags.push("afk-mode-2026-01-31", "advanced-tool-use-2025-11-20", "effort-2025-11-24");
|
||||
}
|
||||
return flags.join(",");
|
||||
}
|
||||
|
||||
@@ -50,13 +50,7 @@ const CLAUDE_CODE_COMPATIBLE_DEFAULT_SYSTEM_BLOCKS = [
|
||||
text: "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
|
||||
},
|
||||
];
|
||||
const CONTEXT_1M_SUPPORTED_MODELS = [
|
||||
"claude-opus-4-7",
|
||||
"claude-opus-4-6",
|
||||
"claude-sonnet-4-6",
|
||||
"claude-sonnet-4-5",
|
||||
"claude-sonnet-4",
|
||||
];
|
||||
const CONTEXT_1M_SUPPORTED_MODELS = ["claude-opus-4-7", "claude-opus-4-6"];
|
||||
export const CLAUDE_CODE_COMPATIBLE_STAINLESS_TIMEOUT_SECONDS = getStainlessTimeoutSeconds(
|
||||
process.env
|
||||
);
|
||||
|
||||
@@ -5,8 +5,9 @@ const { selectBetaFlags } = await import("../../open-sse/executors/claudeIdentit
|
||||
|
||||
// Regression for #2454: Haiku with OAuth rejects `context-1m-2025-08-07` with
|
||||
// 400 "This authentication style is incompatible with the long context beta header".
|
||||
// The heavy-agent beta tier (context-1m, effort, advanced-tool-use) must be gated on
|
||||
// The heavy-agent beta tier (effort, advanced-tool-use) must be gated on
|
||||
// Opus/Sonnet only; Haiku still receives the general full-agent flags.
|
||||
// context-1m is Opus-only in captured Claude Code traffic.
|
||||
|
||||
function fullAgentBody(model: string) {
|
||||
return {
|
||||
@@ -19,6 +20,7 @@ function fullAgentBody(model: string) {
|
||||
test("#2454 Haiku full-agent omits heavy-agent beta flags", () => {
|
||||
const flags = selectBetaFlags(fullAgentBody("claude-haiku-4-5-20251001"));
|
||||
assert.ok(!flags.includes("context-1m-2025-08-07"), "Haiku must NOT receive context-1m");
|
||||
assert.ok(!flags.includes("afk-mode-2026-01-31"), "Haiku must NOT receive afk-mode");
|
||||
assert.ok(!flags.includes("effort-2025-11-24"), "Haiku must NOT receive effort");
|
||||
assert.ok(
|
||||
!flags.includes("advanced-tool-use-2025-11-20"),
|
||||
@@ -31,11 +33,14 @@ test("#2454 Haiku full-agent omits heavy-agent beta flags", () => {
|
||||
assert.ok(flags.includes("extended-cache-ttl-2025-04-11"));
|
||||
});
|
||||
|
||||
test("#2454 Sonnet full-agent includes heavy-agent beta flags", () => {
|
||||
test("#2454 Sonnet full-agent includes heavy-agent flags but omits context-1m", () => {
|
||||
const flags = selectBetaFlags(fullAgentBody("claude-sonnet-4-6"));
|
||||
assert.ok(flags.includes("context-1m-2025-08-07"), "Sonnet should receive context-1m");
|
||||
assert.ok(!flags.includes("context-1m-2025-08-07"), "Sonnet must NOT receive context-1m");
|
||||
assert.ok(flags.includes("effort-2025-11-24"));
|
||||
assert.ok(flags.includes("advanced-tool-use-2025-11-20"));
|
||||
assert.ok(flags.includes("thinking-token-count-2026-05-13"));
|
||||
assert.ok(flags.includes("afk-mode-2026-01-31"));
|
||||
assert.ok(!flags.includes("redact-thinking-2026-02-12"));
|
||||
});
|
||||
|
||||
test("#2454 Opus full-agent includes heavy-agent beta flags", () => {
|
||||
|
||||
@@ -569,7 +569,7 @@ test("DefaultExecutor.execute uses CC-compatible connection defaults to append 1
|
||||
|
||||
assert.equal(calls[0].headers["anthropic-beta"].includes(CONTEXT_1M_BETA_HEADER), false);
|
||||
assert.equal(calls[1].headers["anthropic-beta"].includes(CONTEXT_1M_BETA_HEADER), true);
|
||||
assert.equal(calls[2].headers["anthropic-beta"], CONTEXT_1M_BETA_HEADER);
|
||||
assert.equal(calls[2].headers["anthropic-beta"], undefined);
|
||||
});
|
||||
|
||||
test("DefaultExecutor.execute only injects adaptive thinking defaults for Claude models that support x-high effort", async () => {
|
||||
|
||||
Reference in New Issue
Block a user