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 V2: Compress Function Call Mangled In LLM Output #1366
[bot] 🏷 (continuing — my previous comment was truncated by a client bug; sorry)
Continuing from "once as literal tool-call-shaped XML (opening tag with function=compress plus two parameters) inside the assistant's text", and once as the real structured tool part — the green check-compress line — which executed fine. So compression itself worked; the visible mangling is the model echoing the call as raw text.
Before changing anything I need to pin down who emitted that text — the model or the proxy. Could you share:
bili version running at the time (bili --version).
The upstream provider/endpoint used for MiMo V2.5 (base URL only, no key).
The bili log lines around that turn — the log lives under the XDG state dir (see CONFIGURATION.md, section Logging); specifically the request line showing how many tools were sent upstream for that session, and any response-part lines.
I'm digging into the OpenCode V2 plugin path on our side meanwhile.
Full diagnosis is in — bottom line up front: bili did not mangle anything. The model wrote the same compress call twice — once as literal text inside its prose, and once as the real structured tool call.
What your screenshot actually shows (one turn, two artifacts)
Prose ending in "Now let me compress old conversation to free context, then test:" followed by a literal call-shaped XML blob (an opening tag naming function=compress, then two parameter blocks carrying your EDID/WCG/znver4 summary and a topic) written as plain text inside the message content.
Below it, the green ✓ compress line — a real, successfully executed structured tool part. opencode only renders that after receiving the structured tool-call chunk intact from the stream and dispatching its own natively-registered compress tool (the bili V2 plugin's execute handler forwards it to the proxy's /tool endpoint).
Why this proves bili passed everything through untouched
Nothing bili injects teaches that format either: the compress tool schema is JSON-only (kernel-owned), and the nudge + injected compression prompt are plain prose with no call markup anywhere. The blob's content is clearly the model's own drafted compress payload leaking into its text stream.
So the producer sits upstream of bili: MiMo V2.5 via your relay emitted one tool call in two representations — a text draft plus the real block. This is a known failure class in this project: #361 detects+warns it in proxy mode, #371/#473 add the opt-in fake-completion retry for the pure-text variant. And there is a deliberate project decision (#361, citing the #295 review) NOT to strip call-shaped markup from model prose, because a shape-based filter cannot tell an echoed template apart from legitimate prose that discusses such markup — stripping would corrupt real content.
What you can do
Durable fix is on the provider side: use an endpoint with strong native tool-calling for this model. Relays doing prompt-based function-call extraction are the classic source of these dual emissions.
Optional guard for the worse variant — model writes the call as text AND emits no structured block at all, so nothing runs while the model believes it did: start bili with BILI_FAKE_COMPLETION_RETRIES=2. It buffers the turn, detects the shape, and retries once with a corrective hint. Note it does NOT remove the cosmetic echo in your dual-emission case, and buffering trades off incremental streaming on the turns it engages.
Context-accounting note: the text blob stays in opencode's re-sent history (token cost) until a compression range covers it; the actual compression did run, and subsequent turns carry the genuine tool call/result pair.
Follow-up filed:#1368 — plugin-mode passthrough currently logs nothing when this happens (proxy mode gets a once-per-request warning since #361; the plugin pipe doesn't). Your report arrived as a screenshot with no corroborating log line; that parity gap slows future attribution.
The three items I asked for on floor 4 (bili version, endpoint base URL, log lines) are no longer needed to attribute this one — but if you see the pure-text variant (a turn where NO ✓ line appears yet the model claims it compressed), send those over, since that's the case where data silently doesn't get compressed.
Compress Function Call Difficulties (from LLM session)
1. Compress tool calls appear in visible output
The compress XML tags leak into the conversation view instead of being silently executed by the bili proxy. This happens when the LLM emits the compress call and the proxy doesn't strip it before rendering.
2. Compress tool fails repeatedly with same error
When trying to compress ranges, the tool returns:
[Compression FAILED: no valid ranges parsed (kind=missing-content, dropped=0)]
Despite passing valid startId/endId refs and summary content. Tried both array form {startId, endId, summary} and line-form strings. The error says "compress requires a non-empty content array" but the content IS provided.
3. Live compressible refs mismatch
After multiple failed compress attempts, the live compressible range shrinks:
First attempt: refs m01286-m01539 were compressible
After failures: only m01321-m01639 remains compressible (older refs already in blocks)
But the tool still fails to parse the content array
4. Repeat-failure guard blocks retries
After ~6 failed attempts, the tool emits: "Repeat-failure guard: you have now requested this exact spec 6 times... Fix the argument shape" -- but the format matches the documented spec.
Suggested fixes
Strip compress XML from LLM output before rendering to conversation
Debug why valid {startId, endId, summary} arrays fail with "missing-content"
Allow retries after format adjustments (current guard blocks after 6 attempts)
Consider a simpler API: single string with startId endId on first line, summary on rest
This second screenshot is decisive — it identifies the root cause of the repeated missing-content failures, and your model's own thinking block says it out loud.
What the screenshot shows
Recurring dual emission: below the green ✓ compress line there is again a literal call-shaped blob embedded in the prose — this time in JSON form (an array of startId/endId/summary objects). The model clearly knows the correct schema and still leaks a copy of its own call into the text stream. Same upstream behavior as before (MiMo-V2.6-Flash this time); bili passed both artifacts through verbatim, unchanged.
The actual bug behind your compress loop — self-diagnosed by your model in its thinking block: "I keep issuing an empty second compress() call! Looking at my recent turns — yes, I issued compress with content AND an empty compress() in the same block. The empty call's error is what gets reported."
So the floor-6 premise ("valid {startId, endId, summary} arrays fail with missing-content") does not hold: nothing in the parser rejects a valid array — your valid calls succeeded (the ✓ lines; blocks b77/b78 exist). The quoted error [Compression FAILED: no valid ranges parsed (kind=missing-content, dropped=0)] came from the EMPTY companion call. Verified against the code: an argument object carrying no content field parses to exactly kind=missing-content with zero dropped items and no rejected entries — a byte-for-byte match of what you quoted.
Why it looped 6 times
The receipt for an empty call ends with "Re-issue the compress call with a valid content array." For a structurally empty call, that instruction can never be satisfied by re-issuing the same call — yet that is exactly what the model did, until the repeat-failure guard (#847) tripped. The guard only blocks IDENTICAL specs (any different range passes) and exists precisely because such loops previously burned context 76%→89% over ~13 min. So point 4 is working as designed.
The nudge-vs-tool "conflict" (point 3)
Not a conflict: the nudge reports a coarse advisory window (first-uncovered through last-uncovered, spanning gaps between blocks); the tool error reports the precise live boundary (highest active-block endRef + 1). Your model resolved it correctly by trusting the tool. One genuine imprecision found: the hint's phrasing "(everything up to mNNNNN is already inside active blocks)" is false when gaps exist (your m05027–m05052 gap). Fixing that wording in the PR.
What I am changing (small, diagnostics-only) — behavior change flagged per policy:
In src/stream.ts, when a compress call arrives with no content at all (empty object or empty-string arguments), the model-facing receipt changes:
OLD: [Compression FAILED: no valid ranges parsed (kind=missing-content, dropped=0). … Re-issue the compress call with a valid content array.]
NEW: [Compression FAILED: the call carried no content at all (kind=missing-content) — an empty compress() compresses nothing and can never succeed. Do NOT re-issue an empty call; if you meant to compress, put the non-empty 'content' array (elements {startId, endId, summary}) in that SAME single call.]
Only the receipt wording for truly-empty calls changes; every other receipt stays byte-identical. Plus the one-line span-hint wording fix. Regression tests included — PR follows shortly.
No further evidence needed from you. If you want the cosmetic echo gone entirely, the lever is provider-side: an endpoint with strong native tool-calling for the MiMo family.
中文摘要:第二张截图定位了 missing-content 反复失败的真正原因——模型每次在有效调用之外多发一个空的第二个 compress(),报错全部来自这些空调用(有效调用其实都成功了);而空调用的旧回执以"Re-issue the compress call"结尾,诱导模型对结构性为空的调用反复重试直到 #847 守卫触发。已在 src/stream.ts 修复:空调用获得专门回执(点明"根本没带 content、永远不可能成功、不要重发"),并修正 span 提示中"gaps 存在时 everything up to N 都在 block 里"的不实措辞;PR 稍后提交。
Two small, diagnostics-only commits (both regression-tested, full suite green on current master):
Empty-call receipt fix — applyRanges now detects compress calls that carry no content at all ({} / empty-string args — your model's "empty companion" calls) and returns a receipt that names the actual defect and forbids the re-issue, instead of the old generic lecture that ended in "Re-issue the compress call…" — the instruction that looped your session until the 出现持续压缩失败,无法自动恢复 #847 guard tripped. Behavior change flagged in the PR body (old→new wording; only truly-empty calls affected, every other receipt byte-identical). The repeat-failure guard still records these failures, and the [bug] 0.1.63 起 Windows persist EPERM 风暴:会话持久化静默丢数据(4.9k 次/117 会话)+ compress no-valid-ranges 拒绝 #362 shape-drift case (ranges key) deliberately keeps the format lecture since fixing that key can succeed.
Span-hint wording (labeled in-passing fix from the same incident) — the hint's "(everything up to mNNNNN is already inside active blocks)" was false for your non-contiguous blocks (the m05027–m05052 gap); it now hedges accordingly. Kernel validation was always authoritative; this only removes the misleading phrasing.
What the PR does NOT do, by documented decision: strip call-shaped markup from model output (#361/#295 — a shape filter corrupts legitimate prose, and your second screenshot shows the leaked blob carrying a genuine summary payload). The cosmetic echo itself stays an upstream lever: an endpoint with strong native tool-calling for the MiMo family.
Also on file from this issue: #1368 (plugin-mode passthrough lacks the warn-only log proxy mode has since #361 — the observability gap that made this a screenshot-only diagnosis).
Heads-up: this report arrived again, but it's the same text as your earlier comment (floor 6), which is already fully answered above — no new analysis needed, so keeping this to a status pointer:
Point 2 / fix 2 (the actual defect): root cause was an empty companion compress() call the model emitted alongside each valid one — your valid arrays never failed; every quoted error came from the empty call, whose old receipt ended in "Re-issue…" and looped until the guard tripped. Fixed in fix: stop empty-compress-call retry loops — targeted no-content receipt (#1366) #1384 (targeted no-re-issue receipt for content-less calls + span-hint wording hedge).
Point 3: not a conflict — nudge reports a coarse advisory window, the tool error the precise live boundary. One genuine wording imprecision found and fixed in the PR.
Current status of PR #1384: open, all E2E suites green (fake-codex / local-registry / native-pi / real codex), main CI job still running on the final commit. Merge stays human-only. Related observability gap tracked separately at #1368.
中文摘要:此条与你在上方楼层提交的报告内容相同,已在上面完整答复,此处仅给状态:真正缺陷(模型多发空调用导致 missing-content 循环)已由 PR #1384 修复,E2E 全绿、主 CI 运行中;剥离 XML 按既有决策不做;其余各点均已在上方逐条说明。
Status update: PR #1384 is now fully green — all CI suites passed on the final commit (CI, e2e-fake-codex, e2e-local-registry, e2e-native-pi, E2E real codex, PR Build Artifact, Windows codex overlay). Ready for human merge whenever: #1384
Correction to my earlier comment above — I attributed these failures to an argument-format / API mismatch in my comment. The evidence says otherwise; here it is.
Every failing compress call in the session store is recorded with empty input:
while the same message's reasoning contains the full composed content array, and the rendered transcript shows compress({}). So the proxy received an empty object — no valid ranges parsed (kind=missing-content, dropped=0) is correct for what arrived. The arguments were dropped between the model's stream and the proxy.
Decisive detail: the identical argument format succeeded later in the same session (several subsequent compressions produced blocks without error), so the format/API theory in my earlier comment is wrong — the format was never the problem. It's an intermittent streaming fault.
Cross-session scan of the local 6.0 GB session store: 7 sessions contain no valid ranges parsed markers (worst: 116 in one session; this session: 25). The sibling fault (OpenAI Chat tool call delta is missing id or name → circuit breaker) is being tracked on the client side at anomalyco/opencode#52700, with this session's evidence posted there.
Actionable question for this repo: when a compress tool call arrives with input:{} / missing content, does the proxy have any way to distinguish "model sent empty args" from "args were lost in transport"? If the delta loss happens upstream of the proxy, this issue is at least partially a client/provider problem (see cross-reference above).
Activity
ranxianglei commentedon Sep 25, 2026
[bot] 🏷 Acknowledged — looking into #1366 now.
What the screenshot shows, as far as I can tell: the
compresscall appears twice in that turn — once as literal `ranxianglei commentedon Sep 25, 2026
[bot] 🏷 (continuing — my previous comment was truncated by a client bug; sorry)
Continuing from "once as literal tool-call-shaped XML (opening tag with function=compress plus two parameters) inside the assistant's text", and once as the real structured tool part — the green check-compress line — which executed fine. So compression itself worked; the visible mangling is the model echoing the call as raw text.
Before changing anything I need to pin down who emitted that text — the model or the proxy. Could you share:
I'm digging into the OpenCode V2 plugin path on our side meanwhile.
ranxianglei commentedon Sep 25, 2026
Full diagnosis is in — bottom line up front: bili did not mangle anything. The model wrote the same
compresscall twice — once as literal text inside its prose, and once as the real structured tool call.What your screenshot actually shows (one turn, two artifacts)
Why this proves bili passed everything through untouched
src/server.ts:4835→pipePluginChatWithStrip). The only rewrites ever applied are render-tag / marker-line echo stripping (偶尔重复输出 <acp tokens="177" type="text">m00155</acp> #206/模型把 "📦 [ACP] Compressed" 确认标记伪造为普通 assistant 文本——17 次假压缩、0 次真实执行(自我回执幻觉) #717). Nothing in that path touches call-shaped text.So the producer sits upstream of bili: MiMo V2.5 via your relay emitted one tool call in two representations — a text draft plus the real block. This is a known failure class in this project: #361 detects+warns it in proxy mode, #371/#473 add the opt-in fake-completion retry for the pure-text variant. And there is a deliberate project decision (#361, citing the #295 review) NOT to strip call-shaped markup from model prose, because a shape-based filter cannot tell an echoed template apart from legitimate prose that discusses such markup — stripping would corrupt real content.
What you can do
BILI_FAKE_COMPLETION_RETRIES=2. It buffers the turn, detects the shape, and retries once with a corrective hint. Note it does NOT remove the cosmetic echo in your dual-emission case, and buffering trades off incremental streaming on the turns it engages.Follow-up filed: #1368 — plugin-mode passthrough currently logs nothing when this happens (proxy mode gets a once-per-request warning since #361; the plugin pipe doesn't). Your report arrived as a screenshot with no corroborating log line; that parity gap slows future attribution.
The three items I asked for on floor 4 (bili version, endpoint base URL, log lines) are no longer needed to attribute this one — but if you see the pure-text variant (a turn where NO ✓ line appears yet the model claims it compressed), send those over, since that's the case where data silently doesn't get compressed.
中文摘要:截图里的"乱码"是模型(MiMo V2.5 经你的中转)把同一个 compress 调用写了两次——一次当纯文本写进正文,一次是真正的结构化调用(绿色 ✓ compress 即它成功执行);bili 在 plugin 模式下对模型输出逐字节透传(仅剥 render-tag/marker 回显),并未改写任何内容,属上游模型/中转的已知失败模式(#361/#371/#473),建议换原生工具调用能力更强的端点;另已立跟进 issue #1368 补上 plugin 模式缺失的告警日志。
Selene0623 commentedon Sep 25, 2026
Compress Function Call Difficulties (from LLM session)
1. Compress tool calls appear in visible output
The compress XML tags leak into the conversation view instead of being silently executed by the bili proxy. This happens when the LLM emits the compress call and the proxy doesn't strip it before rendering.
2. Compress tool fails repeatedly with same error
When trying to compress ranges, the tool returns:
Despite passing valid startId/endId refs and summary content. Tried both array form {startId, endId, summary} and line-form strings. The error says "compress requires a non-empty content array" but the content IS provided.
3. Live compressible refs mismatch
After multiple failed compress attempts, the live compressible range shrinks:
4. Repeat-failure guard blocks retries
After ~6 failed attempts, the tool emits: "Repeat-failure guard: you have now requested this exact spec 6 times... Fix the argument shape" -- but the format matches the documented spec.
Suggested fixes
Selene0623 commentedon Sep 25, 2026
ranxianglei commentedon Sep 25, 2026
This second screenshot is decisive — it identifies the root cause of the repeated missing-content failures, and your model's own thinking block says it out loud.
What the screenshot shows
Recurring dual emission: below the green ✓ compress line there is again a literal call-shaped blob embedded in the prose — this time in JSON form (an array of startId/endId/summary objects). The model clearly knows the correct schema and still leaks a copy of its own call into the text stream. Same upstream behavior as before (MiMo-V2.6-Flash this time); bili passed both artifacts through verbatim, unchanged.
The actual bug behind your compress loop — self-diagnosed by your model in its thinking block: "I keep issuing an empty second compress() call! Looking at my recent turns — yes, I issued compress with content AND an empty compress() in the same block. The empty call's error is what gets reported."
So the floor-6 premise ("valid {startId, endId, summary} arrays fail with missing-content") does not hold: nothing in the parser rejects a valid array — your valid calls succeeded (the ✓ lines; blocks b77/b78 exist). The quoted error
[Compression FAILED: no valid ranges parsed (kind=missing-content, dropped=0)]came from the EMPTY companion call. Verified against the code: an argument object carrying no content field parses to exactly kind=missing-content with zero dropped items and no rejected entries — a byte-for-byte match of what you quoted.Why it looped 6 times
The receipt for an empty call ends with "Re-issue the compress call with a valid content array." For a structurally empty call, that instruction can never be satisfied by re-issuing the same call — yet that is exactly what the model did, until the repeat-failure guard (#847) tripped. The guard only blocks IDENTICAL specs (any different range passes) and exists precisely because such loops previously burned context 76%→89% over ~13 min. So point 4 is working as designed.
The nudge-vs-tool "conflict" (point 3)
Not a conflict: the nudge reports a coarse advisory window (first-uncovered through last-uncovered, spanning gaps between blocks); the tool error reports the precise live boundary (highest active-block endRef + 1). Your model resolved it correctly by trusting the tool. One genuine imprecision found: the hint's phrasing "(everything up to mNNNNN is already inside active blocks)" is false when gaps exist (your m05027–m05052 gap). Fixing that wording in the PR.
Your four suggested fixes
What I am changing (small, diagnostics-only) — behavior change flagged per policy:
In
src/stream.ts, when a compress call arrives with no content at all (empty object or empty-string arguments), the model-facing receipt changes:[Compression FAILED: no valid ranges parsed (kind=missing-content, dropped=0). … Re-issue the compress call with a valid content array.][Compression FAILED: the call carried no content at all (kind=missing-content) — an empty compress() compresses nothing and can never succeed. Do NOT re-issue an empty call; if you meant to compress, put the non-empty 'content' array (elements {startId, endId, summary}) in that SAME single call.]Only the receipt wording for truly-empty calls changes; every other receipt stays byte-identical. Plus the one-line span-hint wording fix. Regression tests included — PR follows shortly.
No further evidence needed from you. If you want the cosmetic echo gone entirely, the lever is provider-side: an endpoint with strong native tool-calling for the MiMo family.
中文摘要:第二张截图定位了 missing-content 反复失败的真正原因——模型每次在有效调用之外多发一个空的第二个 compress(),报错全部来自这些空调用(有效调用其实都成功了);而空调用的旧回执以"Re-issue the compress call"结尾,诱导模型对结构性为空的调用反复重试直到 #847 守卫触发。已在 src/stream.ts 修复:空调用获得专门回执(点明"根本没带 content、永远不可能成功、不要重发"),并修正 span 提示中"gaps 存在时 everything up to N 都在 block 里"的不实措辞;PR 稍后提交。
ranxianglei commentedon Sep 26, 2026
PR ready: #1384
Two small, diagnostics-only commits (both regression-tested, full suite green on current master):
applyRangesnow detects compress calls that carry no content at all ({}/ empty-string args — your model's "empty companion" calls) and returns a receipt that names the actual defect and forbids the re-issue, instead of the old generic lecture that ended in "Re-issue the compress call…" — the instruction that looped your session until the 出现持续压缩失败,无法自动恢复 #847 guard tripped. Behavior change flagged in the PR body (old→new wording; only truly-empty calls affected, every other receipt byte-identical). The repeat-failure guard still records these failures, and the [bug] 0.1.63 起 Windows persist EPERM 风暴:会话持久化静默丢数据(4.9k 次/117 会话)+ compress no-valid-ranges 拒绝 #362 shape-drift case (rangeskey) deliberately keeps the format lecture since fixing that key can succeed.What the PR does NOT do, by documented decision: strip call-shaped markup from model output (#361/#295 — a shape filter corrupts legitimate prose, and your second screenshot shows the leaked blob carrying a genuine summary payload). The cosmetic echo itself stays an upstream lever: an endpoint with strong native tool-calling for the MiMo family.
Also on file from this issue: #1368 (plugin-mode passthrough lacks the warn-only log proxy mode has since #361 — the observability gap that made this a screenshot-only diagnosis).
中文摘要:PR #1384 已提交——空调用(空对象/空串参数)现在收到专门回执(点明"根本没带 content、永远不可能成功、不要重发"),不再以诱导重发的"Re-issue…"结尾,从机制上消除本次事故的 6 次重试循环;另修正 span 提示中 gaps 存在时的不实措辞。输出中残留的调用文本回显按既有决策(#361/#295)不做剥离,需在上游端点侧解决。
ranxianglei commentedon Sep 26, 2026
Heads-up: this report arrived again, but it's the same text as your earlier comment (floor 6), which is already fully answered above — no new analysis needed, so keeping this to a status pointer:
BILI_FAKE_COMPLETION_RETRIES=2covers the pure-text variant.Current status of PR #1384: open, all E2E suites green (fake-codex / local-registry / native-pi / real codex), main CI job still running on the final commit. Merge stays human-only. Related observability gap tracked separately at #1368.
中文摘要:此条与你在上方楼层提交的报告内容相同,已在上面完整答复,此处仅给状态:真正缺陷(模型多发空调用导致 missing-content 循环)已由 PR #1384 修复,E2E 全绿、主 CI 运行中;剥离 XML 按既有决策不做;其余各点均已在上方逐条说明。
ranxianglei commentedon Sep 26, 2026
Status update: PR #1384 is now fully green — all CI suites passed on the final commit (CI, e2e-fake-codex, e2e-local-registry, e2e-native-pi, E2E real codex, PR Build Artifact, Windows codex overlay). Ready for human merge whenever: #1384
中文摘要:PR #1384 全部 CI/E2E 套件在最终提交上通过,可合并(合并由人工执行)。
Merge pull request #1384 from ranxianglei/2026-09-26_empty-compress-r…
fix: targeted no-re-issue receipt for content-less compress calls (ra…
fix: hedge the span-hint covered-prefix claim — gaps below the bounda…
Selene0623 commentedon Oct 4, 2026
Correction to my earlier comment above — I attributed these failures to an argument-format / API mismatch in my comment. The evidence says otherwise; here it is.
Every failing
compresscall in the session store is recorded with empty input:{"type":"tool","id":"call_4f80f0b9df644ad993bd69f7","name":"compress","executed":false,"state":{"status":"completed","input":{}, ...}}while the same message's reasoning contains the full composed content array, and the rendered transcript shows
compress({}). So the proxy received an empty object —no valid ranges parsed (kind=missing-content, dropped=0)is correct for what arrived. The arguments were dropped between the model's stream and the proxy.Decisive detail: the identical argument format succeeded later in the same session (several subsequent compressions produced blocks without error), so the format/API theory in my earlier comment is wrong — the format was never the problem. It's an intermittent streaming fault.
Cross-session scan of the local 6.0 GB session store: 7 sessions contain
no valid ranges parsedmarkers (worst: 116 in one session; this session: 25). The sibling fault (OpenAI Chat tool call delta is missing id or name→ circuit breaker) is being tracked on the client side at anomalyco/opencode#52700, with this session's evidence posted there.Actionable question for this repo: when a
compresstool call arrives withinput:{}/ missingcontent, does the proxy have any way to distinguish "model sent empty args" from "args were lost in transport"? If the delta loss happens upstream of the proxy, this issue is at least partially a client/provider problem (see cross-reference above).ranxianglei commentedon Oct 31, 2026
(ai: vllm-qwen/qwen3.8-27b)
Cross-link from triage of #5238(本家族的"纯文本单发"子变体,带 debug 复现):#5238 是 floor 4 点出的更差变体的实锤——muse-spark-1.3-contributor / opencode-go(
/inference/go/v1/responses)经 DSH plugin mode(billion-context 0.1.209)把一个atem:命名空间的完整工具调用当 text 块吐出、无对应function_call结构化块,该 turn 静默未执行;bili forward→usage 全程零[tag-echo]、正文零<ac,透传未动。两点供你参考:
BILI_FAKE_COMPLETION_RETRIES抓不住atem:——hasToolCallStructure(src/fake-completion.ts:64,70)与 runaway-guard(src/runaway-guard.ts:98)的工具调用命名空间都硬编码antml:/裸名。即 floor 4 给的绕行建议对这类 client/model 实际不生效。是否扩命名空间属设计取舍(形状过滤误伤风险),默认不动,复发升高再议。fix: tell the model to re-issue a compress whose args were cut in tra…