Repository navigation
compaction-basic: add a prompt-message budget — long sessions die on gateways that cap message count #10473
layen-king
started this conversation in
General
Replies: 0 comments
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.
Summary
A long-lived session became permanently unsendable: every model call returned HTTP 400 from the provider, and nothing in DSH noticed. The token meter reported pressure below the compaction threshold, so
compaction-basicnever ran, and each retry rebuilt the same oversized prompt.The root cause is that some OpenAI-compatible gateways cap the prompt message count per request independently of the model's context window.
compaction-basiconly reacts to token pressure, so a tool-heavy session can reach that cap while still "fitting" the declared window.Observed failure
Session: 180 goal rounds, 2057 projected prompt messages, ~790k tokens, model declaring
contextWindow: 1000000. From one step onwards every request failed:The message is opaque (it comes from the gateway's internal request-rewrite layer), and it never clears on retry, because the history is already over the cap.
Root cause (bisected against the live endpoint)
a single request cannot evaluate more than 8192 path candidatesThe cap is message count, not bytes or content:
reasoning_contentstripped → still 400DSH side:
resolveCompactSpecderives pressure purely from tokens —min(contextWindow * thresholdRatio, contextWindow − reservedCompletionTokens − headroomTokens). WiththresholdRatio: 0.8,headroomTokens: 65536, a 32k output reservation and a 1M window that is 800,000 tokens, while 2048 messages of a tool-heavy session sat at ~790k. Compaction therefore never triggered, and the session could never be recovered.Suggested fix
Add a second, independent pressure trigger — a prompt-message budget — rather than relying on token scaling to approximate one:
CompactionPolicyConfig.maxMessages?: number(default e.g.1600;0disables), validated as a non-negative integer, inherited by exact-targetmodelPolicieslike the other policy fields.ResolvedPolicyFields→resolveTargetPolicy→resolveCompactSpec.compactIfNeeded(thepressurebranch), treatmeasurement.nodes.length >= spec.maxMessagesas pressure, and re-check the same predicate after the pruner pass and after each compaction attempt.TokenMeasurement.nodesalready gives the projected message count, so no new service or projection is needed. A per-route override (modelPolicies) is worth exposing too, since gateways may cap lower than 2048.Sketch of the predicate change:
With that patch the same session compacts at 1600 messages and continues (verified locally: the failing request goes 400 → 200 after compaction).
Environment
dsh0.2.1-rc.2,webprofileapi: openai-completions), single model route,reasoning_effortin useWorkaround applied meanwhile
Lowering the declared
contextWindowfor that provider's models (1M → 500k) so token pressure lands before the message cap — it works, but it is a guess at the gateway's real limit and costs usable context, which is why a first-class message budget seems preferable.All reactions