Skip to content

fix(anthropic): strip context-1m beta on OAuth path#17442

Closed
SkylineAtDayAndNight wants to merge 2 commits into
NousResearch:mainfrom
SkylineAtDayAndNight:feat/oauth-strip-1m-beta
Closed

fix(anthropic): strip context-1m beta on OAuth path#17442
SkylineAtDayAndNight wants to merge 2 commits into
NousResearch:mainfrom
SkylineAtDayAndNight:feat/oauth-strip-1m-beta

Conversation

@SkylineAtDayAndNight

Copy link
Copy Markdown

Summary

Consumer Claude subscriptions (Pro/Max via OAuth) reject the context-1m-2025-08-07 beta with HTTP 400 ("long context beta is not yet available for this subscription") even on models that don't use 1M context (e.g. Haiku 4.5). The header is rejected pre-routing, so requests fail before reaching the model at all — every Hermes user authenticating via the macOS keychain Claude Code OAuth path is blocked regardless of which model they pick.

Repro

# macOS, with Claude Code logged in (OAuth token in keychain)
hermes chat -q "hi" --provider anthropic --model claude-haiku-4-5-20251001
Error: Error code: 400 - {'type': 'error', 'error': {'type':
'invalid_request_error', 'message': 'The long context beta is not
yet available for this subscription.'}, 'request_id': 'req_011...'}

Root cause

agent/anthropic_adapter.py:234 defines _COMMON_BETAS with context-1m-2025-08-07 included unconditionally. The OAuth branch at line ~471 takes common_betas + _OAUTH_ONLY_BETAS, never strips 1m, and sends it on every request.

The existing comment block at lines 220-233 documents the header as "harmless no-op on endpoints where 1M is GA" — true for console.anthropic.com API-key callers, but consumer-tier OAuth subscriptions enforce a stricter beta allowlist and reject unrecognized betas pre-routing.

Fix

Mirror the _requires_bearer_auth path's existing precedent for stripping incompatible betas — but for the OAuth branch, only strip _CONTEXT_1M_BETA:

oauth_common_betas = [b for b in common_betas if b != _CONTEXT_1M_BETA]
all_betas = oauth_common_betas + _OAUTH_ONLY_BETAS

Direct API-key callers (else branch) keep the full _COMMON_BETAS — their gating policy accepts the header as a no-op.

Test plan

  • New unit test TestBuildAnthropicClient::test_oauth_strips_context_1m_beta — asserts context-1m-2025-08-07 absent from OAuth request headers, OAuth-only betas still present
  • pytest tests/agent/test_anthropic_adapter.py::TestBuildAnthropicClient -v → 6/6 pass
  • Full file regression: pytest tests/agent/test_anthropic_adapter.py → identical pre-existing failure set vs main (19 unrelated keychain-mocking failures, 0 new failures introduced)
  • Manual end-to-end: hermes chat -q "..." --provider anthropic --model claude-haiku-4-5-20251001 — error changes from "long context beta is not yet available for this subscription" to "Third-party apps now draw from your extra usage...", confirming the request now passes the beta-allowlist gate and reaches the actual subscription/usage layer

Scope notes (deliberately out)

  1. No opt-in flag for users with 1M-enabled OAuth tiers — keeping the default safer for the common consumer-tier case. A follow-up PR can add a config knob (e.g. model.context_1m: true) once we know whether any subscription tier actually unlocks 1M via OAuth.
  2. The 19 pre-existing test failures are not fixed here — per CONTRIBUTING.md they're tracked separately. Briefly: TestResolveAnthropicToken / TestReadClaudeCodeCredentials / TestRunOauthSetupToken mock env vars and Path.home, but never mock _read_claude_code_credentials_from_keychain, so on developer machines with Claude Code logged in the subprocess returns a real token and tests fail. Happy to file a separate PR mocking the keychain read if maintainers want.

…er subscriptions

Consumer Claude subscriptions (Pro/Max via OAuth) reject the
context-1m-2025-08-07 beta with HTTP 400 ("long context beta is not yet
available for this subscription") even on models that don't use 1M
context (e.g. Haiku 4.5). The header is rejected pre-routing, so requests
fail before reaching the model at all, blocking all OAuth users on
consumer-tier subscriptions regardless of which model they pick.

Strip context-1m-2025-08-07 from the OAuth path. Direct API-key callers
(console.anthropic.com) keep full _COMMON_BETAS — their gating policy
accepts the header as a no-op as documented in the comment block at
lines 220-233 of agent/anthropic_adapter.py.

Repro (with macOS keychain holding Claude Code OAuth):
  hermes chat -q "hi" --provider anthropic \
    --model claude-haiku-4-5-20251001
  # → HTTP 400 "long context beta is not yet available for this subscription"

After fix: request reaches the routing layer, where the actual
subscription gating (e.g. extra-usage credits) surfaces a clear
user-facing message instead of the cryptic beta rejection.
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround provider/anthropic Anthropic native Messages API comp/agent Core agent loop, run_agent.py, prompt builder area/auth Authentication, OAuth, credential pools labels Apr 29, 2026
…-beta

# Conflicts:
#	tests/agent/test_anthropic_adapter.py
@SkylineAtDayAndNight

Copy link
Copy Markdown
Author

Superseded by #17752 (merged 2026-04-29) which addresses the same consumer-subscription issue with reactive recovery — keeps 1M context for capable subscriptions and only strips the beta after a 400 rejection. Closing.

@SkylineAtDayAndNight SkylineAtDayAndNight deleted the feat/oauth-strip-1m-beta branch April 30, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent loop, run_agent.py, prompt builder P1 High — major feature broken, no workaround provider/anthropic Anthropic native Messages API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants