fix(anthropic-compatible): send Claude beta flags to nodes fronting Anthropic (#3797)
This commit is contained in:
@@ -154,7 +154,18 @@ export class DefaultExecutor extends BaseExecutor {
|
||||
for (const hook of desc.hooks || []) HEADER_HOOKS[hook]?.(headers, credentials);
|
||||
applyAuth(headers, desc, credentials);
|
||||
|
||||
if (this.provider === "claude" && model) {
|
||||
// anthropic-compatible-* nodes serving a real Claude model sit in front of
|
||||
// Anthropic itself (a rotating multi-account proxy, a corporate gateway),
|
||||
// so the request needs the same beta flags the `claude` provider sends:
|
||||
// without `context-management-2025-06-27` upstream rejects the
|
||||
// `context_management` block Claude Code puts in every request with
|
||||
// "context_management: Extra inputs are not permitted" (HTTP 400), and the
|
||||
// combo silently falls through to the next model. The model id gates this:
|
||||
// a node fronting Kimi or GLM answers on its own ids and never matches, so
|
||||
// gateways that would choke on unknown beta flags are left untouched.
|
||||
const isClaudeModel = typeof model === "string" && /^claude-/.test(model);
|
||||
if (model && (this.provider === "claude"
|
||||
|| (this.provider?.startsWith?.("anthropic-compatible-") && isClaudeModel))) {
|
||||
headers["Anthropic-Beta"] = selectAnthropicBeta(model);
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,46 @@ describe("DefaultExecutor.buildHeaders() — anthropic-compatible stripping", ()
|
||||
headers["Anthropic-Version"] || headers["anthropic-version"];
|
||||
expect(hasVersion).toBeDefined();
|
||||
});
|
||||
|
||||
// A node fronting Anthropic (rotating multi-account proxy, corporate gateway)
|
||||
// needs the same beta flags the `claude` provider sends. Without
|
||||
// context-management-2025-06-27 upstream answers HTTP 400
|
||||
// "context_management: Extra inputs are not permitted" and the combo falls
|
||||
// through to the next model without anyone noticing.
|
||||
it("sends context-management beta for a Claude model on a custom host", () => {
|
||||
const executor = new DefaultExecutor("anthropic-compatible-custom");
|
||||
const headers = executor.buildHeaders(
|
||||
{
|
||||
apiKey: "key",
|
||||
providerSpecificData: { baseUrl: "https://myproxy.example.com/v1" },
|
||||
},
|
||||
true,
|
||||
undefined,
|
||||
"claude-opus-5"
|
||||
);
|
||||
|
||||
const betaFlags = (headers["Anthropic-Beta"] || headers["anthropic-beta"] || "")
|
||||
.split(",").map(s => s.trim());
|
||||
expect(betaFlags).toContain("context-management-2025-06-27");
|
||||
// The first-party identity flag is still stripped for a non-Anthropic host.
|
||||
expect(betaFlags).not.toContain("claude-code-20250219");
|
||||
});
|
||||
|
||||
it("gates the beta flags on the model id, not the provider prefix", () => {
|
||||
const executor = new DefaultExecutor("anthropic-compatible-custom");
|
||||
const headers = executor.buildHeaders(
|
||||
{
|
||||
apiKey: "key",
|
||||
providerSpecificData: { baseUrl: "https://myproxy.example.com/v1" },
|
||||
},
|
||||
true,
|
||||
undefined,
|
||||
"kimi-k3"
|
||||
);
|
||||
|
||||
const betaVal = headers["Anthropic-Beta"] || headers["anthropic-beta"] || "";
|
||||
expect(betaVal).not.toContain("context-management-2025-06-27");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── proxyFetch anthropicFetch routing ────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user