feat: add compaction_agent for customizable context compression#288
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 32 minutes and 43 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (12)
📝 WalkthroughWalkthroughAdds a configurable Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant REPL/TUI as REPL/TUI
participant Config as Config
participant AgentStore as AgentStore
participant Agent as CompactionAgent
participant Session as Session
participant Input as Input
participant Client as Client
participant Retry as RetryLogic
REPL/TUI->>Config: request maybe_compact_session()
Config->>Session: get active session & compaction_agent
alt compaction_agent set
Config->>AgentStore: retrieve_agent(name)
AgentStore-->>Config: Agent (may need resolve_variables)
Config->>Agent: resolve_variables()
Agent-->>Config: resolved agent
else no compaction_agent
note right of Config: use DEFAULT_COMPACT_PROMPT
end
Config->>Input: build Input (history preserved)
alt agent override present
Config->>Input: set_agent(compaction agent)
end
Input->>Retry: call_with_retry_and_fallback(Input, abort_signal)
Retry->>Client: attempt chat completion(s)
Client-->>Retry: chat text
Retry-->>Input: chat text
Input->>Session: session.compress(chat text) / write summary
Session-->>Config: mark saved
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.changesets/compaction-agent.md:
- Around line 1-4: Update the changeset frontmatter from "minor" to "major" and
expand the note to explicitly call out the breaking changes: that the `.compress
session` command/alias has been removed (no compatibility alias) and the
`summarize_prompt` / `summary_prompt` fields were deleted; ensure the changeset
(compaction_agent) clearly states that context compression now uses the
`compaction_agent` field and that users must migrate any workflows relying on
the removed `.compress session` or prompt fields.
In `@src/config/mod.rs`:
- Around line 1645-1648: The compaction agent's variables must be resolved
before calling interpolated_instructions: change the Ok arm to make
compaction_agent mutable, invoke the code path that hydrates file-backed/default
variables and populates shared_variables on that agent (e.g., call the existing
resolver like hydrate/resolve_agent_variables on config.read() or a similar
helper) and only then call compaction_agent.interpolated_instructions(); return
(prompt, Some(compaction_agent)) after hydration so no {{...}} placeholders
remain.
- Line 1661: When swapping in the compaction_agent you must preserve the current
session instead of forcing with_session = false; change the call pattern around
Input::from_str(resolve) so swapping the agent does not drop history—either call
Input::from_str without passing Some(compaction_agent) and then set the agent on
the resolved Agent while leaving with_session true, or update resolve_agent so
that when agent_override == compaction_agent it still returns with_session =
true; update the code that currently passes Some(compaction_agent) into
Input::from_str to use one of these approaches so chat history is retained
during compaction.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5c5d489d-6295-45d3-a2ac-c66957499d7b
📒 Files selected for processing (7)
.changesets/compaction-agent.mdexample_config/agents/example-agent.mdsrc/config/agent.rssrc/config/input.rssrc/config/mod.rssrc/repl/mod.rssrc/tui/prompt.rs
| --- | ||
| harnx: minor | ||
| --- | ||
| Add `compaction_agent` field to agent config. When set, context compression uses that agent's model, system prompt, and parameters instead of the global defaults. |
There was a problem hiding this comment.
This changeset should be major, not minor.
This PR removes .compress session without a compatibility alias and deletes summarize_prompt / summary_prompt, so the release is breaking. Please bump the changeset and mention those removals in the note.
Based on learnings, "Create a changeset file in .changesets/ for every user-visible change with YAML front matter specifying version bump (patch, minor, or major)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.changesets/compaction-agent.md around lines 1 - 4, Update the changeset
frontmatter from "minor" to "major" and expand the note to explicitly call out
the breaking changes: that the `.compress session` command/alias has been
removed (no compatibility alias) and the `summarize_prompt` / `summary_prompt`
fields were deleted; ensure the changeset (compaction_agent) clearly states that
context compression now uses the `compaction_agent` field and that users must
migrate any workflows relying on the removed `.compress session` or prompt
fields.
a2dad9f to
3176e44
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/config/mod.rs (2)
2178-2199: Addcompaction_agent(andmodel_fallbacks) to.setautocompletion.
Config::updatenow acceptscompaction_agent(line 936) but the.setcompletion list here doesn't advertise it, so REPL users won't discover it via tab-complete.model_fallbacksappears to have the same pre-existing gap.♻️ Proposed addition
".set" => { let mut values = vec![ "temperature", "top_p", "use_tools", + "model_fallbacks", + "compaction_agent", "save_session", "compress_threshold",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/config/mod.rs` around lines 2178 - 2199, The `.set` autocompletion list in src/config/mod.rs is missing the new keys; update the vector initialized in the ".set" arm to include "compaction_agent" and "model_fallbacks" (so they get sorted and mapped like the other keys), ensuring the existing sort_unstable and map-to-(format!("{v} "), None) behavior is preserved; this aligns the autocompletion with Config::update (which already accepts compaction_agent) and makes those options discoverable in the REPL.
1608-1637: Mixed terminology — external rename to "compact" but internalSessionAPI still uses "compress".
maybe_compact_session/compact_session/is_compacting_sessionwere renamed, but they still drivesession.set_compressing(true),session.compressing(),session.need_compress(...), and logSessionLogEntry::Compress. This is defensible for log-format backward compat (existing session files on disk containtype: compress), but the in-memorySessionmethods have no such constraint. Consider renaming the internal setters/getters to match (set_compacting/compacting/need_compact) and keeping only the serde#[serde(rename = "compress")]to preserve file format — otherwise future readers will have to mentally translate.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/config/mod.rs` around lines 1608 - 1637, The code mixes external "compact" terminology with internal Session APIs named "compress"; rename the in-memory Session API to use "compact" (e.g., change session.set_compressing -> set_compacting, session.compressing() -> compacting(), session.need_compress(...) -> need_compact(...)) and update all call sites (e.g., maybe_compact_session, Config::compact_session, is_compacting_session, tokio spawn closure) to use the new names, but preserve on-disk compatibility by keeping serde renames (add or keep #[serde(rename = "compress")] on the serialized field/enum such as SessionLogEntry::Compress or the Session struct field) so file format stays unchanged.src/config/session.rs (1)
938-946: Duplicates logic that already lives inAgent::build_messages.The prompt-prepending logic here is a partial re-implementation of
Agent::build_messages(seesrc/config/agent.rs:525-555), but missing thetools_textmerging that the real method performs. If an agent with bothinterpolated_instructions()andtools_text()is used as a compaction override, this branch will send only the instructions and silently drop the tools block.Consider delegating: e.g., call
input.agent().build_messages(input)to generate the system message, then splice in the existing session history before the trailing user message, so both methods stay in lockstep.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/config/session.rs` around lines 938 - 946, This code duplicates Agent::build_messages by only inserting interpolated_instructions() and omitting tools_text(), which can drop the tools block when an agent is used as a compaction override; replace the manual prompt-prepend branch (the input.with_agent() block that calls input.agent().interpolated_instructions()) with a call to input.agent().build_messages(input) to produce the full system message(s) (including tools_text), then merge/splice those returned system messages into messages before the trailing user message so you reuse Agent::build_messages and keep both methods in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/config/mod.rs`:
- Around line 3690-3714: The test mutates HARNX_CONFIG_DIR using unsafe
std::env::set_var/remove_var which leaks on panic; replace that pair with a
panic-safe RAII guard (e.g., EnvVarGuard::new("HARNX_CONFIG_DIR", temp.path()))
that saves the previous value and restores/removes it in Drop, then remove the
unsafe remove_var call; update this test around the
Config::compact_session(&config).await.unwrap() invocation to create the guard
before invoking MockClient/TestStateGuard and let Drop handle cleanup, or
alternatively mark the test serial (serial_test) if you prefer to avoid
concurrent env mutation.
In `@src/config/session.rs`:
- Around line 930-948: Session::build_messages currently always inserts
input.agent().interpolated_instructions() at messages.insert(0, ...) when
need_add_msg and input.with_agent(), causing duplicate System messages on turns
after the first; change the logic to first check messages.first() and only
prepend the System message if either messages is empty or the first message is
not a System with the same text—use input.agent().interpolated_instructions() to
compute the prompt and compare to the existing Message::System content before
inserting to avoid duplicate system messages (keep the existing insertion path
for cases where the agent differs or no equivalent System exists).
---
Nitpick comments:
In `@src/config/mod.rs`:
- Around line 2178-2199: The `.set` autocompletion list in src/config/mod.rs is
missing the new keys; update the vector initialized in the ".set" arm to include
"compaction_agent" and "model_fallbacks" (so they get sorted and mapped like the
other keys), ensuring the existing sort_unstable and map-to-(format!("{v} "),
None) behavior is preserved; this aligns the autocompletion with Config::update
(which already accepts compaction_agent) and makes those options discoverable in
the REPL.
- Around line 1608-1637: The code mixes external "compact" terminology with
internal Session APIs named "compress"; rename the in-memory Session API to use
"compact" (e.g., change session.set_compressing -> set_compacting,
session.compressing() -> compacting(), session.need_compress(...) ->
need_compact(...)) and update all call sites (e.g., maybe_compact_session,
Config::compact_session, is_compacting_session, tokio spawn closure) to use the
new names, but preserve on-disk compatibility by keeping serde renames (add or
keep #[serde(rename = "compress")] on the serialized field/enum such as
SessionLogEntry::Compress or the Session struct field) so file format stays
unchanged.
In `@src/config/session.rs`:
- Around line 938-946: This code duplicates Agent::build_messages by only
inserting interpolated_instructions() and omitting tools_text(), which can drop
the tools block when an agent is used as a compaction override; replace the
manual prompt-prepend branch (the input.with_agent() block that calls
input.agent().interpolated_instructions()) with a call to
input.agent().build_messages(input) to produce the full system message(s)
(including tools_text), then merge/splice those returned system messages into
messages before the trailing user message so you reuse Agent::build_messages and
keep both methods in sync.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fe4b5504-03aa-402d-99cb-05ecb258bf31
📒 Files selected for processing (8)
src/client/stream.rssrc/config/agent.rssrc/config/input.rssrc/config/mod.rssrc/config/session.rssrc/rag/mod.rssrc/serve.rssrc/utils/mod.rs
✅ Files skipped from review due to trivial changes (3)
- src/client/stream.rs
- src/utils/mod.rs
- src/rag/mod.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- src/config/input.rs
- src/config/agent.rs
…xt compression Persists the compaction_agent field in session logs so that session.to_agent() reconstructs the agent with compaction settings intact. This enables runtime modification of compaction behavior and ensures consistent behavior across session restarts. Key changes: - Persist compaction_agent in session logs. - Add .set compaction_agent command for runtime modification. - Injects system prompt (including tools) for agent overrides with session history, using a new inject_system_prompt flag on Input to prevent duplicates. - Resolves file-backed variables on compaction agent before interpolation. - Preserves session history during compaction agent calls. - Adds RAII EnvGuard for panic-safe environment variable management in tests. - Updates .set autocompletion for compaction_agent and model_fallbacks. - Cleans up clippy warnings for Rust 1.95. Aristarchus approved. Issue: none tartarus-plan: compaction-agent-session-persistence
9accb8b to
5456982
Compare
Summary
Add
compaction_agentfield to agent config. When context compaction triggers (auto or manual via.compact session), if the current agent hascompaction_agentset, the referenced agent's model, system prompt, and inference parameters are used for the compaction LLM call instead of the hardcoded default.Closes #216
Changes
New:
compaction_agentfield on agent configcompaction_agent: my-compactorin agent YAML frontmatterRenamed:
.compress session→.compact sessioncompress_session→compact_session,maybe_compress_session→maybe_compact_session,is_compressing_session→is_compacting_sessionRemoved:
summarize_promptandsummary_promptconfig fieldssummarize_prompt(the instruction sent to LLM) — replaced by compaction agent's promptsummary_prompt(prefix prepended to stored result) — removed entirely, the LLM response is stored as-isImproved:
fetch_chat_textnow uses retry + fallbackclient.chat_completions()tocall_with_retry_and_fallback()model_fallbacksandretryconfigfetch_chat_textcallersTesting
compaction_agentfield (parse, unset, round-trip)cargo fmt && cargo build && cargo clippy -- -D warnings— cleanSummary by CodeRabbit
New Features
Refactor