feat: /compact — provider compaction + summary banner#107
Conversation
- Add thread.context.compact + thread.context.summarize command schemas - Add thread.context-compacted + thread.context-summarized event schemas - Add optional summary field to ContextTrimPoint and ThreadContextTrimCommand - Decider: validate and emit events for compact and summarize commands - Decider: include summary in trim point when provided via thread.context.trim - ProviderAdapter: add compactThread method to interface - CodexSessionRuntime: implement compactThread via thread/compact/start RPC - Claude/OpenCode/Cursor adapters: return unsupported error for compactThread - ProviderService: delegate compactThread to adapter - ProviderCommandReactor: process thread.context.compact — call provider, emit summarize + trim - Composer: parse /compact, register in autocomplete, dispatch in ChatView - ContextSummaryBanner component: blue-tinted 'Context compacted' callout - MessagesTimeline: render summary banner above trim divider when summary present - Tests: contracts schemas, decider validation, composer parsing
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8955033a19
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ( | ||
| (itemType === "compaction" || itemType === "context_compaction") && | ||
| "encrypted_content" in (item as Record<string, unknown>) |
There was a problem hiding this comment.
Read the compaction summary from a reachable payload
When /compact succeeds for Codex, this scan reads thread/read turn items, but the generated Codex ThreadItem shape uses type: "contextCompaction" with only an id; the "compaction" / "context_compaction" variants with encrypted_content are response-item shapes, not what parseThreadSnapshot() returns. In practice this leaves summary as "" for every successful compaction, so the new trim summary and banner are never populated.
Useful? React with 👍 / 👎.
| yield* orchestrationEngine.dispatch({ | ||
| type: "thread.context.trim", | ||
| commandId: trimCommandId, | ||
| threadId, | ||
| summary: compactResult.summary, | ||
| createdAt: nowIso, |
There was a problem hiding this comment.
Avoid pruning turns created while compacting
After provider compaction finishes, this dispatch trims the current read model with no boundary or keepLastNTurns, while the earlier compact intent does not mark the thread busy. If a user submits and completes a turn during a long compaction, the provider summary was started before that turn but this later trim can still prune the new messages from the UI/read model; record the pre-compaction boundary or block/preserve turns created after compaction starts.
Useful? React with 👍 / 👎.
Summary
/compactcommand: provider-level compaction with duration tracking + summary banner/clear,/new, and/compactduring generation/newcommand: archives current thread, creates a new inheriting one/clear+/clear Ncore context trim infrastructureRuntimeMode.reviewtoggleTesting
decider.contextTrim(1027 lines) covering trim point creation, keepLastNTurns, active turn rejection, idempotent empty trimdecider.archiveAndNew(377 lines) covering archive-and-new flow, active turn guard, collision rejection