feat: sqlite session storage (#6594)
This PR: - Adds retainedTail to compaction entries in the new agent harness so we don't have to walk up the tree for the 2000 tokens before compaction, - Changes getPathToRoot to getPathToRootOrCompaction to only load until last compaction, as unnecessary to access all nodes where it is called, - Adds a SQLite storage backend, in a separate packages/session-backend-sqlite, with a migration system and schemas as per on-site discussions: sessions to match session header messages (except for metadata, which I couldn't understand what it's used for or where it gets written, so I omitted it), session_entries for shared entry types as columns plus payload as a json for what remains, session_sequences to represent the append-only, serialized nature of the jsonl files, branch_entries to attribute nodes to branches (relationship one-to-many), and session_materialized with the session info (see /session in TUI) to act as a "cache" or quick-access for costs, message count, token info, labels, session name, and model-thinking-level config (e.g. for fast resume). - This is compatible with the new agent harness Session abstraction.
This commit is contained in:
committed by
GitHub
parent
54fad505b9
commit
9e7582aa03
@@ -232,10 +232,18 @@ Created when context is compacted. Stores a summary of earlier messages.
|
||||
{"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000}
|
||||
```
|
||||
|
||||
Newer harness-generated compactions embed the retained post-compaction context directly on the entry, instead of `firstKeptEntryId`:
|
||||
|
||||
```json
|
||||
{"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","tokensBefore":50000,"retainedTail":[{"role":"user","content":"latest request"},{"role":"assistant","content":[{"type":"text","text":"latest reply"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}]}
|
||||
```
|
||||
|
||||
Optional fields:
|
||||
- `usage`: LLM usage from generating the summary; included in session token and cost totals
|
||||
- `retainedTail`: Materialized `AgentMessage[]` kept after compaction. This is optional only for backward compatibility with older sessions. Newer harness-generated compactions include it so we can rebuild context from this checkpoint without walking older entries before the compaction entry.
|
||||
- `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
|
||||
- `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
|
||||
- `firstKeptEntryId`: for compatibility with old entry format.
|
||||
|
||||
### BranchSummaryEntry
|
||||
|
||||
@@ -314,8 +322,9 @@ Entries form a tree:
|
||||
1. Collects all entries on the path
|
||||
2. If a `CompactionEntry` is on the path:
|
||||
- Includes the compaction entry first
|
||||
- Then entries from `firstKeptEntryId` to compaction
|
||||
- Then entries after compaction
|
||||
- If `retainedTail` is present, it acts as a self-contained checkpoint and entries after the compaction are included
|
||||
- Otherwise entries from `firstKeptEntryId` to the compaction are included
|
||||
- Then entries after compaction are included
|
||||
3. Preserves non-message entries in the selected range so interactive mode can render them
|
||||
|
||||
`buildSessionContext()` builds on that entry list to produce the message list for the LLM:
|
||||
@@ -323,11 +332,13 @@ Entries form a tree:
|
||||
1. Extracts current model and thinking level settings from the full path
|
||||
2. Converts selected entries to messages:
|
||||
- `message` -> stored `AgentMessage`
|
||||
- `compaction` -> `compactionSummary`
|
||||
- `compaction` -> `compactionSummary` plus `retainedTail` when present
|
||||
- `branch_summary` -> `branchSummary`
|
||||
- `custom_message` -> `CustomMessage`
|
||||
- `custom` -> no context message
|
||||
|
||||
This makes newer compactions act like self-contained checkpoints. `retainedTail` is optional only so older sessions that only store `firstKeptEntryId` continue to load correctly.
|
||||
|
||||
## Parsing Example
|
||||
|
||||
```typescript
|
||||
|
||||
Reference in New Issue
Block a user