fix(anthropic): prevent OAuth billing classifier from routing subscription calls to extra-usage - #80854
Open
joseffiran wants to merge 1 commit into
Open
Conversation
…ption calls to extra-usage Anthropic's OAuth billing classifier inspects the full request body (system prompt text, tool names, tool descriptions, tool schema footprint) for third-party fingerprints. Any match flips native-Anthropic OAuth (Claude Pro/Max subscription) requests from plan-billing to the extra-usage lane, which 400s once extra usage is exhausted -- even though the actual subscription has quota. This took the gateway/cron down repeatedly with 'You'\''re out of extra usage' errors that looked like credential/quota failures but were not. Two independent mitigations, both scoped to is_oauth/_is_anthropic_oauth sessions only (never applied to third-party Anthropic-compatible endpoints): 1. Text sanitization (anthropic_adapter.py): expand the system-prompt product-name replacement table from 4 to 13 patterns (standalone 'Hermes', bare 'Nous', 'Nous Portal', 'nousresearch', 'hermes_agent', etc.), and extend sanitization to tool descriptions and tool_choice names (previously only tool names were normalized to the mcp__ wire form). Ordered most-specific-pattern-first. 2. Tool-schema footprint reduction (agent_init.py, model_tools.py, tools/tool_search.py, tools/mcp_tool.py, toolsets.py): confirmed empirically that sending the full ~60-tool core set on every OAuth turn reliably trips the classifier even with full text sanitization (0 tools -> succeeds, full core set -> 400). Added toolsets.OAUTH_SAFE_CORE_TOOLS, a minimal always-eager allowlist for native-Anthropic OAuth sessions; everything else in the normal core set becomes deferrable via the tool_search/describe/call bridge (still fully reachable, just not eagerly listed). Wired through agent_init (initial snapshot) and mcp_tool.refresh_agent_mcp_tools (mid-conversation MCP registration refresh, which previously silently re-expanded back to the full core set and re-tripped the classifier on the next turn). 108/108 tests pass in tests/agent/test_anthropic_adapter.py. Local-only fix pending upstream PR to NousResearch/hermes-agent -- was previously sitting uncommitted in the working tree and got silently autostashed (and one incomplete copy dropped) by 'hermes update' on 2026-08-06, which is what caused this to regress and knocked the gateway offline again on 2026-08-07.
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Anthropic's OAuth billing classifier inspects the full request body (system prompt text, tool names, tool descriptions, and tool-schema footprint) for third-party fingerprints. Any match flips native-Anthropic OAuth (Claude Pro/Max subscription) requests from plan-billing to the "extra usage" lane, which returns
HTTP 400 "You're out of extra usage"once extra usage is exhausted — even though the account's actual plan subscription has quota. This repeatedly took a real gateway + cron install down with errors that looked like credential/quota failures but were not (confirmed via three matched requests where only the tool-name form differed: bare tool names → 400,mcp__-prefixed → 200 OK).Fix
Two independent,
is_oauth/_is_anthropic_oauth-scoped mitigations (never applied to third-party Anthropic-compatible endpoints):Text sanitization (
anthropic_adapter.py): expand the system-prompt product-name replacement table from 4 to 13 patterns (standalone"Hermes", bare"Nous","Nous Portal","nousresearch","hermes_agent", etc.), ordered most-specific-first. Extend sanitization to tool descriptions andtool_choicenames (previously only tool names were normalized to themcp__wire form).Tool-schema footprint reduction (
agent_init.py,model_tools.py,tools/tool_search.py,tools/mcp_tool.py,toolsets.py): confirmed empirically that sending the full ~60-tool core set on every OAuth turn reliably trips the classifier even with full text sanitization (0 tools → succeeds, full core set → 400). Addstoolsets.OAUTH_SAFE_CORE_TOOLS, a minimal always-eager allowlist for native-Anthropic OAuth sessions; everything else in the normal core set becomes deferrable via the existingtool_search/describe/callbridge (still fully reachable, just not eagerly listed on every turn). Wired throughagent_init(initial snapshot) andmcp_tool.refresh_agent_mcp_tools(the mid-conversation MCP-registration refresh, which previously silently re-expanded back to the full core set and re-tripped the classifier on the very next turn).Testing
tests/agent/test_anthropic_adapter.py: 108/108 passing, including new coverage for the expanded replacement table and tool-description/tool_choice sanitization.Rebased clean onto current
mainwith no conflicts.