From 709c195905c260299facd5b566d9ab537c48c3bc Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Wed, 5 Aug 2026 15:14:03 -0500 Subject: [PATCH] fix(opencode): preserve compatible stream errors (#40718) --- bun.lock | 1 + package.json | 3 +- .../test/session/processor-effect.test.ts | 49 +++++++++++++++++++ .../@ai-sdk%2Fopenai-compatible@2.0.41.patch | 39 +++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch diff --git a/bun.lock b/bun.lock index 0d08cb8a95a..3ba15ef800b 100644 --- a/bun.lock +++ b/bun.lock @@ -1078,6 +1078,7 @@ "@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch", "pacote@21.5.0": "patches/pacote@21.5.0.patch", "@dnd-kit/dom@0.5.0": "patches/@dnd-kit%2Fdom@0.5.0.patch", + "@ai-sdk/openai-compatible@2.0.41": "patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch", }, "overrides": { "@opentui/core": "catalog:", diff --git a/package.json b/package.json index 15725c865fc..58712547b4b 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ "@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch", "@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch", "effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch", - "@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch" + "@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch", + "@ai-sdk/openai-compatible@2.0.41": "patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch" } } diff --git a/packages/opencode/test/session/processor-effect.test.ts b/packages/opencode/test/session/processor-effect.test.ts index 52876054365..d9466c0c2c9 100644 --- a/packages/opencode/test/session/processor-effect.test.ts +++ b/packages/opencode/test/session/processor-effect.test.ts @@ -604,6 +604,55 @@ it.live("session.processor effect tests retry recognized structured json errors" ), ) +it.live("session.processor effect tests retry OpenAI-compatible midstream server errors", () => + provideTmpdirServer( + ({ dir, llm }) => + Effect.gen(function* () { + const { processors, session, provider } = yield* boot() + + yield* llm.push( + raw({ chunks: [{ error: { type: "server_error", code: "server_error", message: "xxx" } }] }), + ) + yield* llm.text("after") + + const chat = yield* session.create({}) + const parent = yield* user(chat.id, "retry midstream server error") + const msg = yield* assistant(chat.id, parent.id, path.resolve(dir)) + const mdl = yield* provider.getModel(ref.providerID, ref.modelID) + const handle = yield* processors.create({ + assistantMessage: msg, + sessionID: chat.id, + model: mdl, + }) + + const value = yield* handle.process({ + user: { + id: parent.id, + sessionID: chat.id, + role: "user", + time: parent.time, + agent: parent.agent, + model: { providerID: ref.providerID, modelID: ref.modelID }, + } satisfies SessionV1.User, + sessionID: chat.id, + model: mdl, + agent: agent(), + system: [], + messages: [{ role: "user", content: "retry midstream server error" }], + tools: {}, + }) + + const parts = yield* MessageV2.parts(msg.id) + + expect(value).toBe("continue") + expect(yield* llm.calls).toBe(2) + expect(parts.some((part) => part.type === "text" && part.text === "after")).toBe(true) + expect(handle.message.error).toBeUndefined() + }), + { config: (url) => providerCfg(url) }, + ), +) + it.live("session.processor effect tests publish retry status updates", () => provideTmpdirServer( ({ dir, llm }) => diff --git a/patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch b/patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch new file mode 100644 index 00000000000..9f03ec95732 --- /dev/null +++ b/patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch @@ -0,0 +1,39 @@ +diff --git a/dist/index.js b/dist/index.js +index dca128d3a790378c51a24a16d92585178343b278..da75f9d64acd2b607abd15079ce2d03b7a8d675a 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -696,7 +696,7 @@ var OpenAICompatibleChatLanguageModel = class { + finishReason = { unified: "error", raw: void 0 }; + controller.enqueue({ + type: "error", +- error: chunk.value.error.message ++ error: chunk.value.error + }); + return; + } +diff --git a/dist/index.mjs b/dist/index.mjs +index 3b1e1b6bdec5032e3b4fa5ffbcc8cdf3dfe1cc40..eaffc446f80552ea0b26573b89daa4dfc7776e6e 100644 +--- a/dist/index.mjs ++++ b/dist/index.mjs +@@ -683,7 +683,7 @@ var OpenAICompatibleChatLanguageModel = class { + finishReason = { unified: "error", raw: void 0 }; + controller.enqueue({ + type: "error", +- error: chunk.value.error.message ++ error: chunk.value.error + }); + return; + } +diff --git a/src/chat/openai-compatible-chat-language-model.ts b/src/chat/openai-compatible-chat-language-model.ts +index 8c622db23c2d9a7373701f5a1b0c2ba109e24602..643c3db68a6043e097edc1122e0eb53fd13495c5 100644 +--- a/src/chat/openai-compatible-chat-language-model.ts ++++ b/src/chat/openai-compatible-chat-language-model.ts +@@ -442,7 +442,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 { + finishReason = { unified: 'error', raw: undefined }; + controller.enqueue({ + type: 'error', +- error: chunk.value.error.message, ++ error: chunk.value.error, + }); + return; + }