fix(ai): own Anthropic SSE parsing to avoid SDK JSON.parse hard-failures
Bypass the Anthropic SDK streaming parser entirely. Use client.messages.create().asResponse() and decode the SSE stream ourselves with defensive JSON parsing that repairs invalid escape sequences and control characters inside string literals. - Switch from SDK .stream() to .asResponse() + pi-owned SSE decoder - Add repairJson() / parseJsonWithRepair() to json-parse.ts - Add anthropic-sse-parsing.test.ts regression for malformed tool deltas - Update github-copilot-anthropic.test.ts mock to match new call path - Update deprecated claude-3-5-haiku-20241022 refs to claude-haiku-4-5 - Remove stale non-reasoning model test fixes #3175
This commit is contained in:
@@ -27,7 +27,7 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => {
|
||||
it.skipIf(!process.env.ANTHROPIC_API_KEY)(
|
||||
"should use default cache TTL (no ttl field) when PI_CACHE_RETENTION is not set",
|
||||
async () => {
|
||||
const model = getModel("anthropic", "claude-3-5-haiku-20241022");
|
||||
const model = getModel("anthropic", "claude-haiku-4-5");
|
||||
let capturedPayload: any = null;
|
||||
|
||||
const s = stream(model, context, {
|
||||
@@ -50,7 +50,7 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => {
|
||||
|
||||
it.skipIf(!process.env.ANTHROPIC_API_KEY)("should use 1h cache TTL when PI_CACHE_RETENTION=long", async () => {
|
||||
process.env.PI_CACHE_RETENTION = "long";
|
||||
const model = getModel("anthropic", "claude-3-5-haiku-20241022");
|
||||
const model = getModel("anthropic", "claude-haiku-4-5");
|
||||
let capturedPayload: any = null;
|
||||
|
||||
const s = stream(model, context, {
|
||||
@@ -74,7 +74,7 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => {
|
||||
process.env.PI_CACHE_RETENTION = "long";
|
||||
|
||||
// Create a model with a different baseUrl (simulating a proxy)
|
||||
const baseModel = getModel("anthropic", "claude-3-5-haiku-20241022");
|
||||
const baseModel = getModel("anthropic", "claude-haiku-4-5");
|
||||
const proxyModel = {
|
||||
...baseModel,
|
||||
baseUrl: "https://my-proxy.example.com/v1",
|
||||
@@ -114,7 +114,7 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => {
|
||||
});
|
||||
|
||||
it("should omit cache_control when cacheRetention is none", async () => {
|
||||
const baseModel = getModel("anthropic", "claude-3-5-haiku-20241022");
|
||||
const baseModel = getModel("anthropic", "claude-haiku-4-5");
|
||||
let capturedPayload: any = null;
|
||||
|
||||
const { streamAnthropic } = await import("../src/providers/anthropic.js");
|
||||
@@ -140,7 +140,7 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => {
|
||||
});
|
||||
|
||||
it("should add cache_control to string user messages", async () => {
|
||||
const baseModel = getModel("anthropic", "claude-3-5-haiku-20241022");
|
||||
const baseModel = getModel("anthropic", "claude-haiku-4-5");
|
||||
let capturedPayload: any = null;
|
||||
|
||||
const { streamAnthropic } = await import("../src/providers/anthropic.js");
|
||||
@@ -168,7 +168,7 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => {
|
||||
});
|
||||
|
||||
it("should set 1h cache TTL when cacheRetention is long", async () => {
|
||||
const baseModel = getModel("anthropic", "claude-3-5-haiku-20241022");
|
||||
const baseModel = getModel("anthropic", "claude-haiku-4-5");
|
||||
let capturedPayload: any = null;
|
||||
|
||||
const { streamAnthropic } = await import("../src/providers/anthropic.js");
|
||||
|
||||
Reference in New Issue
Block a user