Compaction User Prefix
opencode plugin that prepends a synthetic user message when a compacted conversation would otherwise start with an assistant tool-call, avoiding the Anthropic `tool_use` without `tool_result` error.
0
22
8 in 7 days
21.2
Multi-signal model
4 months ago
2026-05-23
Install and configure
opencode.jsonWrites to this project's opencode.json — applies to this repository only.
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-compaction-user-prefix@0.1.0"]
}Writes to ~/.config/opencode/opencode.json — applies to every project.
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-compaction-user-prefix@0.1.0"]
}If you want to modify the plugin locally, install it into the project and reference the local path.
shell
pnpm add -D opencode-compaction-user-prefixOpenCode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.
An opencode plugin that works around a compaction bug where a freshly compacted conversation can start with an assistant tool-call message, causing Anthropic to reject the request with:
messages.N: `tool_use` ids were found without `tool_result` blocks immediately after.
The plugin prepends a synthetic user text message at the experimental.chat.messages.transform boundary so the body sent to the model always begins with a user turn.
The bug
When manual or auto compaction runs after a previous compaction whose tail_start_id landed mid-turn on an assistant tool-call, compaction.process builds selected.head as a chain of consecutive assistant tool-call messages with no user message at the start.
MessageV2.toModelMessagesEffect then faithfully converts that to a model message array whose first entry is assistant tool_use, which Anthropic rejects.
Upstream reference: opencode session message msg_e5550bcfb001EjDfz6hFE3lpHB (compaction failure on session ses_1ae999d1dffeOLwEseaIFPDg0V).
How it works
The plugin hooks experimental.chat.messages.transform, which receives the same WithParts[] opencode is about to pass into toModelMessages. If the first message is an assistant, it prepends a synthetic user text part. opencode recognises text parts in user messages, so the prepended turn survives the conversion and the resulting request body starts with a user message.
This is safe on the normal chat path because real chat already begins with a user message, in which case the !== "assistant" check short-circuits and nothing is prepended.
Use
Register the plugin in your opencode config (opencode.json or ~/.config/opencode/opencode.json):
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-compaction-user-prefix"]
}
License
MIT © Quentin Nivelais
Similar plugins
Compaction Guard
opencode-compaction-guard
OpenCode plugin that prevents and auto-recovers from the 'tool_use ids were found without tool_result blocks' error that makes sessions unrecoverable after auto-compaction or interrupted tool calls.
With Claude
opencode-with-claude
OpenCode plugin to use your Claude Max subscription via Meridian proxy
With Claude
@suiramdev/opencode-with-claude
OpenCode v2 plugin to use your Claude Max/Pro subscription via the Meridian proxy