mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 11:13:43 +08:00
fix(anthropic): drop (external, cli) UA suffix — it's the anti-abuse fingerprint
This commit is contained in:
parent
84cb442446
commit
ed3ff54f0c
@ -38,9 +38,10 @@ import vip.mate.llm.model.ModelProviderEntity;
|
||||
* {@code oauth-2025-04-20} or Anthropic's edge intermittently 500s.
|
||||
* We push these via {@link AnthropicApi.Builder#anthropicBetaFeatures}
|
||||
* so Spring AI's existing header-merging logic still applies.</li>
|
||||
* <li>{@code User-Agent: claude-cli/<ver> (external, cli)} and
|
||||
* {@code x-app: cli} masquerade as the Claude Code CLI — Anthropic
|
||||
* rejects unrecognised UAs on Bearer-auth requests with HTTP 400.</li>
|
||||
* <li>{@code User-Agent: claude-cli/<ver>} (bare — no suffix) and
|
||||
* {@code x-app: cli} masquerade as the Claude Code CLI. Suffix variants
|
||||
* like {@code (external, cli)} are anti-abuse fingerprints; see
|
||||
* {@link ClaudeCodeApiHeaders#userAgent()}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <h2>Token lifecycle</h2>
|
||||
|
||||
@ -20,7 +20,7 @@ import java.util.List;
|
||||
* <caption>Header set sent on OAuth requests</caption>
|
||||
* <tr><th>Header</th><th>Value</th><th>Why</th></tr>
|
||||
* <tr><td>{@code Authorization}</td><td>{@code Bearer <accessToken>}</td><td>OAuth path uses Bearer; non-OAuth uses {@code x-api-key}</td></tr>
|
||||
* <tr><td>{@code User-Agent}</td><td>{@code claude-cli/<version> (external, cli)}</td><td>Anthropic routes OAuth by UA; spoof identity</td></tr>
|
||||
* <tr><td>{@code User-Agent}</td><td>{@code claude-cli/<version>}</td><td>bare form — suffix triggers anti-abuse fingerprint, see {@link #userAgent()}</td></tr>
|
||||
* <tr><td>{@code x-app}</td><td>{@code cli}</td><td>Claude Code identity flag</td></tr>
|
||||
* <tr><td>{@code anthropic-beta}</td><td>(comma-joined list — see {@link #allBetas()})</td><td>OAuth-only + common feature betas</td></tr>
|
||||
* </table>
|
||||
@ -58,12 +58,20 @@ public class ClaudeCodeApiHeaders {
|
||||
|
||||
/**
|
||||
* User-Agent string Anthropic OAuth infrastructure expects.
|
||||
* Format: {@code claude-cli/<version> (external, cli)}.
|
||||
* The {@code (external, cli)} suffix is the canonical hermes / OpenCode /
|
||||
* Cline identity — drop it and Anthropic returns 400.
|
||||
* Format: {@code claude-cli/<version>} — bare, no suffix.
|
||||
*
|
||||
* <p><b>History note:</b> we previously appended {@code (external, cli)}
|
||||
* after hermes-agent's pattern. That turned out to be wrong: Anthropic's
|
||||
* anti-abuse gate uses the suffix to fingerprint third-party clients
|
||||
* (hermes / OpenCode / Cline) and rate-limits them harder. Real Claude
|
||||
* Code (Electron + Node + official Anthropic JS SDK) emits the bare
|
||||
* {@code claude-cli/<v>} form, which is what openclaw
|
||||
* ({@code anthropic-transport-stream.ts:30,572}) also uses. Verified by
|
||||
* reproducing 429 with the suffix and {@code anthropic-ratelimit-*}
|
||||
* headers absent — the diagnostic signature of the anti-abuse path.
|
||||
*/
|
||||
public String userAgent() {
|
||||
return "claude-cli/" + versionDetector.get() + " (external, cli)";
|
||||
return "claude-cli/" + versionDetector.get();
|
||||
}
|
||||
|
||||
/** {@code x-app} header value. Constant. */
|
||||
|
||||
@ -80,8 +80,11 @@ public class ClaudeCodeTokenRefresher {
|
||||
.uri(endpoint)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
// Bare UA — see ClaudeCodeApiHeaders.userAgent() javadoc
|
||||
// for why the (external, cli) suffix would trip Anthropic's
|
||||
// anti-abuse fingerprint.
|
||||
.header(HttpHeaders.USER_AGENT,
|
||||
"claude-cli/" + versionDetector.get() + " (external, cli)")
|
||||
"claude-cli/" + versionDetector.get())
|
||||
.body(body)
|
||||
.retrieve()
|
||||
.body(String.class);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user