dsh-token-meter: messageTokens can underflow below 0 (Zod nonnegative fails) #4703
Replies: 3 comments
|
你的根因和修法都对,而且隔壁 #4674 是同一个 bug、已经有了一份写好的补丁——先指过去省你时间,然后说一件你这份分析里需要修正的地方。 同一个 bug,那边已经走到参考实现了#4674 报的是"大范围 compress 后
你这份分析里有一处需要修正:不止
|
|
The fail-soft direction is appropriate because this is heuristic projection state, but the complete recovery boundary spans more than one accumulator. The shared signed fold also feeds contextPressure.surfaceTokens, so guarding only contextBreakdown.messageTokens leaves a sibling nonnegative schema exposed. Existing Sessions also need projection checkpoint version migration; otherwise reducer code changes do not prove cached rows will be discarded and refolded from authoritative history. A bounded recovery test should preserve a copied Session, clamp both consumers, advance their independent checkpoint versions, refold from seq 0, parse both state/wire views, and complete a subsequent model turn. We updated the source-pinned accounting guide with containment and these recovery gates: https://github.com/sandbaseai/deepseek-harness-handbook/blob/main/docs/en/operations/token-meter-accounting.md Disclosure: I contribute to this independent community handbook. |
|
Confirmed, and your root cause is exact — This is the same defect as #4674, which has more of the failure shape recorded if it is useful: the reason it is unrecoverable rather than merely wrong is that the clamp is missing on BOTH sides of the wire. The state schema and the view schema each declare Worth adding to your analysis: the overshoot is not necessarily a bug in the delta. A replacement's delta is messageTokens: Math.max(0, state.messageTokens + fold.deltaTokens),Under-reporting until the total recovers is strictly better than a permanently unusable session, for a number that is an estimate to begin with. Fixed locally exactly that way. The reproduction that pins it is a compaction whose claim exceeds the folded total — not a large session, which is what makes it look rare when it is really just conditional. |
Uh oh!
There was an error while loading. Please reload this page.
Symptom
Chat turns fail with a Zod validation error:
at
path: ["messageTokens"], surfaced to the user as a failed turn.Root cause
In
packages/llm/token-meter,contextBreakdownProjectionDefinition.applyaccumulates:foldSurfaceProjectionreturns a negativedeltaTokenswhen a surface message is replaced/compacted (surfaceOp === "replace"→deltaTokens = tokens - claim.tokens). When the magnitude of that negative delta exceeds the currently accumulatedstate.messageTokens, the sum goes below zero and trips thetokenCount = z.number().int().nonnegative()schema on the next checkpoint/validation.systemTokens/toolsTokensare always non-negative from their estimators; onlymessageTokenscan underflow via the signed fold delta.Suggested fix
Clamp the accumulator to a non-negative floor:
or make the shadow-price claim accounting resilient to a claim whose
shadowedTokenCountexceeds the live accumulated total (the two should never disagree, but a mismatch currently hard-crashes the turn instead of degrading the heuristic figure).Version
@deepseek-ai/dsh-token-meter@0.1.1-rc.2Note: this figure is a heuristic context-composition estimate (display/metering only), so flooring it at 0 is safe and does not affect the actual request payload.
All reactions