[PR #6173] fix: handle non-text response parts in GitHub action #11761

Closed
opened 2026-02-16 18:16:42 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/6173

State: closed
Merged: Yes


This PR fixes the Failed to parse the text response error in opencode github run when the LLM responds with only tool calls or reasoning parts (no text). This is rare (about ~5/100 runs?) but frustrating as the entire invocation is discarded.

The new extractResponseText() function handles response parts with fallback logic:

  1. Text parts - returns text directly (existing behavior)
  2. Reasoning parts - returns reasoning with [Reasoning] prefix (for thinking models like o1, Claude extended thinking)
  3. Tool-only responses - returns a summary of completed tool calls with their titles

specifically:

  • Tool-heavy responses (e.g., todowrite only) caused findLast to return undefined, throwing an error
  • Thinking models may produce only reasoning parts with no text output
  • The error message now includes part types for debugging: Part types found: [tool, step-start]

repro

This is easy to repro directly by just prompting opencode via the GitHub Action:

/bonk lets reproduce this: put a todo list together based on our plan here. Provide NO other output of any kind. No text. ONLY use the todo tool.

before (fails):

Sending message to opencode...
|  Todo     {"todos":[{"id":"1","content":"Fork/clone sst/opencode repository","status":"pending","priority":"high"},{"id":"2","content":"Navigate to packages/opencode/src/cli/cmd/github.ts and locate lines 858-869","status":"pending","priority":"high"},{"id":"3","content":"Implement Priority 1: Add fallback to reasoning parts for thinking models","status":"pending","priority":"high"},{"id":"4","content":"Implement Priority 2: Handle tool-only responses with graceful summary","status":"pending","priority":"high"},{"id":"5","content":"Implement Priority 3: Improve error message with part types for debugging","status":"pending","priority":"high"},{"id":"6","content":"Handle edge cases: empty parts array, aborted requests, step-start only states","status":"pending","priority":"medium"},{"id":"7","content":"Test the fix with tool-heavy responses and reasoning-only models","status":"pending","priority":"medium"},{"id":"8","content":"Submit PR to sst/opencode with the comprehensive fix","status":"pending","priority":"high"}]}

855 |             `${result.info.error.name}: ${"message" in result.info.error ? result.info.error.message : ""}`,
856 |           )
857 |         }
858 | 
859 |         const match = result.parts.findLast((p) => p.type === "text")
860 |         if (!match) throw new Error("Failed to parse the text response")
                                ^
error: Failed to parse the text response
      at chat (src/cli/cmd/github.ts:860:27)

or:

|  Todo     {"todos":[{"id":"1","content":"Analyze OpenCode github.ts response parsing issue","status":"completed","priority":"high"},{"id":"2","content":"Document reproduction case: reasoning-only or tool-only responses fail","status":"completed","priority":"high"},{"id":"3","content":"Propose fix: add fallbacks for reasoning parts, tool-only responses, and better error messages","status":"completed","priority":"high"}]}
855 |             `${result.info.error.name}: ${"message" in result.info.error ? result.info.error.message : ""}`,
856 |           )
Creating comment...
857 |         }
858 | 
859 |         const match = result.parts.findLast((p) => p.type === "text")
860 |         if (!match) throw new Error("Failed to parse the text response")
                                ^
error: Failed to parse the text response
      at chat (src/cli/cmd/github.ts:860:27)

after (succeeds):

Completed 1 tool call(s):
- todowrite: 8 todos

tests:

  • extractResponseText tested for text parts, reasoning fallback, tool-only responses
  • Tests verify the original bug scenario (tool-only with no text) no longer throws
  • Edge cases: empty parts, running tools (ignored), mixed part types

related:

  • #2240 - Same Failed to parse the text response error (closed but not fully addressed)
  • #4234 - Fixed related race condition in storage.ts (different root cause)
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/6173 **State:** closed **Merged:** Yes --- This PR fixes the `Failed to parse the text response` error in `opencode github run` when the LLM responds with only tool calls or reasoning parts (no text). This is rare (about ~5/100 runs?) but frustrating as the entire invocation is discarded. The new `extractResponseText()` function handles response parts with fallback logic: 1. **Text parts** - returns text directly (existing behavior) 2. **Reasoning parts** - returns reasoning with `[Reasoning]` prefix (for thinking models like o1, Claude extended thinking) 3. **Tool-only responses** - returns a summary of completed tool calls with their titles specifically: - Tool-heavy responses (e.g., `todowrite` only) caused `findLast` to return `undefined`, throwing an error - Thinking models may produce only reasoning parts with no text output - The error message now includes part types for debugging: `Part types found: [tool, step-start]` #### repro This is easy to repro directly by just prompting opencode via the GitHub Action: ``` /bonk lets reproduce this: put a todo list together based on our plan here. Provide NO other output of any kind. No text. ONLY use the todo tool. ``` before (fails): ``` Sending message to opencode... | Todo {"todos":[{"id":"1","content":"Fork/clone sst/opencode repository","status":"pending","priority":"high"},{"id":"2","content":"Navigate to packages/opencode/src/cli/cmd/github.ts and locate lines 858-869","status":"pending","priority":"high"},{"id":"3","content":"Implement Priority 1: Add fallback to reasoning parts for thinking models","status":"pending","priority":"high"},{"id":"4","content":"Implement Priority 2: Handle tool-only responses with graceful summary","status":"pending","priority":"high"},{"id":"5","content":"Implement Priority 3: Improve error message with part types for debugging","status":"pending","priority":"high"},{"id":"6","content":"Handle edge cases: empty parts array, aborted requests, step-start only states","status":"pending","priority":"medium"},{"id":"7","content":"Test the fix with tool-heavy responses and reasoning-only models","status":"pending","priority":"medium"},{"id":"8","content":"Submit PR to sst/opencode with the comprehensive fix","status":"pending","priority":"high"}]} 855 | `${result.info.error.name}: ${"message" in result.info.error ? result.info.error.message : ""}`, 856 | ) 857 | } 858 | 859 | const match = result.parts.findLast((p) => p.type === "text") 860 | if (!match) throw new Error("Failed to parse the text response") ^ error: Failed to parse the text response at chat (src/cli/cmd/github.ts:860:27) ``` or: ``` | Todo {"todos":[{"id":"1","content":"Analyze OpenCode github.ts response parsing issue","status":"completed","priority":"high"},{"id":"2","content":"Document reproduction case: reasoning-only or tool-only responses fail","status":"completed","priority":"high"},{"id":"3","content":"Propose fix: add fallbacks for reasoning parts, tool-only responses, and better error messages","status":"completed","priority":"high"}]} 855 | `${result.info.error.name}: ${"message" in result.info.error ? result.info.error.message : ""}`, 856 | ) Creating comment... 857 | } 858 | 859 | const match = result.parts.findLast((p) => p.type === "text") 860 | if (!match) throw new Error("Failed to parse the text response") ^ error: Failed to parse the text response at chat (src/cli/cmd/github.ts:860:27) ``` after (succeeds): ``` Completed 1 tool call(s): - todowrite: 8 todos ``` #### tests: - `extractResponseText` tested for text parts, reasoning fallback, tool-only responses - Tests verify the original bug scenario (tool-only with no text) no longer throws - Edge cases: empty parts, running tools (ignored), mixed part types #### related: - #2240 - Same `Failed to parse the text response` error (closed but not fully addressed) - #4234 - Fixed related race condition in `storage.ts` (different root cause)
yindo added the pull-request label 2026-02-16 18:16:42 -05:00
yindo closed this issue 2026-02-16 18:16:42 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#11761