fix(agent-core-v2): pre-shrink compaction history to the effective model window - #3911
Conversation
🦋 Changeset detectedLatest commit: b6ad5d4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b6ad5d4b3c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
🔵 Needs a closer look
It changes core compaction request-sizing behavior in the agent engine affecting reliability and cost for all long sessions, relying on heuristic token-budget math that warrants final human review.
Pull request overview
This PR fixes a compaction failure that occurs after switching from a large-context model to a smaller-context one: the first summary request previously always sent the entire (now over-window) history, which was guaranteed to overflow and could leave the session stuck. The change proactively pre-shrinks the history to an input budget derived from the current model's effective window before issuing the first summary request, while leaving the existing reactive overflow-shrink chain as a fallback. This is a core agent-core-v2 compaction-path change that surfaces to CLI users as improved reliability.
Changes:
- Add
preShrinkHistoryToWindowBudgetand call it before the compaction request loop, folding any pre-dropped messages into the existingdroppedCount. - Budget =
floor((effectiveWindow − outputReserve) × 0.85) − requestOverhead, reusing the existing "keep recent messages within token budget" trimmer; unknown window (≤ 0) skips pre-shrink. - Update one existing test to assert the pre-shrunk first request and add a new
FullCompaction pre-shrinksuite; add apatchchangeset.
File summaries
| File | Description |
|---|---|
packages/agent-core-v2/src/agent/fullCompaction/fullCompactionService.ts |
Adds the pre-shrink budget computation and applies it to the summary history before the first request, updating droppedCount. |
packages/agent-core-v2/test/agent/fullCompaction/fullCompaction.test.ts |
Updates the over-window test and adds a suite covering pre-shrink, budget/overhead accounting, dropped-count, reactive fallback, unknown window, and oversized-tail cases. |
.changeset/compaction-pre-shrink.md |
Adds a patch changeset for @moonshot-ai/kimi-code with a single user-facing sentence. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Compaction pre-shrinks the summarizer's history to the model's effective window before the first request (MoonshotAI#3911), replayed thinking on OpenAI-compatible transports rides the declared `reasoning_key` (MoonshotAI#3910), the catalog endpoints expose each provider's resolved `base_url` (MoonshotAI#3909), usage telemetry fires for the swarm transition, external hooks, remote-control toggles and tower entry/exit (MoonshotAI#3897), a steered message carries its prompt's identity end to end (MoonshotAI#3906 / MoonshotAI#3891), and the rating survey payload gains the per-turn trace id plus copilot statistics (MoonshotAI#3907).
Deep-check finding: v2's compaction loop (fullCompactionService.ts:690-710) recovers when the summarization request ITSELF overflows — the pre-shrink (MoonshotAI#3911) is an estimate, and a provider that counts tokens differently can still refuse the request. v2 shrinks the history to COMPACTION_OVERFLOW_SHRINK_RATIOS[attempt-1] (0.7 / 0.5 / 0.35, at most MAX_COMPACTION_OVERFLOW_SHRINK_ATTEMPTS = 3 times, sharing the attempt cap and the len <= 1 guard) and retries. The fork had the pre-shrink and the empty-summary drop-oldest path, but an overflow error is not in the retryable set, so the compaction failed outright. The Err branch now runs the overflow gate first (estimating the outgoing prompt the way v2's requestTokens does), shrinks through the existing take_recent_within_budget, and continues without backoff. Known remaining difference (not ported): v2's observeContextOverflow learns the effective window from observed overflows; the fork's window is host-resolved, so there is no per-model learning state to feed. Tests: shrink-and-retry drops the oldest and keeps the newest; the give-up path surfaces the original error after exactly 1 + 3 requests.
* feat(kimi-code): carry turn trace id and copilot stats in rating surveys (MoonshotAI#3907) * feat: expose resolved base_url on models.dev catalog provider items (MoonshotAI#3909) * fix(agent-core-v2): restore thinking for the openrouter reasoning dialect (MoonshotAI#3910) Keep string reasoning fields when a reasoning_details array is present, stamp each think part by source, and replay those fields on the next request. * ci: release packages (MoonshotAI#3862) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * docs(changelog): sync 2.0.1 from apps/kimi-code/CHANGELOG.md (MoonshotAI#3912) * fix(agent-core-v2): pre-shrink compaction history to the effective model window (MoonshotAI#3911) * fix(vscode): ignore Enter during IME composition in question dialog (MoonshotAI#3915) * fix(kap-server): deliver session-level interaction events past agent filters (MoonshotAI#3901) * revert(kap-server): drop the flat entity message protocol (v3 WS + history API) (MoonshotAI#3532) (MoonshotAI#3920) This reverts 64505e3. The v1 WS + legacy REST + transcript surfaces are alive on main and remain the single protocol surface; kimi-inspect returns to the transcript-based data model (keeping MoonshotAI#3747's removal of the prompt input, which adapted to the agent-core-v2 prompt-queue fold). * feat(oauth): parse goods_version from the managed /me profile payload (MoonshotAI#3921) * fix: keep turn ids above the wire-wide max and fold cold transcripts over the active branch (MoonshotAI#3922) * fix(agent-core-v2): floor the human turn clock at the wire-wide max on engine journal reset * fix(kap-server): fold the cold transcript snapshot over the restorable branch chain * fix(agent-core-v2): advance the human turn clock when a turn starts * fix(kap-server): split reused wire turn ids in the live transcript projector * fix(kap-server): adopt the completed cold tip for mid-turn attach events Continuation deltas after a lazy transcript attach belong on the last cold turn, not a newly split export id. * fix(agent-core-v2): remove the project-root assertion for cwd from the system prompt (MoonshotAI#3929) Co-authored-by: 7Sageer <7sageer@djwcb.cn> * chore: remove the tdd skill (MoonshotAI#3932) * fix(agent-core-v2): don't record turn.steer when an unconsumed steer seeds the next turn (MoonshotAI#3933) * chore: sync web dist from code-app (MoonshotAI#3934) * chore: sync web dist from code-app code-app: 44d7281c7a63ee3c7a907f9406e490efdbec7411 * chore: collapse web dist sync changesets into one summary entry * ci: release packages (MoonshotAI#3913) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * feat: generate native Kimi ACP session titles (#15) --------- Co-authored-by: Grapedge <shiwang.lj@alibaba-inc.com> Co-authored-by: liruifengv <liruifeng1024@gmail.com> Co-authored-by: Haozhe <yanghaozhe@moonshot.ai> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: 7Hanrui <qihanrui@moonshot.ai> Co-authored-by: 7Sageer <7sageer@djwcb.cn> Co-authored-by: Zixuan Chen <remch183@outlook.com>
Related Issue
No tracking issue — internal spec-driven fix (compaction pre-shrink).
Problem
After accumulating a conversation larger than a small-window model can hold (e.g. ~300k tokens on a 1M-window model), switching to a smaller-window model (e.g. 256k) makes compaction fail: the first summary request sends the entire oversized history to the current model, which is guaranteed to overflow. Whether compaction recovers depended entirely on the provider's error text being classified as context overflow — otherwise the first request failed directly with
compaction.failed, leaving the session stuck (context still oversized, every next message re-triggering the same failing auto-compaction chain).This affected all compaction triggers (manual /compact, pre-step water level, post-step check, turn overflow recovery) since they share one summary path.
What changed
Before sending the first summary request, compaction now proactively computes an input budget from the current model's effective context window and pre-shrinks the history to fit:
getEffectiveMaxContextTokens()(min of configured capability and the per-alias observed overflow learning value); unknown window (≤ 0) skips pre-shrink entirely, preserving current behavior.min(compaction output cap, floor(window / 8))so the summary output is never clamped to zero; request overhead: the existingrequestTokens([])estimate (system prompt + tools); safety factor: the existingOVERFLOW_CONTEXT_SAFETY_RATIO.droppedCountfield.One existing test (
auto-compacts very large context in one full-history round) asserted the old "first request always sends full history" behavior for an over-window context; it now asserts the intended pre-shrunk first request.Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.