Uh oh!
There was an error while loading. Please reload this page.
feat: runtime-owned context compaction defaults across surfaces - #1018
Merged
Conversation
The mid_turn capacity invariant becomes a runtime-owned default: whenever history compaction is enabled the runtime derives midTurn from the selected model window (contextWindow - reserve), so Desktop, TUI, and headless inherit it without copying config. MAKA_CONTEXT_HISTORY_COMPACT_MID_TURN=off stays as the explicit escape hatch. The backend still gates activation on the checkpoint seams, the persisted head anchor, and a KNOWN context window, so a session without model metadata or a child session with no anchor seam never misfires even though the default is on (covered by new backend safety guards). Refs #882
Semantic compaction is the #981/#986 attention-first experiment, not the standard historyCompact mechanism. Make the runtime the owner of its default: it stays off unless a surface explicitly opts in (MAKA_CONTEXT_SEMANTIC_COMPACT truthy, or a non-off MAKA_CONTEXT_SEMANTIC_COMPACT_MODE). This lets the CLI drop its local semanticCompact strip and eat the runtime default directly, so the surfaces stop duplicating the same off decision. Desktop and headless inherit the off default without any per-surface wiring. Refs #882
Wire buildDefaultContextBudgetPolicy — the exact default every surface now inherits — into the streaming backend and prove a long turn near the window engages mid-turn compaction and continues to a clean end rather than being truncated or surfacing a raw provider error. The fake-backend Playwright suite cannot exercise this path: it is a separate canned-event backend that never runs AiSdkBackend's prepareStep machinery, so a desktop E2E could only fake the very compaction under test. This deterministic runtime-layer test is the honest representative journey for the proactive path. Refs #882
The flat 16384 reserve assumed large-window models: on gpt-4 (8192 window) the default policy derived maxHistoryEstimatedTokens = max(1, 8192 - 16384) = 1 — a pre-existing turn-boundary pathology on main — and with mid_turn now on by default the 1-token high water made every multi-step turn run the summarizer for a checkpoint the replay gate could never admit. Make defaultCompactReserveTokens the single owner of the reserve default, bounded by the KNOWN window: min(16384, floor(window / 4)), so both the turn-boundary budget and the mid_turn high water derive from one value (8K window -> 2048 reserve / 6144 budget; >= 64K windows byte-identical to before; unknown window keeps the classic constant). An explicit MAKA_CONTEXT_HISTORY_COMPACT_RESERVE_TOKENS is respected verbatim. Peers bound the same way: opencode caps its compaction buffer by the model's output limit, gemini-cli triggers at a window fraction; pi shares the flat-16384 blind spot. Strengthen the shipped-defaults journey to fully-default derivation with durable-persistence assertions (checkpoint recorded, compact block present, replaced raw span gone), and add the unrescuable path: under the derived default a turn with no safe span ends with the explicit context_budget_exhausted outcome. A small-window guard locks the P2 behavior: on an 8K model the default is completely inert when under budget — never a pointless summarizer call. Refs #882
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refs #882 (PR 3 of 3, per the split in #882 (comment); #996 landed the proactive machinery, #1017 the reactive recovery).
Context-budget defaults were owned per surface: the CLI carried its own policy builder, desktop shipped semantic compaction on by default while the CLI required an opt-in, and mid-turn capacity compaction was dark everywhere. This PR sinks the defaults into the runtime's
buildDefaultContextBudgetPolicyso every surface ships the same behavior:MAKA_CONTEXT_HISTORY_COMPACT_MID_TURN=offopts out).MAKA_CONTEXT_SEMANTIC_COMPACT=onopts in) — the runtime default is the owner, so desktop's previous on-by-default flips without a desktop change.defaultCompactReserveTokens):min(16384, window/4), feeding both the turn-boundary history budget and the mid-turn high water. This also fixes a pre-existing pathology on main: the flat 16384 reserve on an 8K-window model derivedmaxHistoryEstimatedTokens = 1, and with mid-turn on it would have run the summarizer every multi-step turn for a checkpoint the replay gate could never admit. On an 8K model the default is now completely inert below the high water — never a pointless summarizer call. ≥64K windows are byte-identical to before; an explicitMAKA_CONTEXT_HISTORY_COMPACT_RESERVE_TOKENSis respected verbatim; an unknown window keeps the classic constants. Peers bound the same way (opencode caps its buffer by the model's output limit, gemini-cli triggers at a window fraction).Verification
npm --workspace @maka/runtime test: 1936 tests, 0 fail (7 pre-existing skips). New coverage: policy derivation matrix (8K → 2048/6144, ≥64K unchanged, unknown window, explicit override), semantic-compact default-off policy tests, a small-window guard (default never runs a pointless summarizer on an 8K model), and a shipped-defaults journey with no env overrides — a long turn under the derived default persists amid_turncheckpoint, the continued request carries the compact block without the replaced raw span, the anchor stays verbatim, and the unrescuable path ends with the explicitcontext_budget_exhaustedoutcome.npm run typecheckandnpm run build: clean.prepareStep, so a renderer-level test would fake the machinery under test; the runtime-level journey with the real shipped policy is the honest seam. A reactive-path (provider overflow) cross-surface E2E needs a real-backend harness and is tracked as follow-up in feat(runtime): compact active turns before context exhaustion #882.Review focus
buildDefaultContextBudgetPolicyis the single owner of shipped context-budget defaults: surfaces consume it and may only override with explicit user-facing configuration. If a surface needs different behavior, the knob belongs in the shared derivation, not in a surface-local builder.