GH#17790: fix(opencode-plugin) strip trailing assistant messages to prevent Claude 4.x prefill error#17791
Conversation
…aude 4.x prefill error (GH#17790) Adds prefill-guard.mjs to opencode-aidevops plugin and composes it into the experimental.chat.messages.transform hook after the existing TTSR hook. The guard strips trailing assistant messages from the outgoing LLM payload when safe — preserving messages with finish=tool-calls or active tool parts so legitimate tool-call flows are untouched. Session DB is never modified. Fixes the mobile webui error 'This model does not support assistant message prefill' on Claude Opus/Sonnet 4.x. Mirrors upstream PRs anomalyco/opencode#14772, marcusquinn#16921, and #18091 which add the same logic in provider/transform.ts but are not yet merged in opencode v1.3.17 / v1.4.0. Fixes marcusquinn#17790
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Maintainer Gate: BLOCKED This PR cannot be merged because: Issue #17790 has
This is an automated check. See issue-triage-gate.yml for the triage policy. |
WalkthroughThis adds a defensive prefill guard to the opencode-aidevops plugin that strips trailing assistant messages from chat conversations before they reach Claude 4.x models, preventing Anthropic's prefill validation errors while preserving legitimate tool-call flows. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Up to standards ✅🟢 Issues
|
| Category | Results |
|---|---|
| Complexity | 2 medium |
🟢 Metrics 33 complexity
Metric Results Complexity 33
TIP This summary will be updated as you push new changes. Give us feedback
Add _check_linked_issue_gate() to full-loop-helper.sh cmd_start that mirrors the CI maintainer-gate.yml check-pr job logic. Workers now fail fast locally before creating PRs that will always fail the CI gate. - Extracts issue number from prompt (#NNN pattern) - Checks needs-maintainer-review label → blocks with clear message - Checks no assignee (exempt: quality-debt issues per GH#6623) → blocks - Skips gracefully for closed issues, missing issue numbers, API errors - Documents the check in full-loop.md as a mandatory pre-start step Root cause: PR #17791 was created for issue #17790 (CONTRIBUTOR-authored, needs-maintainer-review applied by triage gate) before the issue was approved. The CI gate correctly blocked the PR. This fix prevents workers from starting work on unapproved external issues. Fixes #17810
#17812) Add _check_linked_issue_gate() to full-loop-helper.sh cmd_start that mirrors the CI maintainer-gate.yml check-pr job logic. Workers now fail fast locally before creating PRs that will always fail the CI gate. - Extracts issue number from prompt (#NNN pattern) - Checks needs-maintainer-review label → blocks with clear message - Checks no assignee (exempt: quality-debt issues per GH#6623) → blocks - Skips gracefully for closed issues, missing issue numbers, API errors - Documents the check in full-loop.md as a mandatory pre-start step Root cause: PR #17791 was created for issue #17790 (CONTRIBUTOR-authored, needs-maintainer-review applied by triage gate) before the issue was approved. The CI gate correctly blocked the PR. This fix prevents workers from starting work on unapproved external issues. Fixes #17810
Summary
Adds a defensive plugin-level guard that strips trailing assistant messages from the outgoing LLM payload, preventing the "This model does not support assistant message prefill" error on Claude Opus/Sonnet 4.x — most often hit on the mobile webui.
Why
Claude Opus/Sonnet 4.x (Anthropic native, GitHub Copilot, OpenRouter, Bedrock, Vertex) reject any conversation that ends with an assistant message:
opencode v1.3.17 / v1.4.0 has a partial gate at
session/prompt.ts(lastAssistant2?.finish && !["tool-calls"].includes(...)) that handles the most common continuation case, but it fails open whenfinishisundefined— which is exactly the state left by aborted/interrupted previous turns. Mobile users hit this constantly because flaky connections cause aborts.Three upstream PRs (sst/opencode#14772, #16921, #18091) all fix this in
provider/transform.tsby addingstripTrailingAssistant(). None are merged.What
.agents/plugins/opencode-aidevops/prefill-guard.mjs— pure module exportingcreatePrefillGuardHook(deps). Strips trailing assistant messages fromoutput.messagesonly when safe:finish === "tool-calls"pending/running/completed)error/abortedstate, or that have no tool parts.agents/plugins/opencode-aidevops/index.mjs— imports the guard and composes it into theexperimental.chat.messages.transformhook after the existingmessagesTransformHookso TTSR's rule scanning still sees all assistants before they're stripped.Safety properties
qualityLog. A bug here cannot break the hook chain.Verification
The fix has been deployed and verified locally — opencode-web restarted cleanly, plugin loaded without errors, and the mobile webui has been working since.
Related upstream
finish=stop, triggering prefill error on claude-opus-4-6 anomalyco/opencode#17982 — continuation loop root cause analysisThis plugin-level guard is a workaround until one of those upstream PRs lands. When they do, this guard becomes a no-op (the upstream strip will happen first) and can optionally be removed.
Resolves #17790
aidevops.sh v3.6.162 plugin for OpenCode v1.3.17 with claude-opus-4-6 spent 1h 12m and 52,593 tokens on this with the user in an interactive session.
Summary by CodeRabbit