Replies: 1 comment
|
核实结论:属实,三层断言都与源码逐字吻合,而且这正是你引述的那个修复未覆盖的另一半。
修法方向:translate.ts 把空判定放宽为「无可见块(text / tool-call)」,或 agent.ts:487 前补「仅 reasoning」分支重试;UI 折叠随修复自然缓解。(编译产物行号未逐一核对,表达式一致。) |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
A turn that produced only a
reasoningblock is treated ascompleted— no visible answer, no tool call, and the UI then leaves the raw reasoning on screenRelated: this is the uncovered half of the
2026-07-24-empty-model-response-is-retryablefix. It is not the same as "rendering shows reasoning by mistake" (that part is correct) — the defect is that a reasoning-only turn is never recognised as an empty response, so nothing retries it.Environment
@deepseek-ai/dsh0.1.5-rc.1 (Web profile,dsh web)deepseek-official / deepseek-flash,reasoningEffort: maxsession-71f620f9-…— 1.54 MB compressed, 420 zstd frames, 4.19 MB decompressed JSONLSymptom
Repeatedly, a turn ends with no assistant text and no tool call. The conversation appears to "hang": the only thing on screen is the model's reasoning, and the collapsed think-row summary is frozen on whatever the last reasoning line happened to be (in my captures, always the literal string
**发。**, which is the model's own shorthand for "about to call a tool").Sending any further message resumes normally, which is the giveaway: the turn was not aborted, it completed.
Hard evidence from the session log
The same session contains 8 such messages with the identical shape — reasoning only, no
text, notool-call— at seq 511 / 529 / 597 / 741 / 775 / 788 / 806 / 814, every one of them ending in that same "about to send" phrase.Root cause
Two independent checks both miss this case.
1. Empty-response detection only counts zero blocks, not zero visible blocks
@deepseek-ai/dsh-llm-deepseeklib/index.jsL1239:A
reasoningblock callsopen("reasoning")and therefore participates inorder. So a stop that carried only reasoning is not empty by this test and is never retried.The intent is already documented in
@deepseek-ai/dsh-llmlib/types/error.js, whereEMPTY_RESPONSE_CODEis annotated:The implementation's boundary (
order.length === 0) is narrower than that stated intent.2. The agent loop only looks for tool calls
@deepseek-ai/dsh-agent-looplib/index.jsL1115-1119:Nothing inspects whether the message contained any visible text. With no tool call it returns
completed, the turn closes and control goes back to the user.Note the ordering also rules out an output-budget explanation: the recorded termination is
completed, notmax-tokens, somaxTokenswas not exhausted.3. Why the UI leaves the reasoning visible
@deepseek-ai/dsh-client-ui-chatlib/client.js:reasoningHidden(≈ offset 152378) requiresturnProcess.spec.answerStep === data.step && spec.inlineReasoning && !open. Only an answer step hides its reasoning. A step with no visible text is not an answer step, soreasoningHidden === falseand the ReasoningRow renders as-is.ReasoningRow(≈ offset 143626) useslatestLine(text)for the collapsed summary while running — so it always shows the last line, which is exactly why every stalled turn I captured ended on the identical phrase.So the visible symptom is a compound of (2) and (3): the loop accepts a contentless turn, and the UI then has no answer text with which to demote the reasoning into the collapsed process area.
Suggested fixes
@deepseek-ai/dsh-llm-deepseeklib/index.jsorder.length === 0to "no visible block (text / tool-call)", so a reasoning-only stop is classified asEMPTY_RESPONSEand becomes retryable — matching the intent already stated in theEMPTY_RESPONSE_CODEcomment@deepseek-ai/dsh-agent-looplib/index.jstoolCalls.length === 0 → completed, add a branch for "no visible text and only reasoning": retry the step, or at minimum emit a user-visible notice, instead of ending the turn silently@deepseek-ai/dsh-client-ui-chatlib/client.jsreasoningHidden(≈152378),ReasoningRowsummary (≈143626)answerStep === data.steprequirement means a contentless step is the one case that most needs its reasoning collapsed; consider hiding reasoning whenever the step produced no visible text. ThelatestLinesummary should also carry a truncation indicator so a half-sentence of thinking cannot be mistaken for an answer@deepseek-ai/dsh-llmlib/types/error.jsEMPTY_RESPONSE_CODENotes / limitations, stated honestly
assistant/attemptis not written for successful attempts, so the concretefinish_reasonis not in the log. "Not max-tokens" is inferred fromturn/end = completed.thresholdRatio: 0.8withDEFAULT_CONTEXT_WINDOW = 1e6, i.e. ≈ 800k tokens; the affected sessions are ~4 MB decompressed, roughly 300–400k tokens by the token meter's 4-chars-per-token heuristic, and the event log contains no compaction event at all. Large context plausibly makes the failure more likely and certainly makes each step feel slower, but I cannot claim causality. Worth notingdsh-compaction-basic's own README flags that 4-chars-per-token under-prices CJK text, so real Chinese sessions cross the threshold later than the heuristic suggests.reasoningEffort: maxis a high-suspicion but unproven contributor: it lengthens reasoning and therefore raises the chance that the stream tails off right where a tool call was due. No controlled A/B was run. Lowering it tohighis the practical mitigation until the loop is fixed.Reproduction recipe (for whoever picks this up)
Session files are multi-frame zstd —
zlib.zstdDecompressSyncreturns only the first frame (~0.2 KB). Split on the frame magic28 B5 2F FDand decompress each frame separately; then look forassistant/messagerecords whosecontentarray has notextand notool-callblock, and read the followingturn/end— it will saycompleted.All reactions