@tduyng/pi-context 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +36 -82
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,112 +1,62 @@
1
1
  # @tduyng/pi-context
2
2
 
3
- See what fills the context window, summarize it from the warm prompt cache, retire a finished task, and recover what compaction dropped.
3
+ Four things for the context window: see what fills it, compact from the warm cache instead of a cold one, retire a finished turn, and read back what compaction dropped.
4
4
 
5
- ## Commands and tools
5
+ When the window fills, pi compacts and a summariser reads the conversation again, from cold. That request costs the conversation it summarises. `/context` shows where the window went, and the other three make a compaction cheaper or smaller.
6
6
 
7
- ### /context
7
+ `history` is 134 tokens and only in sessions that load it. `/context`, `/collapse` and `/context-cache` are commands, so they cost nothing until typed. The dedupe is an event hook and adds no schema.
8
8
 
9
- Opens a TUI panel with a colored pixel map and a dotted-leader category list. Every context consumer gets a row: system prompt, tools, user messages, assistant text, tool results, bash executions, compacted history, extension entries, free space. Categories break down by tool or custom type, sorted by token weight. Child items within a category are capped at 30 shown. The rest are summarized as a "+N more" line with their combined token count.
9
+ ## Where the window went
10
10
 
11
- The panel fits the window it opens in. Its body takes at most 70% of the terminal rows, each line is truncated to the column width instead of wrapping, and a list too tall for the window keeps every category it can before spending the rest on child rows. A window too short for all categories says how many it hid. The map is hidden when the window is shorter than the map's six rows or narrower than 86 columns, so a small window keeps the numbers instead of a map no one can read. The pixel map uses proportional colored squares across 24 columns.
11
+ `/context` opens a TUI panel with a colored pixel map and a category list. Every consumer gets a row: system prompt, tools, user messages, assistant text, tool results, bash executions, compacted history, extension entries, free space. Categories break down by tool or custom type, sorted by token weight, and children are capped at 30 shown with a `+N more` line carrying their combined count.
12
12
 
13
- ### Cached compaction
13
+ The panel fits the window it opens in. Its body takes at most 70% of the rows, each line is truncated to the column width instead of wrapping, and a list too tall for the window keeps every category it can before spending the rest on child rows. The map is hidden below six rows or 86 columns.
14
14
 
15
- Compaction replays the conversation the provider already cached and appends one instruction, so the summary request reads almost all of its input from cache at a fraction of the price, and the summarizer sees the full tool output instead of pi's 2,000-character head cuts.
15
+ ## Compacting from the warm prefix
16
16
 
17
- The fallback. The branch is projected through pi's own entry conversion and the captured conversation must still be its prefix. A kept region that moved, a model change, a cold cache, a truncated reply or a provider error all fall back to pi's own compaction. Nothing is cancelled: a compaction pi asked for always runs, on the cached path when it can and on pi's path otherwise.
17
+ The capture is the full transcript of the last request, including the leading system message that carries the prompt and the tool declarations. The summary request replays it unchanged with one instruction appended, so almost all of the input is a cache read, and the summariser sees full tool output rather than pi's 2,000-character head cuts.
18
18
 
19
- The capture is the full transcript of the last request, including the leading system message that carries the prompt and the tool declarations, and the summary request replays it unchanged. That is what keeps the prefix cacheable, and the request adds no second system prompt. `/context-cache` shows the state now: the declared lifetime, the last refresh and the warm capture. Idle cache warming is pi's own job (`cacheWarming` in settings), so this extension starts no compaction of its own.
19
+ The fallback is narrow on purpose. The branch is projected through pi's own entry conversion and the captured conversation must still be its prefix. A kept region that moved, a model change, a cold cache, a truncated reply or a provider error all fall back to pi's own compaction. Nothing is cancelled, since a compaction pi asked for always runs, on the cached path when it can and on pi's path otherwise.
20
20
 
21
- Every decision lands in `~/.pi/agent/cached-compaction.jsonl` with the reason it took.
21
+ `/context-cache` shows the declared lifetime, the last refresh and the warm capture. Each decision lands in `<agent-dir>/cached-compaction.jsonl` with its reason, which is where to look when a compaction took the slow path.
22
22
 
23
- ### history
23
+ ## A finished turn, retired
24
24
 
25
- Search or read earlier conversation that left the context window: pruned results, compacted spans, or earlier sessions of the project.
25
+ `/collapse [turns]` replaces finished turns with one branch summary, one turn by default. The anchor is the entry before the oldest user prompt in the span, so nothing before the task moves.
26
26
 
27
- `search` walks the current branch newest-first. With `all: true`, it searches every `.jsonl` session file of the project, newest file first. Multi-word queries OR-match. Echoes (compaction summaries, verbatim input records, prior history results) rank below originals, so a copy never displaces what it copied. Default limit is 10, max 50. The ranking is lexical: a model rerank of the top eight was deleted, see the removal note below.
27
+ It builds the summary from the entries themselves: modified files, read-only files, command count, validation runs, the failures with the command that failed, and the last assistant text as the outcome. No model reads the span and no request goes out, which is where this differs from a compaction. It costs nothing and leaves the cache alone.
28
28
 
29
- `read` returns one entry in full, sliced to fit the remaining context. Page size: min 2,000, max 20,000 chars, sized to leave room for the model's reply. Pass `offset` for pagination.
29
+ Two cases refuse. Nothing sits before the first prompt of a session, so there is no anchor, and a prompt with no assistant turn after it is work in flight rather than a finished turn.
30
30
 
31
- ### Compaction input record
31
+ What it drops is real: the reasoning inside a turn goes, the summary keeps one text block, and the file list caps at twelve with the remainder counted. The raw entries stay in the session file, so `history` recovers any of them and `/tree` walks back to them. The collapsed messages' usage rides along on the branch summary entry, which is where pi reads totals, so `/cost` still counts what those turns cost.
32
32
 
33
- After automatic compaction (not manual `/compact`), the extension appends a hidden custom message listing the compacted span's verbatim user inputs, `ask_question` answers, and visible custom messages. Total cap: 20,000 chars. The first ask, the latest ask, and the latest input always survive. The rest fill newest-first. Anything omitted is recoverable with the `history` tool.
33
+ ## Reading back what compaction dropped
34
34
 
35
+ `history` searches or reads earlier conversation that left the window: pruned results, compacted spans, or earlier sessions of the project.
35
36
 
36
- ### /collapse
37
+ `search` walks the current branch newest first, or every session file of the project with `all: true`, newest file first. Multi-word queries OR-match. Echoes (compaction summaries, verbatim input records, prior history results) rank below originals, so a copy never displaces what it copied. The default limit is 10, the maximum 50, and the ranking is lexical.
37
38
 
38
- `/collapse [turns]` replaces finished turns with one branch summary. The default is one turn. The anchor is the entry before the oldest user prompt in the span, so nothing before the task moves.
39
+ `read` returns one entry in full, sliced to fit the remaining context. Page size is 2,000 to 20,000 characters, sized to leave room for the reply, and `offset` pages through. Session files are append-only JSONL, streamed line by line, so a large transcript never lands in memory.
39
40
 
40
- The summary is built from the entries themselves. One walk collects the modified files, the files that were only read, the command count, the validation runs, and the failures with the command that failed. The last assistant text becomes the outcome. No model reads the span and no summary request goes out, which is where this differs from a compaction. This one costs nothing and it leaves the cache alone.
41
+ ## A record of what was said
41
42
 
42
- Two cases refuse. Nothing sits before the first prompt of a session, so there is no entry to anchor to, and a prompt with no assistant turn after it is work in flight rather than a finished turn.
43
+ After automatic compaction, not manual `/compact`, a hidden custom message lists the compacted span's verbatim user inputs, `ask_question` answers, and visible custom messages. The cap is 20,000 characters, and the first ask, the latest ask and the latest input always survive.
43
44
 
44
- What it drops is real. The reasoning inside a turn goes, the summary keeps one text block, and a file list is capped at twelve with the remainder counted. The raw entries stay in the session file, so `history` recovers any of them and `/tree` walks back to them. The collapsed messages' usage rides along on the branch summary entry, which is where pi reads totals from, so `/cost` still counts what those turns cost.
45
+ A summary paraphrases a request, and the exact wording of an ask is often the requirement.
45
46
 
46
- A hidden `context-collapse` message carries the summary into the next turn and tells the model not to go looking for the raw turns. It starts no turn of its own.
47
+ ## Two defects it fixes
47
48
 
48
- Its reach is not measured yet. What decides whether it is worth running is how much front a finished task leaves behind, and `just retention` prints that for the read side of the same spans.
49
+ When the agent directory and the working directory resolve to the same file through different paths, from a hardlink, a bind mount or a symlinked ancestor, pi adds the same `<project_instructions>` block twice. A `before_agent_start` handler strips the second copy by content, so two identical blocks are always redundant and blocks with different content stay.
49
50
 
50
- ## Reads a later edit made wrong
51
+ The other is a stale read. A `read` puts a file's bytes in the transcript, and a later `edit` makes them wrong. Over the recorded sessions, 66 percent of read bytes are stale by this rule. An earlier version marked them in place, and the measurement removed it: replacing a tool result rewrites the cached prefix from that point, so on a 300k-token session one marker re-bills 200k to 300k tokens to reclaim 8 KB, and it recurs on every later edit to a path already read. Compaction rewrites the whole prefix once and pays for it once.
51
52
 
52
- A `read` puts a file's bytes in the transcript. When an `edit` or `write` then lands on that path, those bytes are stale, and nothing in the transcript says so. Over the recorded sessions the frozen benchmark fixture holds 459 read results, of which 359 are marked by this rule, 66 percent of read bytes, 9.5 percent of all tool-result bytes.
53
+ ## Three ideas that measured to nothing
53
54
 
54
- Marking them in place costs more than it saves. Replacing a tool result in the `context` event rewrites the cached prefix from that point on, so the next request re-bills everything after it. On a 300k-token session that is one 200k to 300k re-bill against the 8KB the marker reclaims, and the rewrite recurs every time a later edit lands on a path already read. The rewrite was removed; `pi-context` now changes nothing the provider has already cached, and the spending on stale reads is left to compaction, which rewrites the whole prefix once and pays for it once.
55
+ Kept because the numbers are the argument against rebuilding them:
55
56
 
56
- The session file keeps the original bytes, so `history` still recovers them.
57
-
58
- ### Project context dedupe
59
-
60
- When the agent dir and the working directory resolve to the same file through different paths (hardlinks, bind mounts, a symlinked ancestor), pi adds the same `<project_instructions>` block twice. A `before_agent_start` handler strips the second copy, matching on content, so two identical blocks are always redundant regardless of path. Blocks with different content stay.
61
-
62
- ## Tool-result views
63
-
64
- Not wired, and the reason is worth keeping because it closes the question rather than deferring it.
65
-
66
- A large tool result is rarely needed whole, so the idea was to build the small views of one: `full`, `head`, `tail`, `signals` (the error and failure lines) and `outline` (headings, definitions and `path:line` references), each built from the result's own lines with no model, and to ask the local model which one to keep.
67
-
68
- It used to run, on a `tool_execution_end` handler over every result past 2,000 characters. It cost 839 calls and 740,402 tokens, 43 percent of everything this suite sent to the local model, and it changed nothing: the handler returned no hint, nothing was rewritten, and the log entry held a `stateHash` rather than the result, so nothing could be scored from it afterwards. Asking the model directly does not work either, and returns near-uniform distributions over the five views.
69
-
70
- The offline fallback scored each view against the lines a later message actually quoted from the result. That label cannot fire. Across 1,045 replayed cases, not one tool-result line was ever quoted verbatim, at every bar from 4 to 80 characters. The model reads a result and acts on it rather than repeating it, so there is no signal in these sessions to score a view against, and no comparison can say which view is safe.
71
-
72
- The views and the benchmark are deleted. This section is what is left of them, so the next person does not build it again.
73
-
74
- ## What actually reclaims context, measured
75
-
76
- Over 358 recorded sessions, pi's own compaction does the work. One session is enough to show
77
- the ratio: its context climbed to 48 percent, dropped to 7, climbed to 53, and dropped again.
78
- Both drops are pi's own compaction, `fromHook: False`, and the second reclaimed about 458,000
79
- tokens in the event.
80
-
81
- Nothing in this package rewrites context between compactions. The panel, `history` and dedupe
82
- add no request bytes, and collapse and handoff act where a compaction boundary has already
83
- rewritten the prefix, so their work is paid for once.
84
-
85
- Two local model gates are gone from this package, both because nothing measured them.
86
-
87
- The compaction deferral asked whether summarizing the older messages would lose something the
88
- work in flight still needs, and it had one live record in the whole history. Pi opens a
89
- threshold compaction at `contextWindow - reserveTokens`, a line at 1,032,192 tokens for this
90
- 1,048,576-token model, against a session request that carries about 217,000, so the hook
91
- cannot fire at the mean context. Its label would be the compaction that happened anyway, and
92
- with no deferral there is no negative class, so no cut could be fitted. Three hand-written
93
- probes said the answer looked right, and three probes are not a corpus.
94
-
95
- The history rerank asked which of the top eight search hits answers the question. Over 17
96
- searches it promoted twice, and the same shape on file selection read 0.612 to 0.659 AUC
97
- against a lexical floor at 0.707, so the ranking it would have reordered was already the
98
- better one. Both are deleted rather than left waiting for a corpus that has not arrived.
99
-
100
- ## Compaction timing
101
-
102
- Pi compacts at `contextWindow - compaction.reserveTokens`. Fixed line. It summarizes whole spans whether or not the work in flight is finished, and a half-applied edit survives that summary by luck.
103
-
104
- The deferral that used to sit here asked the model at that moment whether the summary would lose something the remaining work still needs, and let the space be reclaimed in place instead. It is gone, for the reasons above. What is left is pi's own timing, and cached compaction, which pays for a rewrite once instead of once per edit.
105
-
106
- ## Design
107
-
108
- - `history` registers and unregisters dynamically, so the tool appears only when there is an earlier transcript to search.
109
- - Session files are JSONL, append-only. `history` streams them line by line so large transcripts never land in memory.
57
+ - A tool-result view selector, where a local model picked `full`, `head`, `tail`, `signals` or `outline` for every result over 2,000 characters. It cost 839 calls and 740k tokens and changed nothing, because not one tool-result line was ever quoted verbatim by a later message. With no label, there was nothing to score a view against.
58
+ - A compaction deferral hook. It opened at `contextWindow - reserveTokens`, a line a real session request never reaches, and recorded one firing in the whole history.
59
+ - A history rerank, which promoted twice in 17 searches and scored 0.612 to 0.659 AUC against a lexical floor at 0.707.
110
60
 
111
61
  ## Install
112
62
 
@@ -116,6 +66,10 @@ pi install npm:@tduyng/pi-context
116
66
 
117
67
  Local checkout: `pi install /path/to/dotfiles/pi/agent/extensions/pi-context`
118
68
 
119
- ## Configure
69
+ Set `PI_CACHE_RETENTION=long` so cached compaction has a cache to read. Pi's default is 5 minutes, and a pause longer than that turns the warm path into a cold one. Nothing else is configurable.
70
+
71
+ ## Limits
120
72
 
121
- None.
73
+ - Cached compaction falls back to pi's own path on any change to the prefix, so it helps a long stable session most.
74
+ - `/collapse` drops the reasoning inside a turn, keeps one text block, and caps the file list at twelve.
75
+ - `history` ranks lexically. It is recall over a transcript, not a search engine.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tduyng/pi-context",
3
- "version": "0.0.2",
4
- "description": "Context-window suite: see what fills it, prune spent tool results, retire reads an edit made wrong, and recover what compaction dropped.",
3
+ "version": "0.0.4",
4
+ "description": "See what fills the context window, compact from the warm prompt cache, collapse a finished turn, and recover what compaction dropped.",
5
5
  "keywords": [
6
6
  "pi",
7
7
  "pi-package",