Skip to content

Recover from summary-request overflow and rescue over-ceiling context / 摘要请求超窗自恢复与硬上限截断救援 - #9879

Merged
SivanCola merged 1 commit into
esengine:main-v2from
SivanCola:fix/compaction-overflow-recovery
Sep 7, 2026
Merged

Recover from summary-request overflow and rescue over-ceiling context / 摘要请求超窗自恢复与硬上限截断救援#9879
SivanCola merged 1 commit into
esengine:main-v2from
SivanCola:fix/compaction-overflow-recovery

Conversation

@SivanCola

@SivanCola SivanCola commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Summary / 摘要

Fixes #9818.

In v1.37.0 a session could grow past the compaction threshold without an effective fold and end up 60% over the 1M window; /compact then sent a summary request that DeepSeek rejected (1108110 in the messages, 8192 in the completion) and re-sent the identical request on every retry. Root causes, all in the summary path:

  • The estimator planned the summary prefix with only 8,448 tokens (~0.8%) of headroom, and nothing fed the provider's real prompt count back when the summary request itself overflowed.
  • foldSummaryWithChunkedFallback and the fragment splitter only recognised errSummaryOutputTruncated / ErrCompactionRequired; a provider ContextLimitError bypassed every fallback.
  • At the ceiling a failed summary returned ErrCompactionRequired with no lossy last resort, and a failed attempt silenced further automatic attempts for the whole turn.
  • The DeepSeek chat adapter replays reasoning_content on every assistant turn that carries it, but admission only counted it on tool-call turns.

一句话:摘要请求自身超窗后既不回灌真实 token 数、也不缩小、也不走兜底;硬上限下没有有损救援;估算 shape 少算了普通轮次的 reasoning 回放。

Changes / 改动

  • P0 overflow ladder (fold_ladder.go, compact_summary_feedback.go): a summary overflow recalibrates prompt calibration from the reply's PromptTokens, re-plans a smaller prefix (≤2), then sends the fold once in transcript form, then (manual only) the fragment path. Chunk/merge retries now treat provider overflow as a size failure. No request is ever re-sent byte-identical.
  • P1 headroom + slim form (compact_safe_prefix.go, compact_slim.go): planning keeps max(256, 5% × window) under the output cap; the transcript-form request cuts tool results to 2000 runes, drops images and tool schemas, and is used only after the replay form overflowed, so healthy turns keep the cache-aligned prefix.
  • P2 truncation rescue (truncate.go, maintenance_commit.go): at overflow or the hard ceiling, when no summary can form, a truncate projection elides the oldest tool results outside the protected tail, then drops the oldest replay units behind an explicit marker (latest session context, digests and pinned revisions survive). ErrCompactionRequired is returned only when even that cannot reclaim enough. Prune shares the same commit path.
  • P3 long turns (compact_active_turn.go, context_receipt.go): an overflow rescue may fold the active turn's completed rounds keeping the newest two; the same-turn backoff lifts once the view has grown by 5% of the window since the failed attempt, which bounds the retries one turn can pay.
  • P4 estimator shape (internal/provider/openai/output_budget.go): DeepSeek/Kimi/GLM clients report ReplaysOrdinaryReasoning, so admission counts what the wire actually sends.
  • Docs: docs/SPEC.md / docs/SPEC.zh-CN.md describe the ladder, rescue and margin. Desktop: truncate action label in en/zh/zh-TW; bundle ceiling re-aligned to the measured 2496.6 KiB (2496.5 → 2496.7).

Tests / 测试

  • internal/boot/effect_compaction_test.go: through the real Build stack, a DeepSeek-format 400 on the summary request makes the next summary request strictly smaller and the 30-round tool loop completes.
  • internal/agent/compact_summary_limit_test.go: recalibrate-and-replan lands a digest without the fragment path; an overflow without token numbers (the GLM shape fix(agent,provider): un-stick compaction on thinking-model summaries and unnumbered overflows / 修复思考型模型摘要与无数字超窗导致的分段压缩死锁 #9882 parses) skips the re-plan and goes to the transcript form without learning a ratio or window; a provider that rejects every form never repeats a request and ends in the truncation rescue; slim request shape; active-turn boundary; elide-then-drop truncation; backoff relief.
  • Five existing ceiling tests updated from fail-closed to "rescued by truncation, no fabricated digest, no extra provider calls".
  • go vet ./..., make lint (repolint baseline unchanged at 1263), agent/boot/provider/tool/control/serve/cli suites, frontend typecheck and pnpm build pass. ask-card-layout.test.ts fails identically on the base tree.

Related: rebased onto the merge of #9882. Its reasoning-only surfacing now lives inside runSummaryRequest, so the transcript form inherits it; its "reasoning with a tool call stays rejected" test is adapted to the ceiling policy here (the rejection is recorded, then the truncation rescue lands instead of a digest).

Metadata

Cache-impact: none - healthy turns keep the provider-visible prefix byte-identical; the transcript-form summary request and the truncation projection exist only on the overflow failure path
Cache-guard: internal/boot/effect_compaction_test.go TestEffectSummaryOverflowShrinksNextSummaryThroughRealBuild; TestEffectRoleSettingsShareProviderToolSurface still pins the unified tool surface
System-prompt-review: SivanCola - no system prompt, memory, or skill text changes; the only internal/boot change is an effect test
Documentation-impact: updated - docs/SPEC.md and docs/SPEC.zh-CN.md now describe the overflow ladder, the truncation rescue, the 5% planning margin, and the same-turn backoff relief

@SivanCola
SivanCola requested a review from esengine as a code owner September 7, 2026 06:22
@github-actions github-actions Bot added v2 Go rewrite (1.x) — main-v2 branch, active development desktop Wails desktop app (desktop/**) agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) provider Model providers & selection (internal/provider) and removed v2 Go rewrite (1.x) — main-v2 branch, active development labels Sep 7, 2026
@SivanCola
SivanCola force-pushed the fix/compaction-overflow-recovery branch from bdc1354 to 96aa681 Compare September 7, 2026 07:02
@github-actions github-actions Bot added the v2 Go rewrite (1.x) — main-v2 branch, active development label Sep 7, 2026
…ling context

A summary request the provider rejects now feeds its real prompt count back
into calibration, re-plans a smaller prefix, then falls back to a bounded
transcript form and (manual only) the fragment path; chunk and merge retries
treat provider overflow as a size failure. Prefix planning keeps 5% of the
window as estimator headroom. At the ceiling, when no summary can form, a
truncate projection elides the oldest tool results and drops the oldest replay
units behind a marker instead of returning ErrCompactionRequired. Overflow
rescues may fold the active turn's completed rounds, and the same-turn backoff
lifts once the view has grown 5% of the window since the failed attempt. DeepSeek-style
chat adapters report that ordinary reasoning is replayed so admission counts
it. SPEC and the desktop maintenance notice follow.

Fixes esengine#9818
@SivanCola
SivanCola force-pushed the fix/compaction-overflow-recovery branch from 96aa681 to 5412140 Compare September 7, 2026 07:59
@SivanCola
SivanCola merged commit 3289e23 into esengine:main-v2 Sep 7, 2026
31 of 33 checks passed
SivanCola added a commit to SivanCola/DeepSeek-Reasonix that referenced this pull request Sep 7, 2026
Integrate the reviewed context-overflow recovery changes from esengine#9882 and esengine#9879. Preserve the kernel-reduced startup graph rather than restoring the pre-kernel raw budget.

The integrated build measures 2,438,339 raw bytes (2381.190 KiB), 186 bytes above the repaired PR head. Set only the raw ceiling to 2381.2 KiB; all gzip, CSS, locale and largest-chunk gates remain unchanged.

Validation: frontend build, test typecheck, context-maintenance notice tests, agent/control/provider/boot Go tests and repolint passed. Transcript measurement and session-command production repairs are unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) desktop Wails desktop app (desktop/**) provider Model providers & selection (internal/provider) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: v1.37.0 上下文压缩失败,上下文窗口突然爆满溢出

1 participant