Improve compaction diagrams with legend and realistic message types

This commit is contained in:
Mario Zechner
2025-12-24 12:58:00 +01:00
parent 27250c860b
commit 3c5f4920c0

View File

@@ -186,27 +186,33 @@ The `before_compact` event lets you implement custom compaction strategies. Unde
When context exceeds the threshold, pi finds a "cut point" that keeps recent turns (configurable via `settings.json` `compaction.keepRecentTokens`, default 20k):
```
Legend:
H = header U = user message A = assistant message
T = tool result C = compaction entry B = bashExecution
```
```
Session entries (before compaction):
index: 0 1 2 3 4 5 6 7
┌────────┬───────────────┬─────┬─────┬─────┬─────┬─────┬─────
header │ prev compact │ msg │ msg │ msg │ msg │ msg │ msg
└────────┴───────────────┴─────┴─────┴─────┴─────┴─────┴─────
↑ └─────┬─────┘ └──────────────┘
previousSummary messagesToSummarize messagesToKeep
cutPoint.firstKeptEntryIndex = 5
index: 0 1 2 3 4 5 6 7 8 9 10 11
┌──────┬────────────┬───┬───┬───┬───┬───┬───┐
H │ C │ U │ A │ T │ A │ U │ A │ T │ T │ A │ T
└──────┴────────────┴───┴───┴───┴───┴───┴───┘
↑ └───────┬───────┘ └─────────┬─────────┘
previousSummary messagesToSummarize messagesToKeep
cutPoint.firstKeptEntryIndex = 6
After compaction (new entry appended):
index: 0 1 2 3 4 5 6 7 8
┌────────┬───────────────┬─────┬─────┬─────┬─────┬─────┬─────┬─────────────┐
header │ prev compact │ msg │ msg │ msg │ msg │ msg │ msg │ NEW compact
└────────┴───────────────┴─────┴─────┴─────┴─────┴─────┴─────┴─────────────┘
└─────┬─────┘ └───────┬───────┘
ignored loaded firstKeptEntryIndex = 5
on reload on reload (stored in this entry)
index: 0 1 2 3 4 5 6 7 8 9 10 11 12
┌───┬───────────────┬───┬───┬───┬───┬───┬───┬───┐
H │ C │ U │ A │ T │ A │ U │ A │ T │ T │ A │ T │ C
└───┴───────────────┴───┴───┴───┴───┴───┴───┴───┘
└───────┬───────┘ └─────────┬─────────┘ ↑
ignored loaded firstKeptEntryIndex = 6
on reload on reload (stored in new C)
```
The session file is append-only. When loading, the session loader finds the latest compaction entry, uses its summary, then loads messages starting from `firstKeptEntryIndex`. The cut point is always a user, assistant, or bashExecution message (never a tool result, which must stay with its tool call).
@@ -214,12 +220,11 @@ The session file is append-only. When loading, the session loader finds the late
```
What gets sent to the LLM as context:
┌────────────────────────────────────────────────────────────
│ [system prompt] [summary msg] [msg idx 5] [msg idx 6] [msg idx 7] │
└────────────────────────────────────────────────────────────
└──────────────────────┘
from NEW compact's messages from
summary firstKeptEntryIndex onwards
┌────────────────────────────────────────────────────────────┐
│ [system] [summary] [U idx 6] [A idx 7] [T idx 8] [T idx 9] [A idx 10] [T idx 11] │
└────────────────────────────────────────────────────────────┘
└──────────────────┬──────────────────┘
from new C's summary messages from firstKeptEntryIndex onwards
```
**Split turns:** When a single turn is too large, the cut point may land mid-turn at an assistant message. In this case `cutPoint.isSplitTurn = true`:
@@ -227,25 +232,25 @@ What gets sent to the LLM as context:
```
Split turn example (one huge turn that exceeds keepRecentTokens):
index: 0 1 2 3 4 5 6 7 8 9
┌────────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
header │ user │ asst │ tool │ asst │ tool │ tool │ asst │ tool │ asst
└────────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
turnStartIndex = 1 firstKeptEntryIndex = 7
│ (must be user/asst/bash, not tool)
└────────── turn prefix ───────────┘ (idx 1-6, summarized separately)
└── kept messages (idx 7-9)
index: 0 1 2 3 4 5 6 7 8 9
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
H │ U │ A │ T │ A │ T │ T │ A │ T │ A
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
turnStartIndex = 1 firstKeptEntryIndex = 7
│ (must be U/A/B, not T)
───── turn prefix ─────┘ (idx 1-6, summarized separately)
└── kept messages (idx 7-9)
messagesToSummarize = [] (no complete turns before this one)
messagesToKeep = [msg idx 7, msg idx 8, msg idx 9]
messagesToKeep = [A idx 7, T idx 8, A idx 9]
The default compaction generates TWO summaries that get merged:
1. History summary (previousSummary + messagesToSummarize)
2. Turn prefix summary (messages from turnStartIndex to firstKeptEntryIndex)
```
See [src/core/compaction.ts](../src/core/compaction.ts) for the full implementation.
```
**Event fields:**