Looking for the proactive policy-based system added in PR #1828? See Context Compaction Policy. This page documents the reactive
CompactionConfig system used inside Agent(context=...).Quick Start
1
Agent-Centric Quick Start
2
Simple Usage
3
With Configuration
Anti-Thrashing Protection
Prevents endless compaction cycles in long-running agents by tracking savings effectiveness and giving up when returns diminish.1
Default Protection
2
Custom Thresholds
How Anti-Thrashing Works
- Savings Tracking: Each compaction calculates
(original_tokens - compacted_tokens) / original_tokens * 100 - Streak Counter: Increments when savings <
min_savings_pct, resets on good savings - Circuit Breaker: Stops compaction when
streak >= max_consecutive_low_savings - Reset Trigger: New messages arriving resets the protection state
Configuration Options
Note: Values < 1.0 for
min_savings_pct are auto-scaled (e.g., 0.15 becomes 15.0).
Iterative Summarisation
Builds upon previous summaries instead of starting fresh, preserving context across multiple compaction cycles.1
Enable Iterative Mode
2
Disable for Fresh Summaries
Iterative vs Fresh Summaries
Tool-Result Pruning
Deduplicates and truncates verbose tool outputs before summarization, significantly reducing token waste.1
Default Pruning
2
Custom Tool Pruning
Custom Tool Pruner
Focused Summarisation
Biases summarization toward specific topics using thefocus_topic parameter, preserving relevant content while compacting the rest.
1
Research Agent with Focus
2
Async Compaction with Focus
How Focus Topic Works
- Content Matching: Text matching the focus topic is preserved verbatim
- LLM Emphasis: When using LLM summarization, adds
Focus especially on: {focus_topic}. - Structured Paths: Marks focused content with
*FOCUS*markers in structured summaries
Focus Topic Use Cases
Pluggable Protocols
Inject custom implementations for tool pruning, message formatting, and summary building through protocol interfaces.- Tool Result Pruner
- Message Formatter
- Summary Builder
Anti-Injection Framing
Prevents models from treating compacted summaries as active instructions by prepending safety framing.Default Anti-Injection Prefix
Custom Anti-Injection Framing
Summarize
Replace old messages with a summary:Smart
Intelligently select which messages to keep:LLM-Powered Summarization
LLM_SUMMARIZE uses the agent’s own LLM to summarise older turns, preserving identifiers, file paths, URLs, error messages, and the user’s intent verbatim.Fallback behavior: If the LLM call fails, fallback to naive summarization. If invoked from a sync context that’s already inside an event loop, it also falls back to naive — async callers (achat) get full LLM summarization.
compaction_strategy across restarts — see ExecutionConfig Persistence for the to_dict() → from_dict() round-trip.
Intelligent Conversation Compaction
New structured summarization that preserves conversation continuity:Compactor API
CLI Usage
Structured Summary Template
Organizes compacted content into clear sections instead of flat text.Template Structure
The structured template categorizes messages into six sections:- Active Task - Current user objective
- Completed Actions - Finished operations
- In Progress - Ongoing work
- Pending Questions - Unanswered queries
- Relevant Files / Paths - Mentioned file references
- Remaining Work - Planned future actions
Before/After Example
Before (Flat Summary):When
structured_template=True (the default), ContextCompactor now uses the built-in DefaultSummaryBuilder automatically — no injected builder needed. The default builder renders SUMMARY_TEMPLATE deterministically (no LLM call), so it is offline-safe and never blocks the hot compaction path. It falls back to "Summary of N messages" only if rendering raises.Disable Structured Template
Iterative Updates Across Multiple Compactions
Preserves context from previous compactions so long-running agents don’t lose early context.How Iterative Updates Work
- First compaction: Creates initial structured summary
- Second compaction: Merges previous summary with new content
- Subsequent compactions: Continue preserving essential context
Disable Iterative Updates
In-Loop Compaction (Two-Tier)
In-loop compaction runs between tool iterations inside a single turn, so tool results never accumulate unbounded and blow past the context window mid-run.max_iter times; the hook fires each iteration and does nothing while the conversation stays below threshold. Above threshold it applies up to two tiers in order.
The Two Tiers
Cleared tool results are replaced with this exact placeholder:
Custom Thresholds
The in-loop knobs are passed viallm= extra settings on the Agent.
Disable (Restore Prior Behaviour)
in_loop_compaction=False, compaction runs only once before the turn — the pre-#2995 behaviour.
When the active model changes mid-run (auth failover, model failover), the cached loop compactor is rebuilt automatically so the token budget and tokeniser stay aligned with the new provider’s window. Nothing to configure.
New CompactionConfig Fields
These extend the reactiveCompactionConfig — same class, new fields.
Accurate Token Counting
Every threshold decision above usesestimate_tokens(), which now uses tiktoken when it is available offline, otherwise the character heuristic.
- Tiktoken downloads its BPE vocab from the network on first use.
- To stay offline-safe (CI, air-gapped hosts), the accurate path is probed once in a short-lived, timeout-bounded daemon thread. If the tokeniser is not locally cached, the code permanently falls back to the
len//4heuristic — never blocks. count_message_tokens()now includes thetool_callspayload (function name + arguments), which the old heuristic silently dropped.- For guaranteed-accurate counts,
pip install tiktokenand run once with the model set onCompactionConfig(model=...)to warm the cache.
clear_tool_results() API
- Only mutates entries with
role == "tool". - Rewrites their
contentstring toplaceholder, leaving all other fields intact. - Assistant
tool_callsmessages are never touched, so the model still sees the call structure (name, args, id) needed for coherent tool loops. - Preserves the last
keep_recenttool results.
When To Tune
Configuration Options
Strategies Available
ExecutionConfig Options
CompactionConfig Options
Note:
min_savings_pct values < 1.0 are auto-scaled (e.g., 0.15 becomes 15.0).
Two Ways to Configure Compaction
Choose Your Configuration
Inspecting Results
The newCompactionResult provides detailed metrics about compaction operations and their effectiveness.
New CompactionResult Fields
Only summarising strategies fill
result.summary:
Inspect the populated summary directly:
Monitoring Compaction Health
User Interaction Flow
Real-world example showing how the new features work together in a long research session:How This Helps Long Research Sessions
- Hours 1-2: Agent builds initial knowledge about distributed systems
- Hours 3-4: Tool pruning keeps large documentation snippets manageable
- Hours 5-6: Focus topic preserves critical Raft algorithm details
- Hours 7+: Anti-thrashing prevents compaction overhead when context stabilizes
Tool Pair Safety
Every compaction strategy keeps each assistanttool_calls message paired with its matching tool result, so strict providers never reject the next turn.
tool message whose tool_call_id has no matching preceding tool_calls message — that used to wedge long-lived sessions on every turn after compaction split a pair.
The boundary snap runs at every recent/older split — inside TRUNCATE, SLIDING, SUMMARIZE, PRUNE, and LLM_SUMMARIZE (sync + async). In TRUNCATE, the fallback “drop more” loop also removes a leading assistant tool_calls message together with all its immediately-following tool results, so it never strands an orphan at the head either.
preserve_recent still controls how many recent messages are kept. To keep a tool pair intact, the compactor may keep one or two more than preserve_recent — never fewer. The boundary only ever snaps outward (to a lower index), growing the kept window.Parallel tool calls
A single assistant turn can request several tools at once — the sliding strategy reconciles all their results to a fixed point. A single assistant turn can request several tools at once (parallel tool calls) — the assistant message carriestool_calls: [A, B, ...] and is followed by one role: "tool" result per id. When a sliding window keeps only some of these results, the sliding strategy now iterates its pair reconciliation to a fixed point: re-inserting the shared tool_calls=[A, B] message to satisfy B also detects that A is now missing its response and pulls A’s result back in. The final message list never contains a tool_call id without its matching response, so strict providers (OpenAI, Anthropic, Azure OpenAI) accept the next request. Fixed in PraisonAI PR #4034.
Manually stitching tool pairs after compaction is unnecessary — the fixed-point loop guarantees a balanced transcript.
Optimizer
Also preserves tool_call/tool_result pairs to maintain API validity
Best Practices
How do I tune anti-thrashing for my workload?
How do I tune anti-thrashing for my workload?
Adjust thresholds based on your agent’s usage pattern:For cost-sensitive workloads:For quality-focused workloads:Monitor
result.was_skipped_due_to_low_savings to see if protection is triggering.When should I write a custom ToolResultPrunerProtocol?
When should I write a custom ToolResultPrunerProtocol?
Write a custom tool pruner when:
- Your tools generate domain-specific outputs that need special handling
- Default size limits don’t match your tool output patterns
- You need to preserve specific data types (IDs, timestamps, etc.)
Iterative summaries vs. fresh summaries — which do I want?
Iterative summaries vs. fresh summaries — which do I want?
Use iterative summaries (default) when:
- Agent runs for hours/days with context continuity
- Research sessions with building knowledge
- Project management with evolving requirements
- Frequent topic switches in conversations
- Agent handles independent requests
- You prefer simpler mental models
What does focus_topic actually do?
What does focus_topic actually do?
Focus topic preserves content in three ways:
- Exact matches are preserved verbatim with
*FOCUS*markers - LLM summarization gets explicit instructions:
"Focus especially on: {focus_topic}." - Structured summaries emphasize focused content in relevant sections
- Long research sessions (“machine learning optimization”)
- Debugging sessions (“authentication errors”)
- Feature development (“payment integration”)
System-only overflow no longer hangs
System-only overflow no longer hangs
Since PR #1980,
_truncate() exits cleanly when only system messages remain over budget — previously this could loop indefinitely. The trade-off: when your system prompt alone exceeds target_tokens, post-compaction count may stay over target rather than dropping system messages.Best practices for long-running agents
Best practices for long-running agents
- Keep
enable_iterative_summary=True(default) for context preservation - Use
focus_topicwhen discussing specific technical areas - Monitor
result.tool_results_prunedto track tool output efficiency - Set appropriate
min_savings_pctbased on your cost tolerance - Use structured templates for better organization
- Test topic changes to verify anti-injection works properly
Hooks
BEFORE_COMPACTIONandAFTER_COMPACTIONhook events now fire consistently around every compaction (both sync and async). See Hook Events.
AFTER_COMPACTION now receives a populated CompactionResult.summary for summarising strategies (previously always ""), so plugin persisters that subscribe to AFTER_COMPACTION can finally read the summary text. See Reading the summary from a hook.Persistence
When the agent is bound to asession_id, a successful in-run compaction now writes its summary to the session automatically as a compaction checkpoint. On the next run, resume replays that summary plus the retained tail instead of the full raw transcript.
As of 1.6.152+, this applies to both agent.start(...) and agent.astart(...) / agent.achat(...) / agent.arun(...). Prior versions silently skipped persistence for async proactive compaction; PR #3081 fixed it and routes the checkpoint write through asyncio.to_thread so the event loop is not blocked.
This is fully backward compatible — sessions without a checkpoint resume from raw messages exactly as before. See Compacted Session Resume for the persistence details.
Policy vs. CompactionConfig — which should I use?
ContextCompactionPolicy is the proactive gate that runs before LLM calls. CompactionConfig runs after when compaction is actually needed. Both are compatible —execution.context_compaction is the proactive gate, Agent(context=...) runs after.
Related
Serialization
Intelligent compaction vs. plain summarize
See Intelligent Conversation Compaction for detailed usage.
Zero Performance Impact
Compaction uses lazy loading:Memory Management
Long-term memory storage and retrieval
Agent Configuration
Complete agent configuration options
Context Budgeter
Model context-window limits that drive in-loop thresholds
Memory Flush on Compaction
Save durable facts to long-term memory before compaction discards them
Session Handoff
Turn the durable recap into a continuation prompt for a fresh context

