mpfaffenberger / mpfaffenberger/code_puppy

ClaudeCacheAsyncClient applies Claude-Code-OAuth header/URL transforms unconditionally — vanilla anthropic/custom_anthropic requests get claude-cli UA, oauth beta flags, ?beta=true; x-api-key removal is a no-op

Open Beginner friendly
#403 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
814
Forks
278
Avg merge
2d 5h
Merged PRs (30d)
76

Description

Problem

ClaudeCacheAsyncClient.send() (code_puppy/claude_cache_client.py, lines ~318-345) applies the Claude Code OAuth transformations to every request hitting /v1/messages, regardless of whether the client belongs to an OAuth model:

if is_messages_endpoint:
    ...
    # 1. Transform headers for Claude Code OAuth
    self._transform_headers_for_claude_code(headers)
    headers_modified = True

    # 2. Add ?beta=true query param
    url = self._add_beta_query_param(url)

But model_factory.py also uses ClaudeCacheAsyncClient for the plain anthropic (line ~590) and custom_anthropic (line ~640) model types — API-key based, no OAuth. For those models every request now gets:

  • user-agent: claude-cli/2.1.2 (external, cli) (misrepresents the client to Anthropic),
  • anthropic-beta: oauth-2025-04-20,interleaved-thinking-2025-05-14,... force-injected (these beta flags are OAuth/Claude-Code specific and override the carefully constructed _build_anthropic_beta_header() defaults),
  • ?beta=true appended to the URL.

Only the tool-name prefixing and httpx-level cache injection are correctly gated behind the _apply_claude_code_prefix constructor flag; the header/URL transforms are not.

Bonus bug: x-api-key removal is a silent no-op

_transform_headers_for_claude_code deletes x-api-key from the local headers dict, but the rebuild logic only sets headers back:

# Update headers
for key, value in headers.items():
    request.headers[key] = value

Deletions are never propagated to request.headers, so the removal does nothing. (This is accidentally what saves vanilla anthropic auth from breaking today — the API key survives only because the delete silently fails.) Either intent or implementation is wrong; right now both are.

Suggested fix

Gate steps 1-2 behind the same opt-in flag as the prefixing:

if is_messages_endpoint and self._apply_claude_code_prefix:
    self._transform_headers_for_claude_code(headers)
    url = self._add_beta_query_param(url)

and, when rebuilding, replace the header set wholesale (e.g. request.headers = httpx.Headers(headers)) so deletions actually take effect.

Filed by Zen Reviewer A (code-puppy-60635a)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in code_puppy/claude_cache_client.py at ClaudeCacheAsyncClient.send() and inspect how _apply_claude_code_prefix controls request handling. Verify that OAuth header and URL transforms apply only when that flag is enabled, and that rebuilding request headers propagates deletions. Done means vanilla anthropic and custom_anthropic requests retain their normal headers and URL while OAuth requests keep the intended transforms.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.