From 8323e6218ce8756a7a22505f20835c7919285278 Mon Sep 17 00:00:00 2001 From: Xiaohan-Tian <157918347+Xiaohan-Tian@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:34:26 -0700 Subject: [PATCH] fix: use raw streaming chat completions and keep readable preview stacks Switch OpenAI-compatible streaming from chat.completions.stream() to chat.completions.create({ stream: true }) and track finish_reason from streamed chunks directly. This avoids the SDK's final chat-completion reconstruction path, which could throw in preview builds while processing agent streams. Also keep function/class names and sourcemaps in production builds to make preview stack traces easier to read. This issue can randomly happen when using `google/gemma-4-31b-it` model via OpenRouter. Original error stacktrace: ``` index-Bh7OJFcp.js:807 Error processing stream: kn: Cannot read properties of undefined (reading 'type') at Bb.qJ (index-Bh7OJFcp.js:780:4436)Caused by: TypeError: Cannot read properties of undefined (reading 'type') at _J (index-Bh7OJFcp.js:780:1713) at index-Bh7OJFcp.js:780:416 at Array.map () at R6e (index-Bh7OJFcp.js:780:408) at z6e (index-Bh7OJFcp.js:785:258) at Bb.By (index-Bh7OJFcp.js:781:4928) at Bb._createChatCompletion (index-Bh7OJFcp.js:781:1059) at async Bb._runChatCompletion (index-Bh7OJFcp.js:780:6759) ``` --- src/agent/llm/LLMProvider.ts | 10 ++++++---- vite.config.ts | 6 ++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/agent/llm/LLMProvider.ts b/src/agent/llm/LLMProvider.ts index bca9437..adb6c91 100644 --- a/src/agent/llm/LLMProvider.ts +++ b/src/agent/llm/LLMProvider.ts @@ -165,8 +165,9 @@ export class OpenAICompatibleLLMProvider implements LLMProvider { requestParams.tool_choice = 'auto'; } - const stream = this.client.chat.completions.stream(requestParams); + const stream = await this.client.chat.completions.create(requestParams); const toolCallAccumulator = new Map(); + let finishReason = 'stop'; for await (const chunk of stream) { // Do not delete: leave this commented out for future debugging purpose. @@ -174,6 +175,10 @@ export class OpenAICompatibleLLMProvider implements LLMProvider { const choice = chunk.choices[0]; if (!choice) continue; + if (choice.finish_reason) { + finishReason = choice.finish_reason; + } + const delta = choice.delta; if (delta.content) { yield { type: 'text', content: delta.content }; @@ -197,9 +202,6 @@ export class OpenAICompatibleLLMProvider implements LLMProvider { } } - const finalCompletion = await stream.finalChatCompletion(); - const finishReason = finalCompletion.choices[0]?.finish_reason ?? 'stop'; - if (toolCallAccumulator.size > 0) { for (const [, tc] of toolCallAccumulator) { const toolCall: ToolCall = { diff --git a/vite.config.ts b/vite.config.ts index 492a9cd..5802a65 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,6 +16,12 @@ export default defineConfig({ define: { __APP_VERSION__: JSON.stringify(version), }, + esbuild: { + keepNames: true, + }, + build: { + sourcemap: true, + }, server: { host: true, headers: {