Skip to content

feat: LLM and User-controlled compaction via new_session tool#2333

Open
taoeffect wants to merge 11 commits intocharmbracelet:mainfrom
taoeffect:new_session_tool
Open

feat: LLM and User-controlled compaction via new_session tool#2333
taoeffect wants to merge 11 commits intocharmbracelet:mainfrom
taoeffect:new_session_tool

Conversation

@taoeffect
Copy link
Contributor

@taoeffect taoeffect commented Mar 1, 2026

This PR closes #2331 by adding:

  • A new_session tool that allows customizable compaction
  • A new compaction method switching menu to the UI
  • Injecting information about the remaining context into the system prompt when the compaction method is switched to LLM/user-driven
  • By default, the new_session tool is instructed to trigger at 75% context remaining. As a fallback, the auto-compaction remains enabled in case the LLM fails to trigger it.

I think this PR also closes #2240 because new_session can handle custom compaction instructions.

Screenshot_20260228_195641 Screenshot_20260228_195558
  • I have read CONTRIBUTING.md.
  • I have created a discussion that was approved by a maintainer (for new features).

Co-authored by Opus 4.6 using Crush.

Introduce a new agent tool that allows the LLM to create a fresh session
when working on long-running tasks, carrying forward a summary of
progress and remaining work. This prevents context exhaustion during
complex multi-step tasks.

The implementation spans four layers:

- Tool definition (`internal/agent/tools/new_session.go`): Defines the
  tool with a `summary` parameter and returns a sentinel
  `NewSessionError` that propagates up through the agent coordinator.

- Coordinator integration (`internal/agent/coordinator.go`): Registers
  the tool in `buildTools()` alongside existing tools.

- UI handling (`internal/ui/model/ui.go`, `internal/ui/chat/`): Catches
  `NewSessionError` in `sendMessage`, emits a `newSessionMsg` that
  creates a new session and auto-sends the summary as the first message.
  Adds a renderer for the tool's pending/completed states.

- Config allowlist (`internal/config/config.go`): Adds `"new_session"`
  to `allToolNames()` so the tool is not filtered out before being sent
  to the LLM provider. Updates corresponding test expectations.
Introduce a compaction method toggle (auto vs LLM/user-driven) that
controls how context window management works. In LLM mode, a
<context_status> block is injected each turn so the model can track
usage and invoke the new_session tool proactively. The setting is
selectable via the command palette and persists across sessions in
the data config.
- Use system role (not user) for context status message to avoid
  provider alternation violations and LLM misdirection
- Validate empty/whitespace summaries in new_session tool, returning a
  tool error so the LLM can retry instead of propagating an agent error
- Clamp used_pct to 100 and remaining_tokens to 0 consistently
- Document one-step token lag in contextStatusMessage
- Register new_session tool only when compaction method is LLM
- Normalize CompactionMethod zero value "" to "auto" in setDefaults
- Add trailing newline to new_session.md

Assisted-by: Claude via Crush <crush@charm.land>
@taoeffect taoeffect requested a review from a team as a code owner March 1, 2026 04:21
@taoeffect taoeffect requested review from Copilot, meowgorithm and raphamorim and removed request for a team March 1, 2026 04:21
@charmcli
Copy link
Contributor

charmcli commented Mar 1, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@taoeffect
Copy link
Contributor Author

I have read the Contributor License Agreement (CLA) and hereby sign the CLA.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds LLM/user-controlled context compaction by introducing a new_session tool, a new CompactionLLM mode, context-status injection into system prompts, and a UI dialog for switching between compaction modes. It closes issue #2331.

Changes:

  • Added new_session agent tool (returns a sentinel error to trigger UI-side session reset with a summary)
  • Added CompactionLLM compaction mode with context-status injection, and compactionFlags helper to derive disableAutoSummarize/disableContextStatus from config
  • Added Compaction dialog for selecting the compaction method, wired into the command palette

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/agent/tools/new_session.go New sentinel tool that signals session reset via NewSessionError
internal/agent/tools/new_session.md Tool description embedded in the tool for the LLM
internal/agent/tools/new_session_test.go Tests for the new tool
internal/agent/agent.go Migrated disableAutoSummarize to thread-safe csync.Value; added disableContextStatus field and SetCompactionFlags interface method; injects context-status system message per turn
internal/agent/coordinator.go Added compactionFlags helper, named field initialization, new_session tool conditional registration, and SetCompactionFlags call in UpdateModels
internal/agent/coordinator_test.go Updated mock to implement new SetCompactionFlags interface method
internal/agent/compaction_flags_test.go Tests for compactionFlags helper function
internal/agent/set_compaction_flags_test.go Tests for SetCompactionFlags and round-trip behavior
internal/agent/context_status_test.go Tests for contextStatusMessage method
internal/agent/common_test.go Updated testSessionAgent to use named struct fields
internal/config/config.go Added CompactionMethod type, CompactionAuto/CompactionLLM constants, Options.CompactionMethod field, SetCompactionMethod method, new_session in allToolNames
internal/config/load.go Added CompactionMethod default in setDefaults
internal/config/load_test.go Updated tool list assertions and added compaction method default test
internal/config/compaction_method_test.go Tests for SetCompactionMethod persistence and defaults
internal/ui/dialog/compaction.go New dialog for selecting compaction method
internal/ui/dialog/actions.go Added ActionSelectCompactionMethod action
internal/ui/dialog/commands.go Added "Select Compaction Method" to the command palette
internal/ui/model/ui.go Handles newSessionMsg, ActionSelectCompactionMethod, and opens compaction dialog
internal/ui/chat/new_session.go New chat UI renderer for the new_session tool call
internal/ui/chat/tools.go Wires NewSessionToolName to NewNewSessionToolMessageItem
.gitignore Added project-local working files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Handle NewSessionError specially in agent.Run() error dispatch to avoid
persisting a spurious "Provider Error" finish entry. Update new_session.md
to document the context_window field in the context_status payload.
@taoeffect taoeffect changed the title LLM and User-controlled compaction via new_session tool feat: LLM and User-controlled compaction via new_session tool Mar 1, 2026
…g files across sessions

The file history system hit a UNIQUE constraint violation on
(path, session_id, version) when the same file was edited in multiple
sessions — particularly after the new_session tool created a fresh
session that re-edited files from a prior session.

Two bugs were identified:

1. CreateVersion() used ListFilesByPath which queried ALL sessions for a
   file path, then picked max(version)+1 globally. But the UNIQUE
   constraint is per-session, so version numbers from session A leaked
   into session B, causing sparse versions and eventual collisions.

2. Create() always hardcoded version 0 (InitialVersion). The retry loop
   only attempted 3 increments (0, 1, 2), so if those versions already
   existed for (path, session_id), it exhausted retries and failed.

The fix:
- Add a ListFilesByPathAndSession SQL query scoped to a single session.
- Change CreateVersion() to use the session-scoped query so version
  numbers are independent per session.
- Make Create() delegate to CreateVersion() so it always picks the
  correct next version instead of hardcoding 0.
- Add regression tests covering both bugs plus basic version semantics.
Wrap goose.SetBaseFS and goose.SetDialect in sync.Once to prevent
concurrent writes to package-level globals when parallel tests each
call db.Connect.

Assisted-by: Opus 4.6 via Crush <crush@charm.land>
compactionFlags() was returning disableAutoSummarize=true for CompactionLLM
mode, which completely disabled the StopWhen auto-compaction check. This meant
that if the LLM failed to call new_session (expected at ~75% context usage),
there was no fallback — context would silently overflow. Now auto-summarize
stays enabled in LLM mode so it kicks in at 80% as a safety net.

Assisted-by: Claude via Crush <crush@charm.land>
@taoeffect
Copy link
Contributor Author

Updated behavior and edited the PR description to add:

  • By default, the new_session tool is instructed to trigger at 75% context remaining. As a fallback, the auto-compaction remains enabled in case the LLM fails to trigger it.

@taoeffect
Copy link
Contributor Author

One question I have for @andreynering: should it keep/remember the permissions granted from the current session when the new_session tool is called, or reset them as it currently does?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Better tools for long-term work: detecting remaining context + new_session tool for AI Crush clears the context losing all work

3 participants