From 0de9bd6b671d5a98d3710bb340eb9bbb4d5756cf Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Wed, 11 Nov 2026 10:11:37 -0400 Subject: [PATCH 1/2] fix(aiclient): propagate messages streaming provider errors --- .../src/wireApiProvider/messages.types.ts | 9 ++++++ .../messagesWireApiProvider.ts | 5 ++++ .../aiclient/test/providerAdapter.spec.ts | 30 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/ts/packages/aiclient/src/wireApiProvider/messages.types.ts b/ts/packages/aiclient/src/wireApiProvider/messages.types.ts index 02c294ee70..16db7f84d8 100644 --- a/ts/packages/aiclient/src/wireApiProvider/messages.types.ts +++ b/ts/packages/aiclient/src/wireApiProvider/messages.types.ts @@ -198,7 +198,16 @@ export interface RawContentBlockStopEvent { type: "content_block_stop"; } +export interface RawMessageErrorEvent { + type: "error"; + error: { + type: string; + message: string; + }; +} + export type RawMessageStreamEvent = + | RawMessageErrorEvent | RawMessageStartEvent | RawMessageDeltaEvent | RawMessageStopEvent diff --git a/ts/packages/aiclient/src/wireApiProvider/messagesWireApiProvider.ts b/ts/packages/aiclient/src/wireApiProvider/messagesWireApiProvider.ts index e0247298e1..11db3c5576 100644 --- a/ts/packages/aiclient/src/wireApiProvider/messagesWireApiProvider.ts +++ b/ts/packages/aiclient/src/wireApiProvider/messagesWireApiProvider.ts @@ -205,6 +205,11 @@ export class MessagesWireApiProvider implements ProviderAdapter { const evt = JSON.parse(raw) as RawMessageStreamEvent; const piece: StreamPiece = {}; + if (evt.type === "error") { + piece.error = new Error(evt.error.message); + return piece; + } + if ( evt.type === "content_block_delta" && evt.delta.type === "text_delta" diff --git a/ts/packages/aiclient/test/providerAdapter.spec.ts b/ts/packages/aiclient/test/providerAdapter.spec.ts index f22686cb5d..4111489e90 100644 --- a/ts/packages/aiclient/test/providerAdapter.spec.ts +++ b/ts/packages/aiclient/test/providerAdapter.spec.ts @@ -294,6 +294,36 @@ describe("ChatCompletionsWireApiProvider (default path is byte-identical)", () = describe("MessagesWireApiProvider", () => { const adapter = adapterFor("messages"); + test.each([false, true])( + "stream reports provider errors (partial text: %s)", + (partialText) => { + const decoder = adapter.createStreamDecoder!( + makeRequest({ stream: true }), + ); + if (partialText) { + expect( + decoder.push( + JSON.stringify({ + type: "content_block_delta", + index: 0, + delta: { type: "text_delta", text: "Partial answer" }, + }), + ).text, + ).toBe("Partial answer"); + } + const piece = decoder.push( + JSON.stringify({ + type: "error", + error: { type: "overloaded_error", message: "Overloaded" }, + }), + ); + expect(piece.error).toBeInstanceOf(Error); + expect(piece.error?.message).toBe("Overloaded"); + expect(piece.text).toBeUndefined(); + expect(piece.usage).toBeUndefined(); + }, + ); + test("buildRequestBody splits system prompt, requires max_tokens", () => { const req = makeRequest({ modelName: "claude-3-5-sonnet", From 8b5cb613cf6aa43d3c32d84efea58d67b9670347 Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Wed, 11 Nov 2026 10:16:57 -0400 Subject: [PATCH 2/2] style(aiclient): format streaming error regression test --- ts/packages/aiclient/test/providerAdapter.spec.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ts/packages/aiclient/test/providerAdapter.spec.ts b/ts/packages/aiclient/test/providerAdapter.spec.ts index 4111489e90..4afc132c89 100644 --- a/ts/packages/aiclient/test/providerAdapter.spec.ts +++ b/ts/packages/aiclient/test/providerAdapter.spec.ts @@ -306,7 +306,10 @@ describe("MessagesWireApiProvider", () => { JSON.stringify({ type: "content_block_delta", index: 0, - delta: { type: "text_delta", text: "Partial answer" }, + delta: { + type: "text_delta", + text: "Partial answer", + }, }), ).text, ).toBe("Partial answer");