mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-19 21:32:20 +03:00
* fix(claude): forward client-negotiated thinking-binding-controls and thinking-display-updates betas Gateways drops anthropic-beta tokens not on FORWARDABLE_CLIENT_BETAS, so @ai-sdk/anthropic Fable 5.1 requests carrying thinking.block_binding were rejected upstream with thinking.adaptive.block_binding: Extra inputs are not permitted even when the client negotiated thinking-binding-controls-2026-08-01 correctly. Same class for thinking.display updates (thinking-display-updates-2026-08-18). Regression guard: tests/unit/thinking-binding-controls-beta-forward.test.ts * chore(changelog): fragment for #12989 * chore: trim comments
70 lines
3.1 KiB
TypeScript
70 lines
3.1 KiB
TypeScript
/**
|
|
* Fable 5.1 sends `thinking.block_binding` + `thinking-binding-controls-2026-08-01`
|
|
* (and `thinking.display` + `thinking-display-updates-2026-08-18`) automatically.
|
|
* The gateway stripped both betas, so upstream 400'd with `Extra inputs are not
|
|
* permitted`. Both must be forwarded when the client negotiates them.
|
|
*/
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { ANTHROPIC_BETA_API_KEY, mergeClientAnthropicBeta, FORWARDABLE_CLIENT_BETAS } =
|
|
await import("../../open-sse/config/anthropicHeaders.ts");
|
|
|
|
const BINDING_CONTROLS = "thinking-binding-controls-2026-08-01";
|
|
const DISPLAY_UPDATES = "thinking-display-updates-2026-08-18";
|
|
|
|
// ── allowlist membership ────────────────────────────────────────────────────
|
|
|
|
test("FORWARDABLE_CLIENT_BETAS must include thinking-binding-controls beta", () => {
|
|
assert.ok(FORWARDABLE_CLIENT_BETAS.includes(BINDING_CONTROLS));
|
|
});
|
|
|
|
test("FORWARDABLE_CLIENT_BETAS must include thinking-display-updates beta", () => {
|
|
assert.ok(FORWARDABLE_CLIENT_BETAS.includes(DISPLAY_UPDATES));
|
|
});
|
|
|
|
// ── client-negotiated beta forwarding ───────────────────────────────────────
|
|
|
|
test("mergeClientAnthropicBeta must forward client-negotiated thinking-binding-controls beta", () => {
|
|
const out = mergeClientAnthropicBeta(
|
|
ANTHROPIC_BETA_API_KEY,
|
|
`claude-code-20250219,${BINDING_CONTROLS}`
|
|
);
|
|
const tokens = out.split(",").map((s) => s.trim());
|
|
assert.ok(tokens.includes(BINDING_CONTROLS), `client beta dropped: ${out}`);
|
|
});
|
|
|
|
test("mergeClientAnthropicBeta must forward client-negotiated thinking-display-updates beta", () => {
|
|
const out = mergeClientAnthropicBeta(
|
|
ANTHROPIC_BETA_API_KEY,
|
|
`claude-code-20250219,${DISPLAY_UPDATES}`
|
|
);
|
|
const tokens = out.split(",").map((s) => s.trim());
|
|
assert.ok(tokens.includes(DISPLAY_UPDATES), `client beta dropped: ${out}`);
|
|
});
|
|
|
|
test("mergeClientAnthropicBeta forwards both betas together without duplication", () => {
|
|
const out = mergeClientAnthropicBeta(
|
|
`${ANTHROPIC_BETA_API_KEY},${BINDING_CONTROLS}`,
|
|
`claude-code-20250219,${BINDING_CONTROLS},${DISPLAY_UPDATES}`
|
|
);
|
|
const tokens = out.split(",").map((s) => s.trim());
|
|
assert.ok(tokens.includes(BINDING_CONTROLS), `binding-controls missing: ${out}`);
|
|
assert.ok(tokens.includes(DISPLAY_UPDATES), `display-updates missing: ${out}`);
|
|
assert.equal(
|
|
tokens.filter((t) => t.toLowerCase() === BINDING_CONTROLS).length,
|
|
1,
|
|
`binding-controls duplicated: ${out}`
|
|
);
|
|
});
|
|
|
|
// ── guard: allowlist still closed ───────────────────────────────────────────
|
|
|
|
test("mergeClientAnthropicBeta still ignores non-allowlisted client betas", () => {
|
|
const out = mergeClientAnthropicBeta(
|
|
ANTHROPIC_BETA_API_KEY,
|
|
"some-random-future-beta-2099-01-01"
|
|
);
|
|
assert.ok(!out.includes("some-random-future-beta"), `unknown beta leaked: ${out}`);
|
|
});
|