mirror of
https://github.com/decolua/9router.git
synced 2026-05-08 12:01:28 +00:00
- Add claudeHeaderCache.js to intercept and cache live Claude Code client headers - Forward cached headers dynamically to api.anthropic.com via default.js - Strip first-party identity headers (x-app, claude-code-* beta) for non-Anthropic upstreams - Validate and sanitize tool call IDs to match Anthropic pattern (^[a-zA-Z0-9_-]+$) - Skip thinking blocks when applying cache_control; fix max_tokens buffer (+1024) - Strip cache_control from thinking blocks in openai-to-claude translator - Comment out thoughtSignature in Gemini translator (kept for reference) - Expand .gitignore to match all deploy*.sh variants Co-authored-by: kwanLeeFrmVi <quanle96@outlook.com> Closes #433 Made-with: Cursor
70 lines
2.0 KiB
JavaScript
70 lines
2.0 KiB
JavaScript
/**
|
|
* Singleton cache for real Claude Code client headers.
|
|
* Captures headers from authentic Claude Code requests and makes them available
|
|
* for forwarding to api.anthropic.com, replacing static hardcoded values.
|
|
*/
|
|
|
|
const CLAUDE_IDENTITY_HEADERS = [
|
|
"user-agent",
|
|
"anthropic-beta",
|
|
"anthropic-version",
|
|
"anthropic-dangerous-direct-browser-access",
|
|
"x-app",
|
|
"x-stainless-helper-method",
|
|
"x-stainless-retry-count",
|
|
"x-stainless-runtime-version",
|
|
"x-stainless-package-version",
|
|
"x-stainless-runtime",
|
|
"x-stainless-lang",
|
|
"x-stainless-arch",
|
|
"x-stainless-os",
|
|
"x-stainless-timeout",
|
|
"package-version",
|
|
"runtime-version",
|
|
"os",
|
|
"arch",
|
|
];
|
|
|
|
let cachedHeaders = null;
|
|
|
|
/**
|
|
* Detect if request headers look like a real Claude Code client.
|
|
* @param {object} headers - Lowercase header key/value object
|
|
*/
|
|
function isClaudeCodeClient(headers) {
|
|
const ua = (headers["user-agent"] || "").toLowerCase();
|
|
const xApp = (headers["x-app"] || "").toLowerCase();
|
|
return ua.includes("claude-cli") || ua.includes("claude-code") || xApp === "cli";
|
|
}
|
|
|
|
/**
|
|
* Store Claude Code identity headers if this looks like a real client request.
|
|
* Called at the entry point before any translation/forwarding.
|
|
* @param {object} headers - Lowercase header key/value object (from request.headers.entries())
|
|
*/
|
|
export function cacheClaudeHeaders(headers) {
|
|
if (!headers || typeof headers !== "object") return;
|
|
if (!isClaudeCodeClient(headers)) return;
|
|
|
|
const captured = {};
|
|
for (const key of CLAUDE_IDENTITY_HEADERS) {
|
|
if (headers[key] !== undefined && headers[key] !== null) {
|
|
captured[key] = headers[key];
|
|
}
|
|
}
|
|
|
|
if (Object.keys(captured).length > 0) {
|
|
cachedHeaders = captured;
|
|
console.log(`[ClaudeHeaders] Cached ${Object.keys(captured).length} identity headers from Claude Code client`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the most recently cached Claude Code identity headers.
|
|
* Returns null if no authentic client request has been seen yet (cold start).
|
|
* @returns {object|null}
|
|
*/
|
|
export function getCachedClaudeHeaders() {
|
|
return cachedHeaders;
|
|
}
|