Reapply "fix(ai): own Anthropic SSE parsing to avoid SDK JSON.parse hard-failures"

This reverts commit fc9220d2de.
This commit is contained in:
Mario Zechner
2026-04-21 23:42:19 +02:00
parent fc9220d2de
commit e58d631c89
12 changed files with 430 additions and 124 deletions

View File

@@ -4,37 +4,42 @@ import type { Context } from "../src/types.js";
const mockState = vi.hoisted(() => ({
constructorOpts: undefined as Record<string, unknown> | undefined,
streamParams: undefined as Record<string, unknown> | undefined,
createParams: undefined as Record<string, unknown> | undefined,
}));
vi.mock("@anthropic-ai/sdk", () => {
const fakeStream = {
async *[Symbol.asyncIterator]() {
yield {
function createSseResponse(): Response {
const body = [
`event: message_start\ndata: ${JSON.stringify({
type: "message_start",
message: {
id: "msg_test",
usage: { input_tokens: 10, output_tokens: 0 },
},
};
yield {
})}\n`,
`event: message_delta\ndata: ${JSON.stringify({
type: "message_delta",
delta: { stop_reason: "end_turn" },
usage: { output_tokens: 5 },
};
},
finalMessage: async () => ({
usage: { input_tokens: 10, output_tokens: 5, cache_creation_input_tokens: 0, cache_read_input_tokens: 0 },
}),
};
})}\n`,
].join("\n");
return new Response(body, {
status: 200,
headers: { "content-type": "text/event-stream" },
});
}
class FakeAnthropic {
constructor(opts: Record<string, unknown>) {
mockState.constructorOpts = opts;
}
messages = {
stream: (params: Record<string, unknown>) => {
mockState.streamParams = params;
return fakeStream;
create: (params: Record<string, unknown>) => {
mockState.createParams = params;
return {
asResponse: async () => createSseResponse(),
};
},
};
}
@@ -79,7 +84,7 @@ describe("Copilot Claude via Anthropic Messages", () => {
expect(beta).not.toContain("fine-grained-tool-streaming");
// Payload is valid Anthropic Messages format
const params = mockState.streamParams!;
const params = mockState.createParams!;
expect(params.model).toBe("claude-sonnet-4");
expect(params.stream).toBe(true);
expect(params.max_tokens).toBeGreaterThan(0);