Repository navigation
[BUG] In some cases, with Codex's auto model + DeepSeek, it will suddenly terminate automatically. #732
Copy link
Copy link
Closed
Description
log
2026-09-12T14:43:08.075Z [info] forward POST → https://api.deepseek.com/responses
2026-09-12T14:43:22.209Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-usage] round 1 input=86426 cached=84864 (cache hit 98%)
2026-09-12T14:43:22.210Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-proxy: compress requested 1 range(s): m00109–m00241]
2026-09-12T14:43:22.210Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-proxy: ctx has 150 message(s), state has ? ref(s) mapped]
2026-09-12T14:43:22.210Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-proxy: first msg ids: acp_summary_b1(4061c), h_04717dfa80527a27(874c), h_c409b04ed442fbde(57c), acp_summary_b2(3581c), acp_summary_b3(11663c), h_111d38449f61bea7(4469c), h_d15b859a5b434346(290c), h_7e894daa91504165(154c), h_acd8d70bbfb03b00(5254c), h_8ea31d5c56c4658a(154c)]
2026-09-12T14:43:22.215Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-compress-obs] shrink 35% (~29987/86426 tok) foldPoint=m00109 blocks=1 anchor≈2479 tok (2 active blocks, sys excluded) postCtx≈56439 → next-request cache ceiling ≥4%
2026-09-12T14:43:22.215Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-proxy: [Compressed m00109–m00241 → 1 block(s), ~29987 tokens saved.]]
2026-09-12T14:43:22.218Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-loop] round 1: re-request view refreshed to post-compress fold
2026-09-12T14:43:22.218Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-loop] round 1: proxy tool executed; re-requesting so the model sees the result
2026-09-12T14:43:32.513Z [warn] [degenerate-turn] responses: turn ended completed with zero visible text and zero tool calls (thinking present; no visible text emitted) — the agent receives an empty turn and may stall until nudged (#673)
2026-09-12T14:43:32.513Z [info] [01a09604-f526-7822-bd15-37389368b47d] [acp-usage] round 2 input=53587 cached=13184 (cache hit 25%) fold=new
2026-09-12T14:44:08.791Z [info] [update] checking npm registry for billion-context (last check 180s ago)…
2026-09-12T14:44:11.201Z [warn] [update] running v0.1.106 but v0.1.107 is installed — restart bili to activate (auto-update replaced the on-disk install; this process is still on the old code)
2026-09-12T14:46:30.533Z [info] [01a09604-f526-7822-bd15-37389368b47d] dropped 1 whitespace-only message item(s) before projection (flattened-turn artifact)
2026-09-12T14:46:30.538Z [info] [01a09604-f526-7822-bd15-37389368b47d] processTurn: 72 msgs, renderTags=text-only, 6 text tagged, 0 tool tagged (should be 0 with text-only)
2026-09-12T14:46:30.538Z [info] [01a09604-f526-7822-bd15-37389368b47d] nudge idle: usage=42% (53587/128000), growth=-2852/22500 (ref=56439, interval=50000), pendingT1=27079/50000 model=deepseek-flash, reason="max compressible 27079 < threshold 50000; growth -2852 < floor 22500"
2026-09-12T14:46:30.538Z [warn] [01a09604-f526-7822-bd1
check 2 timestamp
2026-09-12T14:43:32.513Z auto mode stop and don't know why
2026-09-12T14:44:08.791Z
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
[-][BUG] AUTO model sometime stop[/-][+][BUG] In some cases, with Codex's auto model + DeepSeek, it will suddenly terminate automatically.[/+]ranxianglei commentedon Sep 12, 2026
[bot] 🏷
Thanks for the log — this is a real, reproducible failure mode and I can pinpoint both timestamps.
What actually stopped —
14:43:32.513ZThat timestamp IS the stop. The sequence:
14:43:22(round 1): the model issued acompresscall → bili executed it server-side (Compressed m00109–m00241 → ~29987 tokens saved) and re-requested so the model sees the result (round 1: proxy tool executed; re-requesting).14:43:32(round 2): the model returned a degenerate turn — it finished normally (completed) but emitted only a thinking/reasoning block, zero visible text, zero tool calls. That's exactly what the[degenerate-turn] … (#673)warning reports. The agent gets an empty completed turn and stalls until nudged.So the "stop" is the upstream model (deepseek-flash) ending its turn with thinking only. bili detected it correctly and flagged it — it just had no recovery step, so the empty turn was passed straight through and the agent sat idle until the next request at
14:46:30.The second timestamp —
14:44:08.791ZUnrelated to the stop. It's just the routine npm auto-update check (
checking npm registry … last check 180s ago). The following line (running v0.1.106 but v0.1.107 is installed — restart bili) likewise has nothing to do with the stall — it only means you should restart bili to pick up v0.1.107. The gap between14:43:32and14:46:30is simply the agent stalled by the empty turn.Root cause / layer
BILI_FAKE_COMPLETION_RETRIES) does not cover this: (a) it's off by default, (b) it detects a different shape (the model writing tool-call XML as plain text), and (c) it only guards the first fetch, not the compress loop's round-2+ re-requests — which is where this happens.Fix I'm implementing
An invisible single-retry inside the compress loop (
src/loop/core.ts): when a terminal turn is degenerate (normal completion, zero visible text, zero tool calls) and nothing has been forwarded to the client yet (forwardedAny === false— true for these post-compress rounds, since round>1 reasoning/meta are suppressed), re-fetch once with a light continuation nudge. A plain re-fetch would deterministically reproduce the same silent output, so the nudge is what breaks the pattern. It's one-shot per request and mirrors the existing invisible truncation-retry guard (#413), so it can't corrupt the client stream. This completes the auto-retry that #673/#674 set up.Opening a PR with a regression test. If you'd rather I gate it behind an env flag instead of on-by-default, say so and I'll adjust before merge.
——
中文摘要:
14:43:32那次停止是模型(deepseek-flash)在压缩后重请求的 round 2 只返回了思考块、没有任何可见文本或工具调用(即 #673 的 degenerate-turn),agent 拿到空回合就卡住了;14:44:08只是例行 npm 自动更新检查,与卡住无关。根因在上游推理模型的偶发行为,bili 检测正确但缺重试。我会在压缩循环里加一个“对客户端不可见的单次重试(带继续提示)”来补上 #673 预留的 auto-retry。ranxianglei commentedon Sep 12, 2026
Short answer on your two timestamps:
14:43:32.513Zis the stop. That's the[degenerate-turn]line: right after bili ran your round-1compress(Compressed m00109–m00241) and re-requested, the model (deepseek-flash) returned a turn that endedcompletedbut contained only a thinking block — no visible text, no tool call. The client got an empty completed turn, so the agent sat idle until the next request arrived at14:46:30.14:44:08.791Zis unrelated — that's just the routine npm auto-update check (checking npm registry … last check 180s ago). The follow-up "running v0.1.106 but v0.1.107 is installed — restart bili" is the same housekeeping, not the stall.Root cause. This is upstream reasoning-model behavior, not a bili data bug: deepseek-flash occasionally emits a reasoning-only completion, and the post-compress re-request makes it more likely (the model sees freshly-shrunk context and "wraps up" into a silent thought). bili already detected this correctly (#673) — but only as a warning. The detector was described as "the groundwork for auto-retry," and that retry was never implemented. (The separate #371 fake-completion backstop catches a different shape, is off by default, and only guards the first fetch, not later loop rounds.)
Fix (PR open): #734. It implements the missing retry. When a loop round ends
completedwith zero text and zero tool calls, thinking present, and nothing forwarded to you yet, bili re-fetches once with a short continuation nudge. It's invisible to the client, the nudge is never persisted into session state, it's one-shot per request, and it's guarded so a genuinely-empty (no-reasoning) terminal turn is left untouched. Pre-flight: typecheck ✅ / test ✅ (1431 pass, 0 fail) / build ✅.Not released yet — it ships in the next release and your running proxy will pick it up via auto-update after that lands. Until then, if you hit a stall like this, sending any message (even a bare nudge) resumes it, because the trigger is the model's silent turn, not lost state.
中文摘要:你贴的两个时间戳里,
14:43:32.513Z才是卡住的原因——压缩后重新请求时 deepseek-flash 只返回了一个「纯思考」回合(状态 completed,但没有可见文本、没有工具调用),客户端拿到空回合就停住了;14:44:08.791Z只是例行 npm 自动更新检查,跟卡住无关。根因是上游推理模型偶尔只输出思考块(bili 在 #673 已经能检测到,但当时只做了告警,自动重试一直没实现)。我已在 PR #734 补上缺失的重试:当某个循环回合以 completed 结束、零文本零工具调用、有思考、且还没向你转发任何内容时,带一条临时续写提示重取一次(对客户端不可见、也不落盘),每请求最多一次;真正为空的回合不受影响。typecheck / test / build 全绿。合并发布后你正在跑的代理会自动更新拿到它。ranxianglei commentedon Sep 14, 2026
ework简述本issue在最新版本是否还有问题,哪个pr需要合并
fix: auto-retry invisible degenerate terminal turns (#732)
ranxianglei commentedon Sep 14, 2026
结论:最新版仍有问题;需要合并的是 PR #734。
1) 最新版是否还有问题 —— 有。
npm 上现已发布到 v0.1.110,但本 issue 的 bug(压缩后重新请求时,模型只返回一个「纯思考」回合——状态
completed却无可见文本、无工具调用 → 客户端拿到空 completed 回合而卡住)在 v0.1.110 里依然存在。我核对了 master 自 v0.1.107 以来的全部提交:没有任何一个修这个问题。其间的 reasoning-guard(#739/#740)是另一回事——针对 gpt-5.x/gpt-6.x 的推理截断保护,和本次「静默思考回合导致空回合」无关。所以最新版尚未修复。2) 需要合并哪个 PR —— #734。
我刚把 #734 rebase 到当前 master(v0.1.110),重同步了依赖并重跑校验:
version-guard、build-artifact、codex 零 token E2E 预检均为 success),4 个必需 test 矩阵(ubuntu/windows × node22/24)正在跑,转绿后mergeable_state即变 clean、可合并。合并后 CI 会自动发布下一个版本,正在运行的代理会通过自动更新拿到该修复。(合并动作按仓库规则由人工执行。)
Merge pull request #734 from ranxianglei/2026-09-12_auto-mode-degener…
fix(plugin): retry a turn whose only visible output was a stripped ta…
Harden the Responses plugin pipe with the degenerate-turn retry (ranx…
Harden the Responses plugin pipe with the degenerate-turn retry (ranx…
Harden the Responses plugin pipe with the degenerate-turn retry (ranx…
fix(plugin): retry a turn whose only visible output was a stripped ta…
Harden the Responses plugin pipe with the degenerate-turn retry (ranx…
fix(plugin): never retry a bare or trigger-final empty turn (ranxiang…
fix: recover from mid-stream upstream truncations (#413 relaxation + …
fix: release held done-family events when the next item opens (#1061)
fix(#1778): count fast-path prose in the plugin responses pipe's visi…
fix(plugin): drain held tag tails before a terminal finish frame (ran…
fix: classify released refs-run tails as prose in degenerate-turn acc…
escalate the degenerate-turn retry: second anti-echo nudge, bounded a…
feat: termination diagnostics on the plugin-lane truncation signal (#…
feat: termination diagnostics on the plugin-lane truncation signal (#…
fix(#2769): reach the degenerate-turn gate on the Gemini wire
fix(ranxianglei#2756): degenerate-turn gate asks for ANSWER text, not…