Compaction Ladder
Bound long agent runs without corrupting history
FabrCore v1.7.1 separates what a model sees during one call from what the application stores between turns. The result is a five-rung ladder ordered from cheap and reversible to permanent and protective.
0.50 layer 1 evict old tool results free, reversible
0.80 layer 1 truncate oldest groups free, reversible
0.87 layer 2 summarize persisted history one LLM call, permanent
0.90 fuse clip the read projection last-resort insurance
1.00 stop reject an oversized run FabrCoreRunStoppedException
Two layers, two responsibilities
| Layer 1: context compaction | Layer 2: history compaction | |
|---|---|---|
| Runs | Before every model call, including tool loops | Before or after a turn |
| Bounds | The messages sent to this LLM call | The persisted MessageThreads record |
| Reversible | Yes; messages are excluded from the request projection | No; history is summarized and rewritten |
| LLM cost | None | One or more summarization calls |
| Customization | CompactionStrategy | Override OnCompaction |
Persisting that index would duplicate the conversation and let a stale projection survive a layer-two rewrite. The deterministic index is rebuilt on activation.
Model configuration
For most deployments, set the model window and output reserve. FabrCore derives the input budget and orders the remaining rungs.
{
"Name": "default",
"Provider": "OpenAI",
"Model": "gpt-5",
"ApiKeyAlias": "openai",
"ContextWindowTokens": 200000,
"MaxOutputTokens": 16000,
"ContextCompactionEnabled": true,
"ContextEvictThreshold": 0.50,
"ContextTruncateThreshold": 0.80,
"CompactionEnabled": true,
"CompactionThreshold": 0.87,
"PerTurnMaxInputTokens": 400000,
"MaxPromptInputTokens": 200000
}
| Field | Default | Purpose |
|---|---|---|
ContextWindowTokens | Unset | Anchor for every ladder rung. |
MaxOutputTokens | Unset | Output reserve; layer 1 requires both values. |
ContextCompactionEnabled | true | Enable reversible in-run compaction. |
ContextEvictThreshold | 0.50 | Collapse old tool results. |
ContextTruncateThreshold | 0.80 | Drop the oldest request groups. |
CompactionEnabled | true | Enable persisted history consolidation. |
CompactionThreshold | 0.87 with layer 1; 0.75 without | Stored-token threshold for history compaction. |
CompactionKeepLastN | 20 | Recent messages retained verbatim. |
CompactionStaleAfterMinutes | 60 | Preflight a dormant, over-threshold thread. |
Agent-level overrides
Blueprint args can override individual rungs for one agent. Keys are case-sensitive.
"args": {
"_ContextCompactionEnabled": "true",
"_ContextEvictThreshold": "0.55",
"_ContextTruncateThreshold": "0.82",
"_CompactionThreshold": "0.88",
"_PerTurnMaxInputTokens": "300000"
}
Diagnostics and monitoring
Every agent logs its resolved ladder once during compaction initialization. context:unconfigured means ContextWindowTokens or MaxOutputTokens is missing and no in-run context bound can be composed. [OUT OF ORDER] means a later rung would fire before an earlier one.
- Layer 1 emits OpenTelemetry spans through compaction telemetry.
- Layer 2 emits
compaction.history.started,completed, andfailedmonitor events. - History events include a
preflightorpost-turntrigger. - Stored history may contain
[Compacted History]; a model request may additionally contain transient[Tool Calls]and[Summary]messages.
Migration from mid-turn history compaction
MidTurnCompactionEnabled is retired.
The property remains deserializable, but it is obsolete and ignored. Replace it with ContextCompactionEnabled. FabrCoreRunStoppedException.CheckpointCount and the _fabrcore_checkpoint_count diagnostic were also removed.
Run safety now has one job: stop over-budget work. It no longer mutates persisted history while a tool loop is active.