test: dedupe anthropic transport fixtures

This commit is contained in:
Peter Steinberger
2026-04-18 22:08:16 +01:00
parent e069169765
commit b4543caf55

View File

@@ -13,6 +13,12 @@ vi.mock("./provider-transport-fetch.js", () => ({
let createAnthropicMessagesTransportStreamFn: typeof import("./anthropic-transport-stream.js").createAnthropicMessagesTransportStreamFn;
type AnthropicMessagesModel = Model<"anthropic-messages">;
type AnthropicStreamFn = ReturnType<typeof createAnthropicMessagesTransportStreamFn>;
type AnthropicStreamContext = Parameters<AnthropicStreamFn>[1];
type AnthropicStreamOptions = Parameters<AnthropicStreamFn>[2];
type RequestTransportConfig = Parameters<typeof attachModelProviderRequestTransport>[1];
function createSseResponse(events: Record<string, unknown>[] = []): Response {
const body = events.map((event) => `data: ${JSON.stringify(event)}\n\n`).join("");
return new Response(body, {
@@ -30,6 +36,48 @@ function latestAnthropicRequest() {
};
}
function makeAnthropicTransportModel(
params: {
id?: string;
name?: string;
reasoning?: boolean;
maxTokens?: number;
headers?: Record<string, string>;
requestTransport?: RequestTransportConfig;
} = {},
): AnthropicMessagesModel {
return attachModelProviderRequestTransport(
{
id: params.id ?? "claude-sonnet-4-6",
name: params.name ?? "Claude Sonnet 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: params.reasoning ?? true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: params.maxTokens ?? 8192,
...(params.headers ? { headers: params.headers } : {}),
} satisfies AnthropicMessagesModel,
params.requestTransport ?? {
proxy: {
mode: "env-proxy",
},
},
);
}
async function runTransportStream(
model: AnthropicMessagesModel,
context: AnthropicStreamContext,
options: AnthropicStreamOptions,
) {
const streamFn = createAnthropicMessagesTransportStreamFn();
const stream = await Promise.resolve(streamFn(model, context, options));
return stream.result();
}
describe("anthropic transport stream", () => {
beforeAll(async () => {
({ createAnthropicMessagesTransportStreamFn } =
@@ -44,42 +92,26 @@ describe("anthropic transport stream", () => {
});
it("uses the guarded fetch transport for api-key Anthropic requests", async () => {
const model = attachModelProviderRequestTransport(
{
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
headers: { "X-Provider": "anthropic" },
} satisfies Model<"anthropic-messages">,
{
const model = makeAnthropicTransportModel({
headers: { "X-Provider": "anthropic" },
requestTransport: {
proxy: {
mode: "explicit-proxy",
url: "http://proxy.internal:8443",
},
},
);
const streamFn = createAnthropicMessagesTransportStreamFn();
});
const stream = await Promise.resolve(
streamFn(
model,
{
messages: [{ role: "user", content: "hello" }],
} as Parameters<typeof streamFn>[1],
{
apiKey: "sk-ant-api",
headers: { "X-Call": "1" },
} as Parameters<typeof streamFn>[2],
),
await runTransportStream(
model,
{
messages: [{ role: "user", content: "hello" }],
} as AnthropicStreamContext,
{
apiKey: "sk-ant-api",
headers: { "X-Call": "1" },
} as AnthropicStreamOptions,
);
await stream.result();
expect(buildGuardedModelFetchMock).toHaveBeenCalledWith(model);
expect(guardedFetchMock).toHaveBeenCalledWith(
@@ -104,40 +136,16 @@ describe("anthropic transport stream", () => {
});
it("ignores non-positive runtime maxTokens overrides and falls back to the model limit", async () => {
const model = attachModelProviderRequestTransport(
await runTransportStream(
makeAnthropicTransportModel(),
{
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
} satisfies Model<"anthropic-messages">,
messages: [{ role: "user", content: "hello" }],
} as AnthropicStreamContext,
{
proxy: {
mode: "env-proxy",
},
},
apiKey: "sk-ant-api",
maxTokens: 0,
} as AnthropicStreamOptions,
);
const streamFn = createAnthropicMessagesTransportStreamFn();
const stream = await Promise.resolve(
streamFn(
model,
{
messages: [{ role: "user", content: "hello" }],
} as Parameters<typeof streamFn>[1],
{
apiKey: "sk-ant-api",
maxTokens: 0,
} as Parameters<typeof streamFn>[2],
),
);
await stream.result();
expect(latestAnthropicRequest().payload).toMatchObject({
model: "claude-sonnet-4-6",
@@ -147,40 +155,16 @@ describe("anthropic transport stream", () => {
});
it("ignores fractional runtime maxTokens overrides that floor to zero", async () => {
const model = attachModelProviderRequestTransport(
await runTransportStream(
makeAnthropicTransportModel(),
{
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
} satisfies Model<"anthropic-messages">,
messages: [{ role: "user", content: "hello" }],
} as AnthropicStreamContext,
{
proxy: {
mode: "env-proxy",
},
},
apiKey: "sk-ant-api",
maxTokens: 0.5,
} as AnthropicStreamOptions,
);
const streamFn = createAnthropicMessagesTransportStreamFn();
const stream = await Promise.resolve(
streamFn(
model,
{
messages: [{ role: "user", content: "hello" }],
} as Parameters<typeof streamFn>[1],
{
apiKey: "sk-ant-api",
maxTokens: 0.5,
} as Parameters<typeof streamFn>[2],
),
);
await stream.result();
expect(latestAnthropicRequest().payload).toMatchObject({
model: "claude-sonnet-4-6",
@@ -260,25 +244,13 @@ describe("anthropic transport stream", () => {
},
]),
);
const model = attachModelProviderRequestTransport(
{
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
} satisfies Model<"anthropic-messages">,
{
const model = makeAnthropicTransportModel({
requestTransport: {
tls: {
ca: "ca-pem",
},
},
);
});
const streamFn = createAnthropicMessagesTransportStreamFn();
const stream = await Promise.resolve(
streamFn(
@@ -338,25 +310,13 @@ describe("anthropic transport stream", () => {
});
it("coerces replayed malformed tool-call args to an object for Anthropic payloads", async () => {
const model = attachModelProviderRequestTransport(
{
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
} satisfies Model<"anthropic-messages">,
{
const model = makeAnthropicTransportModel({
requestTransport: {
tls: {
ca: "ca-pem",
},
},
);
});
const streamFn = createAnthropicMessagesTransportStreamFn();
const stream = await Promise.resolve(
@@ -407,40 +367,22 @@ describe("anthropic transport stream", () => {
});
it("maps adaptive thinking effort for Claude 4.6 transport runs", async () => {
const model = attachModelProviderRequestTransport(
{
id: "claude-opus-4-6",
name: "Claude Opus 4.6",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
} satisfies Model<"anthropic-messages">,
{
proxy: {
mode: "env-proxy",
},
},
);
const streamFn = createAnthropicMessagesTransportStreamFn();
const model = makeAnthropicTransportModel({
id: "claude-opus-4-6",
name: "Claude Opus 4.6",
maxTokens: 8192,
});
const stream = await Promise.resolve(
streamFn(
model,
{
messages: [{ role: "user", content: "Think deeply." }],
} as Parameters<typeof streamFn>[1],
{
apiKey: "sk-ant-api",
reasoning: "xhigh",
} as Parameters<typeof streamFn>[2],
),
await runTransportStream(
model,
{
messages: [{ role: "user", content: "Think deeply." }],
} as AnthropicStreamContext,
{
apiKey: "sk-ant-api",
reasoning: "xhigh",
} as AnthropicStreamOptions,
);
await stream.result();
expect(latestAnthropicRequest().payload).toMatchObject({
thinking: { type: "adaptive" },
@@ -449,40 +391,22 @@ describe("anthropic transport stream", () => {
});
it("maps xhigh thinking effort for Claude Opus 4.7 transport runs", async () => {
const model = attachModelProviderRequestTransport(
{
id: "claude-opus-4-7",
name: "Claude Opus 4.7",
api: "anthropic-messages",
provider: "anthropic",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 8192,
} satisfies Model<"anthropic-messages">,
{
proxy: {
mode: "env-proxy",
},
},
);
const streamFn = createAnthropicMessagesTransportStreamFn();
const model = makeAnthropicTransportModel({
id: "claude-opus-4-7",
name: "Claude Opus 4.7",
maxTokens: 8192,
});
const stream = await Promise.resolve(
streamFn(
model,
{
messages: [{ role: "user", content: "Think extra hard." }],
} as Parameters<typeof streamFn>[1],
{
apiKey: "sk-ant-api",
reasoning: "xhigh",
} as Parameters<typeof streamFn>[2],
),
await runTransportStream(
model,
{
messages: [{ role: "user", content: "Think extra hard." }],
} as AnthropicStreamContext,
{
apiKey: "sk-ant-api",
reasoning: "xhigh",
} as AnthropicStreamOptions,
);
await stream.result();
expect(latestAnthropicRequest().payload).toMatchObject({
thinking: { type: "adaptive" },