You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
OpenCode 2: model-echoed §N§ tags are never stripped from saved assistant text #613
Magic Context: 0.44.4 installed; also checked at main0037574 (2026-10-03) OpenCode: 2.0.22 Found by: reading source. Not yet observed in a live session. Related to #582 (which covers the WebSocket cache side) and the closed, unmerged PR #593.
What happens
On OpenCode 1, MC strips §N§ tags the model echoes into its own text at the persistence boundary, via experimental.text.complete (index.ts:996, text-complete.ts). OpenCode 2 has no equivalent hook: its session hooks are prompt, context, compaction, generate, title, model.request, http.request, http.response, the experimental ws.* hooks and retry (packages/plugin/src/promise/session.ts), and there's no text.complete. The V2 entry registers nothing in its place, so echoed tags are saved in session_message and shown in the transcript.
Suggested fix
Strip echoed tags on OpenCode 2 through an available carrier (for example the http.response hook, or a post-step rewrite if the host exposes one). If no hook can do it, document the limitation.
Run an OpenCode 2 session with ctx_reduce available until the model echoes a §N§ tag in its reply. The stored assistant text in session_message still contains it, and the timeline shows it.
Thanks for tracing this. You're right about the cause. On OpenCode 1, Magic Context removes the tags a model writes into its reply before the text is saved, through the experimental.text.complete hook. OpenCode 2 has no hook that runs between the parsed reply and saving it, so there's currently no reliable way for a plugin to change the assistant text OpenCode 2 saves and shows. A plugin can rewrite the raw provider stream before parsing, but that depends on each provider's stream format and breaks when a tag is split across stream events. So for now the tag stays visible in the OpenCode 2 transcript; the model still sees its own text unchanged.
Not prefixing assistant text on OpenCode 2 (#593) isn't an option, because the agent needs those tags to drop its own messages with ctx_reduce.
We've asked OpenCode for a hook in anomalyco/opencode#53019, preferably one that runs before assistant text is displayed, or else a text.complete equivalent. If you're affected, a 👍 there helps. We're keeping this issue open until OpenCode 2 has a hook we can use.
What happened?
Magic Context: 0.44.4 installed; also checked at
main0037574 (2026-10-03)OpenCode: 2.0.22
Found by: reading source. Not yet observed in a live session. Related to #582 (which covers the WebSocket cache side) and the closed, unmerged PR #593.
What happens
On OpenCode 1, MC strips §N§ tags the model echoes into its own text at the persistence boundary, via
experimental.text.complete(index.ts:996,text-complete.ts). OpenCode 2 has no equivalent hook: its session hooks areprompt,context,compaction,generate,title,model.request,http.request,http.response, the experimentalws.*hooks andretry(packages/plugin/src/promise/session.ts), and there's notext.complete. The V2 entry registers nothing in its place, so echoed tags are saved insession_messageand shown in the transcript.Suggested fix
http.responsehook, or a post-step rewrite if the host exposes one). If no hook can do it, document the limitation.Reproduce
Run an OpenCode 2 session with
ctx_reduceavailable until the model echoes a §N§ tag in its reply. The stored assistant text insession_messagestill contains it, and the timeline shows it.