Description
With github-copilot/claude-opus-4.8, OpenCode can persist pseudo tool-call text as normal assistant text instead of receiving a structured tool call.
The malformed assistant message can look structurally like this:
role = assistant
providerID = github-copilot
modelID = claude-opus-4.8
finish = tool-calls
- structured tool parts:
0
- assistant text contains pseudo tool-call markup such as
<invoke ...> or short call <tool> lines
This appears to be the root cause behind the assistant-prefill 400 tracked in #31807. After such a malformed finish=tool-calls turn, OpenCode continues the tool loop, but the conversation history effectively ends with an assistant message. Copilot Claude Opus 4.8 then rejects the follow-up request.
Steps to Reproduce
I do not yet have a small deterministic repro, but the issue occurred in real OpenCode TUI sessions with a tool-heavy workflow:
- Start an OpenCode TUI session with
github-copilot/claude-opus-4.8.
- Perform a long multi-step task with many tool calls (
read, write, edit, grep, bash, etc.).
- Continue the same session through many tool-call turns.
- Inspect local SQLite
message / part metadata.
- Observe assistant text parts containing pseudo tool-call text such as
<invoke ...> or call read, while the assistant message has finish=tool-calls but no structured tool part.
Expected Behavior
- If the model requests a tool, OpenCode should receive or recover a structured tool call.
- Pseudo tool-call text should not be persisted as normal assistant prose.
- A response with
finish=tool-calls should not leave OpenCode with zero actual tool parts and then continue the tool loop blindly.
Actual Behavior
In the affected session, Opus 4.8 produced malformed assistant turns where pseudo tool-call text was persisted as normal assistant text parts.
Same-session structural comparison:
| Model |
Assistant messages |
<invoke> text parts |
call ... text parts |
finish=tool-calls with 0 tool parts |
assistant-prefill API errors |
claude-opus-4.6 |
161 |
0 |
0 |
0 |
0 |
claude-opus-4.7 |
71 |
0 |
0 |
0 |
0 |
claude-opus-4.8 |
337 |
13 |
229 |
6 |
6 |
Representative malformed turn shape:
model: github-copilot/claude-opus-4.8
role: assistant
finish: tool-calls
structured tool parts: 0
assistant text contains: <invoke ...>
Every sampled assistant-prefill 400 in #31807 was immediately preceded by this malformed shape.
Additional Evidence
Sanitized DB-derived metadata only:
https://gist.github.com/doomsday616/d3fb56acd0f14964a9797df35f1fcd96
The gist contains only structural metadata from local SQLite message / part rows. Private message text, local paths, usernames, WeChat identifiers, and conversation content are not included.
OpenCode Version
Operating System
Terminal
Windows Terminal / PowerShell 7
Provider / Model
github-copilot / claude-opus-4.8
I tested the same affected session metadata against other Copilot Claude models. In that session, claude-opus-4.6 and claude-opus-4.7 did not show the same malformed pseudo tool-call pattern.
Related Issues
Sanitization
The original full session contains private content. The linked gist only includes sanitized structural metadata needed for debugging.
Description
With
github-copilot/claude-opus-4.8, OpenCode can persist pseudo tool-call text as normal assistant text instead of receiving a structured tool call.The malformed assistant message can look structurally like this:
role = assistantproviderID = github-copilotmodelID = claude-opus-4.8finish = tool-calls0<invoke ...>or shortcall <tool>linesThis appears to be the root cause behind the assistant-prefill 400 tracked in #31807. After such a malformed
finish=tool-callsturn, OpenCode continues the tool loop, but the conversation history effectively ends with an assistant message. Copilot Claude Opus 4.8 then rejects the follow-up request.Steps to Reproduce
I do not yet have a small deterministic repro, but the issue occurred in real OpenCode TUI sessions with a tool-heavy workflow:
github-copilot/claude-opus-4.8.read,write,edit,grep,bash, etc.).message/partmetadata.<invoke ...>orcall read, while the assistant message hasfinish=tool-callsbut no structured tool part.Expected Behavior
finish=tool-callsshould not leave OpenCode with zero actual tool parts and then continue the tool loop blindly.Actual Behavior
In the affected session, Opus 4.8 produced malformed assistant turns where pseudo tool-call text was persisted as normal assistant
textparts.Same-session structural comparison:
<invoke>text partscall ...text partsfinish=tool-callswith 0 tool partsclaude-opus-4.6claude-opus-4.7claude-opus-4.8Representative malformed turn shape:
Every sampled assistant-prefill 400 in #31807 was immediately preceded by this malformed shape.
Additional Evidence
Sanitized DB-derived metadata only:
https://gist.github.com/doomsday616/d3fb56acd0f14964a9797df35f1fcd96
The gist contains only structural metadata from local SQLite
message/partrows. Private message text, local paths, usernames, WeChat identifiers, and conversation content are not included.OpenCode Version
Operating System
Terminal
Provider / Model
I tested the same affected session metadata against other Copilot Claude models. In that session,
claude-opus-4.6andclaude-opus-4.7did not show the same malformed pseudo tool-call pattern.Related Issues
Sanitization
The original full session contains private content. The linked gist only includes sanitized structural metadata needed for debugging.