Repository navigation
feat(agent): pin, unpin and drop turns, and keep pins out of compression - #307
Merged
Merged
Conversation
B5's first slice. Context management had one strategy: keep the first two user groups, keep the last two, summarize everything between, with no way to say "keep this" or "drop that". - `types.Message.Pinned` marks a message; `Agent.PinLast` / `UnpinLast` / `DropLast` work in *turns* — a user message plus everything up to the next, the same grouping the compressor uses — and report what they touched. - `compressHistory` never feeds a pinned group to the summarizer and re-inserts it verbatim after the summary. A middle that is entirely pinned costs no provider call and leaves the history alone. - `/pin [n]`, `/unpin [n]`, `/drop [n]` in the TUI, refused while a run is active for the same reason `/compress` is: they replace Agent.History while the run goroutine may append to it. - `/drop` shapes the live context only. The session file is the record `--resume` reads, so the command says so rather than quietly deleting from it. A pin is honoured for the life of the session; carrying it through the UI transcript into the session file is S2 of #306, with the run-level compaction D7 depends on. Two things the tests taught me, both worth keeping: - the first version of the compression test pinned turn 3 of 6, which lands in the *head* — the region that is kept regardless. It passed with pin handling disabled. The test now uses eight turns and pins a real middle turn, and the mutation (pinning switched off) fails it with "the pinned turn was fed to the summarizer". - `DropLast` copies the retained prefix instead of truncating in place: history slices are shared with any goroutine reading them. Verified: go test ./... -count=1, 16 packages ok; go vet and gofmt clean; the pin path mutation-checked as above. Refs #306, #168
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.
What changed
types.Message.Pinned— a pin rides on the message, so the compressor can see it.agent/context.go:PinLast(n)/UnpinLast(n)/DropLast(n)/PinnedTurns()over turns (auser message plus everything up to the next — the grouping
compressHistoryalready works in).DropLastcopies the retained prefix rather than truncating in place, because history slices areshared with goroutines reading them.
agent/compression.go: a pinned group is never fed to the summarizer and is re-inserted verbatim afterthe summary; a middle that is entirely pinned returns the history unchanged with no provider call.
/pin [n],/unpin [n],/drop [n], palette entries,/helplines, and the same"a run is in progress" refusal
/compresshas.CODEBASE.md(compression step 5, newcontext.gosection), roadmap B5 → In progress — [agent] Give context management turn-level control: pin, unpin, drop #306(S1 landed, S2/S3 open), palette goldens, test count 1237 → 1249.
Why
The compressor had two settings — summarize the middle, or raise the threshold until nothing is
compressed — and no per-turn control.
/dropis context shaping, not deletion: the session file is what--resumereads, so the command says it leaves the record alone. Pins are the other half: a turn a usermarked is kept verbatim, and the summarizer never sees it.
Verification
go test ./... -count=1→ 16 packagesok;go vetandgofmt -lclean.if falsearoundgroupPinned) →TestCompressionKeepsPinnedGroupsVerbatimfails withthe pinned turn was fed to the summarizer;restored, it passes.
sits in the head — the region kept regardless — so it passed against the mutation. It now uses
eight turns and pins a middle turn, so the assertion is about the path it claims to test.
agent/context_test.go(pin/unpin/drop counts and effects, the pinned group keptverbatim and absent from the summarizer, the fully pinned middle costing nothing) and 7 in
tui/context_command_test.go(each command, counts, empty history, the run guard, the palette).git log --format='%h %G? %s'→G.Honest scope
persistSessionrebuilds the stored messages fromm.messages, so theflag has to travel through the UI transcript to survive a resume. That is S2 of [agent] Give context management turn-level control: pin, unpin, drop #306, together with
the run-level compaction D7 depends on.
compressHistorystill runs only at the start of a run. A long round grows until the providerrefuses — the gap S2 exists for.
becomes meaningful.
Follow-ups
Refs #306, #168