GC Plugins
Context Garbage Collection plugins manage conversation history to prevent context window overflow. When the context approaches its limit, GC plugins automatically reduce history size while preserving important context.
| Module | shared.plugins.gc |
| Kind | gc |
| Auto-trigger | Yes (threshold-based) |
Available Strategies
| Plugin | Strategy | Best For |
|---|---|---|
gc_truncate |
Remove oldest turns | Simple, fast, predictable |
gc_summarize |
Compress old turns into summaries | Preserve context, slower |
gc_hybrid |
Summarize middle, truncate oldest | Balanced approach |
gc_budget |
Policy-driven removal (EPHEMERAL → PARTIAL → PRESERVABLE priority) | Long sessions, policy-aware context management |
from shared.plugins.gc import load_gc_plugin, GCConfig
# Load truncate strategy
gc = load_gc_plugin("gc_truncate", {
"preserve_recent_turns": 10
})
# Configure auto-trigger threshold
config = GCConfig(
threshold_percent=80.0, # Trigger at 80% context
auto_trigger=True
)
# Set on client
client.set_gc_plugin(gc, config)
# Conversation now auto-manages context!
from shared.plugins.gc import load_gc_from_file
# Load from .jaato/gc.json
result = load_gc_from_file()
if result:
gc_plugin, gc_config = result
client.set_gc_plugin(gc_plugin, gc_config)
GCConfig
Configuration for when and how GC triggers.
| Parameter | Type | Default | Description |
|---|---|---|---|
threshold_percent |
float | 80.0 | Context usage % to trigger GC; env: JAATO_GC_THRESHOLD |
target_percent |
float | 60.0 | Target context usage % after GC completes; env: JAATO_GC_TARGET |
pressure_percent |
float | 90.0 | Usage % at which PRESERVABLE content may be collected; 0 or None enables continuous mode; env: JAATO_GC_PRESSURE |
max_turns |
int | None | Max turns before GC (optional) |
preserve_recent_turns |
int | 5 | Turns to keep after GC |
auto_trigger |
bool | True | Auto-trigger during streaming |
check_before_send |
bool | True | Check context usage and possibly trigger GC before each send_message call |
pinned_turn_indices |
list[int] | [] | Turn indices (0-indexed) that are never removed by any GC strategy |
plugin_config |
dict | {} | Plugin-specific options |
auto_trigger=True, GC monitors context usage during
streaming and triggers automatically when the threshold is crossed.
This prevents context overflow mid-response.
pressure_percent=0 (or None) to enable
continuous mode. In this mode GC runs after every turn whenever context
usage exceeds target_percent, providing gradual predictable
trimming. PRESERVABLE content is never collected in continuous mode.
Enabled via: GCConfig(pressure_percent=None) or
JAATO_GC_PRESSURE=0.
from shared.plugins.gc import GCConfig
# Conservative: trigger early, keep more context
conservative = GCConfig(
threshold_percent=70.0,
preserve_recent_turns=10
)
# Aggressive: maximize context usage
aggressive = GCConfig(
threshold_percent=90.0,
preserve_recent_turns=3
)
# Turn-based trigger
turn_based = GCConfig(
max_turns=20, # GC after 20 turns
preserve_recent_turns=5
)
# Disable auto-trigger (manual only)
manual = GCConfig(
auto_trigger=False
)
GCPolicy Tiers
The GCPolicy enum (in shared.instruction_budget)
classifies instruction sources by how aggressively they may be collected.
The gc_budget strategy consults these policies to decide
removal order.
| Policy | Indicator | Behavior |
|---|---|---|
LOCKED |
🔒 | Never removed — essential for operation (system instructions, original request) |
PRESERVABLE |
◑ | Kept unless context exceeds pressure_percent |
PARTIAL |
◐ | Container with mixed-policy children; children evaluated individually |
EPHEMERAL |
○ | First candidates for removal (enrichment, working output, thinking tokens) |
CONDITIONAL |
◈ | Delegated to plugin evaluation — the plugin decides at GC time whether to remove |
Default policies per instruction source:
| Source | Default Policy |
|---|---|
SYSTEM | LOCKED |
PLUGIN | PARTIAL |
ENRICHMENT | EPHEMERAL |
CONVERSATION | PARTIAL |
THINKING | EPHEMERAL |
from shared.plugins.gc_budget import create_plugin as create_gc
from shared.plugins.gc import GCConfig
gc = create_gc()
gc.initialize({
"preserve_recent_turns": 5,
"target_percent": 60.0, # Target after GC
"pressure_percent": 90.0, # When to touch PRESERVABLE
"notify_on_gc": True,
})
client.set_gc_plugin(gc, GCConfig(
threshold_percent=80.0,
target_percent=60.0,
pressure_percent=90.0,
))
# Removal order:
# 1. EPHEMERAL (enrichment + working output) — oldest/largest first
# 2. PARTIAL turns — oldest first, respecting preserve_recent_turns
# 3. PRESERVABLE — only when usage > pressure_percent
# 4. LOCKED — never removed
# Continuous mode: run after every turn, PRESERVABLE never touched
gc = create_gc()
gc.initialize({
"preserve_recent_turns": 5,
"target_percent": 60.0,
"pressure_percent": 0, # 0 = continuous mode
})
client.set_gc_plugin(gc, GCConfig(
threshold_percent=80.0,
pressure_percent=None, # None = continuous mode in GCConfig
))
gc_truncate
Simple truncation strategy. Removes oldest turns first, keeping the most recent turns. Fast and predictable.
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
preserve_recent_turns |
int | 5 | Turns to keep |
notify_on_gc |
bool | True | Add notification to context |
agent_name |
str | None | Agent name for logging |
Pros & Cons
- Pro: Fast, no API calls
- Pro: Predictable behavior
- Con: Loses old context completely
from shared.plugins.gc_truncate import create_plugin as create_gc
gc = create_gc()
gc.initialize({
"preserve_recent_turns": 10,
"notify_on_gc": True
})
client.set_gc_plugin(gc, GCConfig(
threshold_percent=80.0
))
gc_summarize
Summarization strategy. Compresses old turns into a summary message, preserving semantic context while reducing token count.
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
preserve_recent_turns |
int | 5 | Turns to keep verbatim |
summarize_prompt |
str | (built-in) | Custom summarization prompt |
max_summary_tokens |
int | 500 | Max tokens in summary |
Pros & Cons
- Pro: Preserves semantic context
- Pro: Model remembers key points
- Con: Requires API call to summarize
- Con: Slower than truncation
from shared.plugins.gc_summarize import create_plugin as create_gc
gc = create_gc()
gc.initialize({
"preserve_recent_turns": 5,
"max_summary_tokens": 1000
})
client.set_gc_plugin(gc, GCConfig(
threshold_percent=75.0
))
gc_hybrid
Combined strategy: summarizes middle turns, truncates oldest turns, preserves recent turns. Best balance of context preservation and efficiency.
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
preserve_recent_turns |
int | 5 | Recent turns to keep verbatim |
summarize_middle_turns |
int | 10 | Middle turns to summarize |
How It Works
History: [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^
truncated summarized preserved
After GC: [Summary, T10, T11, T12]
from shared.plugins.gc_hybrid import create_plugin as create_gc
gc = create_gc()
gc.initialize({
"preserve_recent_turns": 5,
"summarize_middle_turns": 10
})
client.set_gc_plugin(gc, GCConfig(
threshold_percent=80.0
))
File Configuration
Configure GC via .jaato/gc.json for easy project-level
settings without code changes.
JSON Schema
| Key | Type | Description |
|---|---|---|
type |
str | "truncate", "summarize", "hybrid", or "budget" |
threshold_percent |
float | Context % to trigger GC (default: 80.0) |
target_percent |
float | Target context % after GC (default: 60.0) |
pressure_percent |
float | PRESERVABLE threshold % (default: 90.0); 0 = continuous mode |
preserve_recent_turns |
int | Turns to keep |
max_turns |
int | Max turns before GC |
notify_on_gc |
bool | Add notification message |
summarize_middle_turns |
int | For hybrid strategy |
{
"type": "hybrid",
"threshold_percent": 80.0,
"preserve_recent_turns": 5,
"summarize_middle_turns": 10,
"notify_on_gc": true
}
from shared.plugins.gc import load_gc_from_file
result = load_gc_from_file(".jaato/gc.json", agent_name="main")
if result:
gc_plugin, gc_config = result
client.set_gc_plugin(gc_plugin, gc_config)
else:
print("No GC config found")
Manual GC
Trigger GC manually when needed, regardless of threshold.
GCResult
| Field | Type | Description |
|---|---|---|
tokens_before |
int | Tokens before GC |
tokens_after |
int | Tokens after GC |
tokens_freed |
int | Tokens recovered |
turns_removed |
int | Turns removed/summarized |
strategy |
str | Strategy used |
trigger_reason |
str | "manual", "threshold", "max_turns" |
# Trigger GC manually
result = client.manual_gc()
print(f"Freed {result.tokens_freed} tokens")
print(f"Removed {result.turns_removed} turns")
print(f"Before: {result.tokens_before}")
print(f"After: {result.tokens_after}")
# Check GC history
for gc in client.get_gc_history():
print(f"GC at {gc.timestamp}: {gc.strategy}")
Environment Variables
| Variable | Default | Description |
|---|---|---|
JAATO_GC_THRESHOLD |
80.0 | Context usage % that triggers GC |
JAATO_GC_TARGET |
60.0 | Target context usage % after GC completes |
JAATO_GC_PRESSURE |
90.0 | Usage % at which PRESERVABLE content may be collected; set to 0 to enable continuous mode |
JAATO_GC_THRESHOLD=75.0 # Trigger GC at 75% context usage
JAATO_GC_TARGET=55.0 # Reduce to 55% after GC
JAATO_GC_PRESSURE=88.0 # Allow PRESERVABLE collection at 88%
# JAATO_GC_PRESSURE=0 # Uncomment for continuous mode