fix(ai/providers): drop context-1m beta from anthropic oauth requests

The 17.2.1 cowork request profile appended context-1m-2025-08-07 for any
model with a 1M catalog window, but that gate only runs on the OAuth path.
Subscription (Pro/Max) credentials have no long-context credit balance, so
Anthropic hard-429s ('Usage credits are required for long context requests')
on every beta-gated 1M model regardless of prompt size, breaking all
subagents (task/smol/scout resolve to claude-sonnet-4-6).

The beta is no longer advertised on OAuth requests; subscription accounts
transparently get the standard 200k window. Natively-1M models like
claude-sonnet-5 serve their full window without the beta anyway.

Fixes #7238
This commit is contained in:
roboomp
2026-08-01 06:05:17 +00:00
committed by can1357
parent 71c755d5f6
commit 46bdfff8aa
3 changed files with 17 additions and 14 deletions
+3
View File
@@ -5,6 +5,9 @@
### Added
- Added the ai& (`aiand`) provider registry entry with API-key paste login validated against `https://api.aiand.com/v1/models`.
### Fixed
- Fixed Anthropic OAuth (Claude Pro/Max subscription) requests hard-429ing (`Usage credits are required for long context requests`) on every beta-gated 1M model — e.g. `claude-sonnet-4-6`, which the default `task`/`smol`/`scout` subagent roles resolve to — regardless of prompt size, breaking all subagents. The 17.2.1 cowork request profile reintroduced the `context-1m-2025-08-07` beta for any model with a 1M catalog window, but subscription credentials have no long-context credit balance so Anthropic rejects the request outright. The beta is no longer advertised on OAuth requests; subscription accounts transparently get the standard 200k window. ([#7238](https://github.com/can1357/oh-my-pi/issues/7238))
## [17.2.2] - 2026-07-31
+7 -12
View File
@@ -157,7 +157,6 @@ function mergeAnthropicBetaHeader(callerHeaders: Record<string, string>, beta: s
const midConversationSystemBeta = "mid-conversation-system-2026-04-07";
const contextManagementBeta = "context-management-2025-06-27";
const structuredOutputsBeta = "structured-outputs-2025-12-15";
const context1mBeta = "context-1m-2025-08-07";
const thinkingTokenCountBeta = "thinking-token-count-2026-05-13";
const fallbackCreditBeta = "fallback-credit-2026-06-01";
const coworkUtilityBetaDefaults = [
@@ -187,15 +186,18 @@ const serverSideFallbackBeta = "server-side-fallback-2026-06-01";
function buildCoworkBetas(
agentRequest: boolean,
thinkingRequest: boolean,
longContext: boolean,
disableStrictTools = false,
): readonly string[] {
// `context-1m-2025-08-07` is intentionally never advertised. OAuth
// subscription credentials have no long-context credit balance, so Anthropic
// hard-429s ("Usage credits are required for long context requests") on any
// beta-gated 1M model regardless of prompt size (#7238). Natively-1M models
// (e.g. claude-sonnet-5) serve their full window without the beta anyway.
if (!agentRequest && !disableStrictTools) return coworkUtilityBetaDefaults;
const betas: string[] = [];
for (const beta of agentRequest ? coworkAgentBetaDefaults : coworkUtilityBetaDefaults) {
if (disableStrictTools && beta === structuredOutputsBeta) continue;
betas.push(beta);
if (agentRequest && longContext && beta === "claude-code-20250219") betas.push(context1mBeta);
}
if (!agentRequest) return betas;
if (thinkingRequest) betas.push(effortBeta);
@@ -245,7 +247,7 @@ export function buildAnthropicHeaders(options: AnthropicHeaderOptions): Record<s
// Cowork's beta profile is part of the OAuth fingerprint; API-key requests
// default to extras only, matching the streaming path.
const betaHeader = buildBetaHeader(
options.coworkBetas ?? (oauthToken ? buildCoworkBetas(true, true, false) : []),
options.coworkBetas ?? (oauthToken ? buildCoworkBetas(true, true) : []),
extraBetas,
);
const acceptHeader = oauthToken ? "application/json" : stream ? "text/event-stream" : "application/json";
@@ -2949,14 +2951,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
isCloudflareAiGateway: model.provider === "cloudflare-ai-gateway",
allowAnthropicHeaderOverrides: model.compat.allowAnthropicHeaderOverrides,
claudeCodeSessionId,
coworkBetas: oauthToken
? buildCoworkBetas(
hasTools || thinkingEnabled,
thinkingEnabled,
(model.contextWindow ?? 0) >= 1_000_000,
disableStrictTools,
)
: [],
coworkBetas: oauthToken ? buildCoworkBetas(hasTools || thinkingEnabled, thinkingEnabled, disableStrictTools) : [],
});
if (model.provider === "cloudflare-ai-gateway") {
+7 -2
View File
@@ -234,7 +234,11 @@ describe("Anthropic request fingerprint alignment", () => {
expect(hiddenUtility.defaultHeaders["anthropic-beta"]).not.toContain("redact-thinking-2026-02-12");
});
it("adds Cowork's context-1m beta for million-token models", () => {
it("never advertises context-1m on OAuth requests for million-token models (#7238)", () => {
// OAuth subscription credentials have no long-context credit balance, so
// advertising `context-1m-2025-08-07` hard-429s beta-gated 1M models
// ("Usage credits are required for long context requests") regardless of
// prompt size, breaking every subagent on Claude Pro/Max.
const longContextModel = buildModel({
...ANTHROPIC_MODEL_SPEC,
id: "claude-opus-5",
@@ -250,8 +254,9 @@ describe("Anthropic request fingerprint alignment", () => {
});
expect(options.defaultHeaders["anthropic-beta"]).toBe(
"claude-code-20250219,context-1m-2025-08-07,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,advanced-tool-use-2025-11-20,effort-2025-11-24,fallback-credit-2026-06-01",
"claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,advanced-tool-use-2025-11-20,effort-2025-11-24,fallback-credit-2026-06-01",
);
expect(options.defaultHeaders["anthropic-beta"]).not.toContain("context-1m-2025-08-07");
});
it("matches Cowork's system-block layout: billing and instruction uncached, single breakpoint on the last context block", () => {