Compaction preserves the loop and drops the substance - #544
Open
TheGreatAxios wants to merge 4 commits into
Open
Compaction preserves the loop and drops the substance#544TheGreatAxios wants to merge 4 commits into
TheGreatAxios wants to merge 4 commits into
Conversation
Errored tool_results scored above the anchor threshold on their own, so a failing-edit retry loop anchored every iteration verbatim while healthy context got summarized away. Score errors below threshold and collapse runs of the same repeating error to one representative before scoring. Pairing anchors were pulled in with no cap, making maxAnchorTurns not a real bound; the scored-anchor selection now takes each candidate's pair closure whole-or-nothing against a shared budget. The summary prompt seeded from the last 8 assistant snippets, which during degeneration is the looped text itself; filter snippets flagged by the existing detectRepetition detector before they reach the summarizer. Superseded-result stubbing only covered read_file; extend it to grep, search_files, and list_dir (byte-identical arguments), excluding run_shell since the same command is not idempotent. CompactorConfig.summarize was typed with one argument even though the summarizer already accepted a workflow context, so the context never made it through; widen the type and thread cfg.summaryContext() into the call. Replace the bare catch in the model summarizer with a logged warning and a fallback marker so a failed LLM summary is distinguishable from a real one.
The TUI wrapped summarize to inject the active workflow, but the pruning compactor always called summarize with one argument, so mid-workflow compaction still lost the step contract. Also make the max-anchor fixture score above the new threshold so the cap test actually exercises it.
Main's repetition detector now needs sixteen consecutive repeats, so ten copies of the loop phrase no longer trip it. Twenty copies still flag, and the Unreleased changelog records the compaction-quality pass.
2 tasks
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 free
to 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.
DO NOT AUTO-MERGE
This touches context-management (compaction/summarization), which is human-gated in this repo. It carries
needs-sawyer-reviewand must wait for Sawyer's manual review and approval before merging. Do not squash-merge, auto-merge, or merge on green CI alone.Summary
src/session/compactor.tsanchored every erroredtool_result(score +5, threshold 5) regardless of whether it repeated, so a failing-edit retry loop got preserved verbatim past the summary boundary while healthy context was summarized away. Pairing anchors were then pulled in with no cap, somaxAnchorTurnswas not a real bound.src/session/summarizer.tsseeded its summary prompt from the last 8 assistant snippets, which during degeneration is the looped text itself, and silently swallowed summary failures in a bare catch.Changes
condenseTurnsnow drops assistant snippets flagged by the existingdetectRepetition(fromsrc/subagent/repetition.ts) before they reach the summarizer — no new detector written.maxAnchorTurns. Scored-anchor selection now takes each candidate's tool_call/tool_result pair closure whole-or-nothing against a shared budget, so the cap is a real bound. Partners of turns that straddle the recent-window boundary are still pulled in unconditionally (required for a well-formed tool sequence) and count against the same budget; the initiating task remains an explicit, documented exception outside the cap, as before.read_filealready used for path identity.run_shellis deliberately excluded: the same command is not idempotent (builds, tests, mutations), so an older run_shell result can be the only record of a genuinely distinct outcome.CompactorConfig.summarizenow accepts the optional workflow context and actually receives it.summarizer.tsalready supported aSummaryContextparameter, but the compactor calledsummarizewith one argument, so it was alwaysundefined. AddedsummaryContexttoCompactorConfigand threaded it through. The bare catch increateModelSummarizeris replaced with a logged warning and both failure paths (empty output, thrown error) now prefix the deterministic fallback with[Model summary unavailable (...)]so a lossy fallback is distinguishable from a real model summary.Each item has a regression test in
src/context-compactor.test.ts,tests/unit/compactor-pairing.test.ts, andtests/unit/summarizer.test.ts.Test plan
bunx prettier --checkandbunx eslinton all touched files — eslint reports the same count/kind of pre-existing errors as the untouched baseline (a known repo-wide issue); no new violations introduced.bun run typecheck— clean.bun run build— clean.bun test ./src ./tests ./evals— 5127 pass, 1 fail (src/agent/lsp-availability.test.ts, pre-existing and unrelated — fails identically onmainin this worktree because it's a git worktree checkout, not a.gitdirectory).Fixes CL-6906