Skip to content

feat: add compaction_agent for customizable context compression#288

Merged
dobesv merged 1 commit into
mainfrom
customize-compression
Apr 17, 2026
Merged

feat: add compaction_agent for customizable context compression#288
dobesv merged 1 commit into
mainfrom
customize-compression

Conversation

@dobesv

@dobesv dobesv commented Apr 17, 2026

Copy link
Copy Markdown
Owner

Summary

Add compaction_agent field to agent config. When context compaction triggers (auto or manual via .compact session), if the current agent has compaction_agent set, 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_agent field on agent config

  • compaction_agent: my-compactor in agent YAML frontmatter
  • References another agent by name
  • That agent's model, prompt, fallback models, retry config, temperature, etc. are all used for compaction
  • If the referenced agent can't be loaded → warning logged, falls back to default behavior
  • If not set → existing default compaction behavior unchanged

Renamed: .compress session.compact session

  • REPL command renamed (no backwards compat alias — breaking change)
  • Internal functions renamed: compress_sessioncompact_session, maybe_compress_sessionmaybe_compact_session, is_compressing_sessionis_compacting_session

Removed: summarize_prompt and summary_prompt config fields

  • summarize_prompt (the instruction sent to LLM) — replaced by compaction agent's prompt
  • summary_prompt (prefix prepended to stored result) — removed entirely, the LLM response is stored as-is
  • Environment variable overrides for these fields also removed

Improved: fetch_chat_text now uses retry + fallback

  • Changed from direct client.chat_completions() to call_with_retry_and_fallback()
  • Compaction (and autoname) now honor the agent's model_fallbacks and retry config
  • This is a behavior improvement for all fetch_chat_text callers

Testing

  • 3 unit tests for compaction_agent field (parse, unset, round-trip)
  • cargo fmt && cargo build && cargo clippy -- -D warnings — clean
  • 301/301 unit tests pass

Summary by CodeRabbit

  • New Features

    • Added a compaction_agent option so context compaction can use an agent’s model, system prompt, and parameters.
  • Refactor

    • Renamed commands and UI wording from "compress" to "compact" across the app.
    • Compaction now preserves session history and can be driven by the configured compaction agent instead of global defaults.
    • Session logs now record compaction agent selection.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@dobesv has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 32 minutes and 43 seconds before requesting another review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 54bbd012-95c8-4e6e-9018-1baf5825a9ec

📥 Commits

Reviewing files that changed from the base of the PR and between a2dad9f and 5456982.

📒 Files selected for processing (12)
  • .changesets/compaction-agent.md
  • example_config/agents/example-agent.md
  • src/client/stream.rs
  • src/config/agent.rs
  • src/config/input.rs
  • src/config/mod.rs
  • src/config/session.rs
  • src/rag/mod.rs
  • src/repl/mod.rs
  • src/serve.rs
  • src/tui/prompt.rs
  • src/utils/mod.rs
📝 Walkthrough

Walkthrough

Adds a configurable compaction_agent to agents so context compaction can use a specified agent's model/prompt/parameters; renames compression terminology to "compact" across codepaths and updates compaction control flow to load and optionally override Input with the compaction agent.

Changes

Cohort / File(s) Summary
Changesets & Examples
.changesets/compaction-agent.md, example_config/agents/example-agent.md
New changeset declaring minor release; example agent config documents compaction_agent: null.
Agent config & API
src/config/agent.rs
Added compaction_agent: Option<String> to Agent/AgentFrontMatter, accessor and setter, resolve_variables() helper, tests for parsing/round-trip.
Session persistence & behavior
src/config/session.rs
Persisted compaction_agent in session/log/header, added set_compaction_agent, updated message-building to inject agent system prompt when appropriate, test helper added.
Global config & compaction flow
src/config/mod.rs
Renamed compress→compact APIs, removed old summary prompt fields, introduced DEFAULT_COMPACT_PROMPT, implemented compaction-agent lookup/resolve/override flow and config setter for compaction agent, added tests.
Input → client call path
src/config/input.rs
Reworked fetch_chat_text() to use create_abort_signal() and retry::call_with_retry_and_fallback() rather than direct client single-call usage; doc comment added.
REPL / TUI wiring
src/repl/mod.rs, src/tui/prompt.rs
Renamed command and internal calls/messages from .compress session.compact session, updated polling/checks and post-chat hooks to use compact APIs.
Minor algorithmic/refactor tweaks
src/client/stream.rs, src/rag/mod.rs, src/serve.rs, src/utils/mod.rs
Small control-flow/iterator/sorting refactors: match guard for stream parser, zip iterator adjustment, non-consuming zip in message parsing, and sort key change in fuzzy_filter.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I found a little compaction key,
An agent to tuck old context neatly,
Models and prompts now hop in line,
Compacting tales so threads stay fine.
Hooray — a rabbit-approved refine! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add compaction_agent for customizable context compression' clearly and concisely summarizes the main change: introducing a new compaction_agent feature for customizing context compression behavior.
Linked Issues check ✅ Passed The PR fully addresses issue #216 by implementing customizable context compression through a compaction_agent field that allows specifying an agent with custom prompt, model, fallback models, and retry configuration.
Out of Scope Changes check ✅ Passed All code changes are directly related to implementing customizable context compression via compaction_agent; minor refactors (iterator style, guard patterns) are supporting improvements within scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch customize-compression

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between bc09020 and e8928f4.

📒 Files selected for processing (7)
  • .changesets/compaction-agent.md
  • example_config/agents/example-agent.md
  • src/config/agent.rs
  • src/config/input.rs
  • src/config/mod.rs
  • src/repl/mod.rs
  • src/tui/prompt.rs

Comment on lines +1 to +4
---
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment thread src/config/mod.rs Outdated
Comment thread src/config/mod.rs Outdated
@dobesv dobesv enabled auto-merge (squash) April 17, 2026 04:26
@dobesv dobesv disabled auto-merge April 17, 2026 04:26
@dobesv dobesv force-pushed the customize-compression branch from a2dad9f to 3176e44 Compare April 17, 2026 06:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/config/mod.rs (2)

2178-2199: Add compaction_agent (and model_fallbacks) to .set autocompletion.

Config::update now accepts compaction_agent (line 936) but the .set completion list here doesn't advertise it, so REPL users won't discover it via tab-complete. model_fallbacks appears 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 internal Session API still uses "compress".

maybe_compact_session/compact_session/is_compacting_session were renamed, but they still drive session.set_compressing(true), session.compressing(), session.need_compress(...), and log SessionLogEntry::Compress. This is defensible for log-format backward compat (existing session files on disk contain type: compress), but the in-memory Session methods 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 in Agent::build_messages.

The prompt-prepending logic here is a partial re-implementation of Agent::build_messages (see src/config/agent.rs:525-555), but missing the tools_text merging that the real method performs. If an agent with both interpolated_instructions() and tools_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

📥 Commits

Reviewing files that changed from the base of the PR and between e8928f4 and a2dad9f.

📒 Files selected for processing (8)
  • src/client/stream.rs
  • src/config/agent.rs
  • src/config/input.rs
  • src/config/mod.rs
  • src/config/session.rs
  • src/rag/mod.rs
  • src/serve.rs
  • src/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

Comment thread src/config/mod.rs Outdated
Comment thread src/config/session.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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to set custom prompt and model for context compression

1 participant