Repository navigation
[Provider compatibility] opencode-go/mimo-v2.6: native XML tool-call envelope reaches visible assistant text #5499
Description
Client or integration
Codex App
Area
Provider adapter
Summary
MiMo v2.6 emits its tool call in the Xiaomi native XML envelope, and on the routed freeform path that envelope text reaches the assistant message body, so Codex renders raw call syntax as visible output.
Envelope taken verbatim from a Codex App subagent session routed to opencode-go/mimo-v2.6-flash:
...并立即给出 canonical final。<tool_call><function=exec>const results = await Promise.allSettled([
tools.exec_command({ cmd: "git status --short --branch", workdir: "...", yield_time_ms: 10000 }),
...
</parameter></function></tool_call>
The call itself executed: 2 ms later in the same turn the rollout records a custom_tool_call whose input is the identical JavaScript, so the visible text is a duplicate in the content channel. 6 of 11 exec turns in that session carried the envelope; earlier turns in the same session on opencode-go/deepseek-v4.1-flash produced 107 structured calls and 0 textual leaks.
Where the shape comes from: opencodex lowers the Codex freeform exec custom tool to a function with a single required string parameter named input (src/responses/custom-tool-compat.ts, rewriteForUpstream). MiMo renders function arguments in the <parameter=name> syntax, so the native call is <tool_call><function=exec><parameter=input>...</parameter></function></tool_call>.
Expected: a recognized XML envelope is either consumed into the structured call or stripped from content. It must not reach the client as assistant text.
Reproduction
Deterministic half - the envelope survives into the wire on the routed freeform path.
ocx start(proxy on 127.0.0.1:10100), provideropencode-goas shipped (adapter: openai-chat,baseUrl: https://opencode.ai/zen/go/v1).- POST to
http://127.0.0.1:10100/v1/responseswith the Codex wire shape:
{
"model": "opencode-go/mimo-v2.6-flash",
"input": [{"role": "user", "content": [{"type": "input_text", "text": "用 exec 工具列出 /tmp 下的文件。"}]}],
"tools": [{"type": "custom", "name": "exec", "description": "Run JavaScript...", "format": {"type": "text"}}],
"tool_choice": "auto",
"stream": false
}Result: HTTP 200, and the returned custom_tool_call.input begins with the literal <parameter=input>.
- Repeat with a replayed turn - append a
custom_tool_callitem and itscustom_tool_call_outputtoinput, then ask for another call. Result: HTTP 200 and the returnedinputends with a stray</parameter>.
Control: the same conversation sent straight to https://opencode.ai/zen/go/v1/chat/completions (with x-opencode-session) returned clean JSON arguments and empty content in 8/8 probes covering mimo-v2.6-flash, mimo-v2.6-pro and deepseek-v4.1-flash. Zen Go parses this envelope cleanly on plain chat; the residue appears only on the routed freeform path.
Intermittent half: the content-channel leak is not reproducible on demand yet. Probes that all came back clean: a system prompt forcing plan-then-call, multi-turn replay (including replaying the envelope itself as assistant text), stream: true and stream: false, custom and JSON-schema function tools, both mimo-v2.6 ids. The observed frequency (6/11) points at a long-context trigger: the Codex code-mode system prompt, 8 declared tools, and a long replayed history.
Version
2.59.0 (bun 1.4.0 runtime). 2.60.0 is not installed because npm latest still resolves to 2.59.0 (#5385).
Operating system
macOS 26.5.2 (25F84), arm64
Provider and model
opencode-go / mimo-v2.6-flash (also seen with mimo-v2.6-pro); Codex CLI 0.155.0-alpha.9.2
Logs or error output
No error is raised; the defect is in the delivered output. The two rollout items for one leaked turn:
2026-09-22T02:34:14.528Z response_item message/assistant (content ends with the XML envelope)
2026-09-22T02:34:14.530Z response_item custom_tool_call name=exec input=<identical JS, 1563 bytes>
Redacted configuration
Provider-level workaround for the secondary gap below; no credentials:
"modelReasoningEfforts": {
"mimo-v2.6-flash": ["low", "medium", "high"],
"mimo-v2.6-pro": ["low", "medium", "high"]
},
"modelReasoningEffortMap": {
"mimo-v2.6-flash": {"low":"low","medium":"medium","high":"high","xhigh":"high","max":"high","ultra":"high"},
"mimo-v2.6-pro": {"low":"low","medium":"medium","high":"high","xhigh":"high","max":"high","ultra":"high"}
}Notes
Why the existing wrapper fixes do not cover this: #5047 / #5113 / #5151 / #5129 / #5395 all act on the JSON freeform wrapper ({"input": ...} / {"code": ...}) inside the tool-input channel. On current dev, progressiveFreeformInput is called only next to emit("response.custom_tool_call_input.delta", ...) in src/bridge/sse.ts, while the response.output_text.delta emissions are untouched. A source search for <tool_call> / <parameter= returns nothing outside the cursor adapter [TOOL_CALL] quarantine (#4815/#4816), so content is pure passthrough today.
Secondary gap on the same route: the registry declares no effort ladder for the new mimo-v2.6-* ids, so the Codex catalog advertises low...ultra while Zen Go accepts only none|low|medium|high and answers 400 Invalid request parameters for xhigh/max/ultra (the Codex global default is max). Same class as #1483 / #2410; the snippet above is the local workaround.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
xunhe730 commentedon Sep 22, 2026
We are seeing the same failure on a separate route, which suggests that the scope is broader than
opencode-go.Environment:
2.59.00.155.0-alpha.9.2https://token-plan-cn.xiaomimimo.com/v1)openai-chatmimo-v2.6-flashIn the affected rollout, there were 4 structured
custom_tool_callrecords. Three of them were immediately preceded by a visible assistant message containing the corresponding native XML envelope:The structured call still executed successfully, so this is the same duplicate-content behavior described here: the call appears once in the assistant text channel and once as the actual tool event. DeepSeek routed through the same local OpenCodex installation does not show this behavior.
This also reproduced after a clean OpenCodex restart and is independent of our subagent-role configuration. It appears to be a MiMo v2.6 plus routed
openai-chatnormalization issue rather than anopencode-go-specific issue.We would appreciate a fix that consumes or removes a recognized XML tool-call envelope from assistant content when the same call has already been emitted as a structured tool event, while preserving any genuine commentary around it.
fix(adapters/openai-chat): drop MiMo tool-call XML echo from content (l…
marciodps commentedon Sep 23, 2026
Same family of leak reproduced through
command-codewithxiaomi/mimo-v2.6-proon 2.64.0 — there it bypassesCommandCodeToolTextFilterbecause the markup arrives after prose inside the same text block and the filter only holds blocks that open with the marker. Details, repro shape and a validated local patch sketch in #5698.lidge-jun commentedon Sep 26, 2026
Closing: this is fixed on
devby #5739 (a8d526f). OpenCode Go is pinned to theopenai-chatadapter, and #5739 taught that adapter's reconciler (src/adapters/openai-chat/serialized-tool-call-content.ts, wired into both the streaming and buffered paths ofopenai-chat.ts) to consume MiMo's bare<tool_call><function=…>envelope from assistant text when it duplicates a structured call, and to repair doubled or<parameter=input>-prefixed arguments. Genuine commentary around the envelope is kept; only agreeing duplicates are stripped. If you still see raw call syntax on a current build, please reopen with the model id and a redacted stream.c787297017 commentedon Sep 27, 2026
This still reproduces on OpenCodex 2.68.0 after #5739. Could a maintainer reopen #5499? GitHub currently reports
viewerCanReopen: falsefor my account.Environment: Codex App/CLI 0.158.0-alpha.2.1; provider
opencode-go; modelmimo-v2.6-flash; reasoning efforthigh. The OpenCodex 2.68.0 package was installed before the proxy started, and the proxy started before this task.Redacted rollout evidence from one task on 2026-09-27 (UTC):
<tool_call><function=exec>…</tool_call>.custom_tool_callforexec; its complete JavaScript input also appears in the preceding visible message.</parameter>close tag).custom_tool_callforexec; again its complete input appears in the preceding visible message.Thus 2 of 14 custom tool calls in this task leaked their native XML envelope into assistant text while the corresponding structured call still executed. No prompt, tool arguments, paths, or credentials are included here.
A direct check against the installed 2.68.0
splitAtPossibleSerializedToolCallconfirms the boundary: withprose。<tool_call>...it returnshasOpenTag=falseand emits the XML as text; withprose。\n<tool_call>...it returnshasOpenTag=trueand holds the marker. The current parser only probes for the opening tag at line start. This matches the exact same-line shape in the original report.This run did not show
<parameter>residue in the structured tool inputs. The confirmed remaining defect is the content-channel leak.