pi-supernova 0.3.2 → 0.5.0
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.
- package/README.md +148 -29
- package/docs/CHANGELOG.md +52 -0
- package/docs/TOKEN_COSTS.md +173 -0
- package/index.js +155 -41
- package/package.json +3 -1
- package/src/bridge/catalog.js +35 -1
- package/src/bridge/host-bridge.js +411 -50
- package/src/bridge/native-tools.js +35 -1
- package/src/config/config.default.json +1 -1
- package/src/config/config.js +19 -0
- package/src/context/evidence.js +119 -5
- package/src/context/fuzzy.js +37 -0
- package/src/context/ledger.js +128 -6
- package/src/context/outline.js +24 -0
- package/src/context/repo-index.js +102 -4
- package/src/context/search.js +45 -0
- package/src/context/snap.js +118 -6
- package/src/context/spans.js +39 -0
- package/src/context/surface.js +33 -6
- package/src/fs/check.js +50 -0
- package/src/fs/diff.js +16 -0
- package/src/fs/json-read.js +91 -0
- package/src/fs/patch.js +26 -0
- package/src/fs/vfs.js +102 -5
- package/src/fs/workspace.js +62 -3
- package/src/output/bottleneck.js +63 -4
- package/src/output/format.js +136 -17
- package/src/runtime/guest-worker.js +169 -31
- package/src/runtime/parallel.js +33 -0
- package/src/runtime/program-batch.js +112 -0
- package/src/runtime/program-file.js +40 -0
- package/src/runtime/reference.js +18 -0
- package/src/runtime/runtime.js +90 -8
- package/src/shared/decode.js +40 -0
- package/src/ui/omp-frame.js +30 -1
- package/src/ui/render-measure.js +24 -0
- package/src/ui/render.js +96 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-supernova
|
|
2
2
|
|
|
3
|
-
**One
|
|
3
|
+
**One `supernova` invocation. Inline code, a workspace program, or an explicit program batch. Four commands inside CodeMode.**
|
|
4
4
|
|
|
5
5
|
```javascript
|
|
6
6
|
const source = await read("validateRefreshToken");
|
|
@@ -48,12 +48,15 @@ settings. The runtime does not silently rewrite your tool policy.
|
|
|
48
48
|
| Function | Examples and behavior |
|
|
49
49
|
| --- | --- |
|
|
50
50
|
| `read` | `read(path, offset?, limit?)`, `read({path,offset,limit})`; one-based line windows |
|
|
51
|
-
| `read` | `
|
|
52
|
-
| `read` | `read({
|
|
51
|
+
| `read` | `return await read("plot.png")`; displays images directly, without a browser |
|
|
52
|
+
| `read` | `read({path,json:".verdict"})`; parse full JSON before bounded field selection |
|
|
53
|
+
| `read` | `read(directory)`, `read("symbol or question")`, `read(path,{about:question})`; a path is raw text, a symbol is a view |
|
|
54
|
+
| `read` | `read({query,resolve:true})`; same view as `read("symbol")`: status, path, line, lines, text, complete |
|
|
53
55
|
| `read` | `read({query,evidence:true})`; ranked evidence with provenance; optional `path` scopes discovery |
|
|
54
56
|
| `read` | `read({path,outline:true})`; structural declarations |
|
|
55
57
|
| `read` | `read([path1,path2])`; up to 64 paths, ordered values with labelled individual failures |
|
|
56
|
-
| `edit` | `edit(path,oldText,newText)`, `edit({path,edits:[{oldText,newText}]})`;
|
|
58
|
+
| `edit` | `edit(path,oldText,newText)`, `edit({path,edits:[{oldText,newText}]})`; unique in the file |
|
|
59
|
+
| `edit` | `edit(view,text)` CAS-replaces that span; `edit(view,old,new)` is unique inside it |
|
|
57
60
|
| `edit` | `edit({path,patch})`; unified patch application |
|
|
58
61
|
| `edit` | `edit(async () => {...})`; filesystem-only checkpoint, described below |
|
|
59
62
|
| `write` | `write(path,text)`, `write({path,content})`; atomic replacement |
|
|
@@ -68,27 +71,26 @@ payloads are not repeated in owned direct-execution errors;
|
|
|
68
71
|
stdout/stderr, exit status and source context remain. Session environment variables are taken
|
|
69
72
|
from the current execution context, not inherited from a different parent session.
|
|
70
73
|
|
|
71
|
-
Source questions
|
|
74
|
+
Source questions locate a declaration in one command. An exact
|
|
72
75
|
declaration match uses one bounded direct ripgrep search, without a prerequisite
|
|
73
76
|
file listing, persistent index, embeddings or summarization. A transient filename
|
|
74
77
|
listing is a fallback for unmatched content or unresolved bare filenames. Natural-language
|
|
75
78
|
questions reuse lexical stemming. Ripgrep must be available on PATH.
|
|
76
79
|
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
`read(path)` stays raw text. `read("symbol")` is the same view as
|
|
81
|
+
`read({query, resolve:true})` — not the file, not a path/range header:
|
|
79
82
|
|
|
80
83
|
```javascript
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
+
const v = await read("validateRefreshToken");
|
|
85
|
+
if (v.status !== "found") return v;
|
|
86
|
+
await edit(v, v.text.replace("token.length > 3", "token.length > 5"));
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
The
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
the matching line and give a continuation; they are not summarized. Uncertain
|
|
89
|
+
The view contains `status`, `path`, the matching `line`, span `lines`, unchanged
|
|
90
|
+
`text`, `complete`, and `nextOffset` when a budget clip continues. A declaration
|
|
91
|
+
snap is that span (`complete` is false unless the span is the whole file). Uncertain
|
|
90
92
|
results report `ambiguous`, `not_found` or `incomplete` with no selected path.
|
|
91
|
-
Use `{path: directory, about: question
|
|
93
|
+
Use `{path: directory, about: question}` to narrow the scope.
|
|
92
94
|
|
|
93
95
|
Ordinary reads stay self-contained. Outlines and graph evidence remain explicit
|
|
94
96
|
options, not mandatory stages of source resolution. Ordinary calls also get:
|
|
@@ -122,16 +124,33 @@ full dataflow tracking or a security sandbox.
|
|
|
122
124
|
|
|
123
125
|
Explicit read arrays reject missing/failed paths. For typed partial outcomes use
|
|
124
126
|
`Promise.allSettled(paths.map(path => read(path)))`. Successful arrays remain arrays.
|
|
125
|
-
For
|
|
126
|
-
|
|
127
|
+
For literal file content or scripts, prefer the optional tool-level `data` parameter:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"code": "await write(data.path,data.content); return await bash({command:\"python3\",args:[data.path]});",
|
|
132
|
+
"data": {
|
|
133
|
+
"path": "probe.py",
|
|
134
|
+
"content": "print(\"literal `backticks` and ${braces}\")\n"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`data` crosses the worker boundary as JSON, never as JavaScript source. Its
|
|
140
|
+
JSON-encoded length is capped separately at `maxCodeChars`; split larger inputs.
|
|
141
|
+
The binding exists only when supplied, so older programs declaring their own `data`
|
|
142
|
+
remain valid. Syntax errors run no commands and give quoting guidance. For inline
|
|
143
|
+
source, use `String.raw` (escaping backtick delimiters) or JSON-quoted strings.
|
|
127
144
|
|
|
128
145
|
On hosts exposing `sessionManager.getArtifactsDir()`, bare `agent://<id>` and
|
|
129
146
|
`artifact://<number>` read files from the calling session's artifact directory.
|
|
130
147
|
They preserve ID casing and support offset/limit and structured continuation.
|
|
131
148
|
These resources are read-only; ambiguous artifact IDs and escaping symlinks fail.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
A single `?q=.answer` (URL-encoded when needed) selects JSON from either resource
|
|
150
|
+
using the same bounded projection as `read({path,json})`. The resource must contain
|
|
151
|
+
valid JSON; ordinary Markdown is not parsed heuristically. This is not the full
|
|
152
|
+
OMP URI language: full jq, cross-session search and other schemes are not implemented.
|
|
153
|
+
Hosts without an artifact directory report that limitation rather than treating the URI as a local path.
|
|
135
154
|
|
|
136
155
|
For unstructured logs/text, `read(path,{about:"STT database"})` returns bounded,
|
|
137
156
|
line-numbered matching windows, or explicitly reports no matching text. It is not
|
|
@@ -139,6 +158,67 @@ a complete-file read. Write temporary investigation files under the workspace
|
|
|
139
158
|
(e.g. `.work/probe.py`): ordinary `write`/`edit` paths cannot escape it, including
|
|
140
159
|
absolute `/tmp` paths. Shell execution is a separate trusted boundary, not a sandbox.
|
|
141
160
|
|
|
161
|
+
### Reuse a program without resending its source
|
|
162
|
+
|
|
163
|
+
Save a trusted JavaScript async body or arrow in the workspace, then invoke it:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{"file":".work/audit.js","data":{"paths":["src/a.js","src/b.js"],"term":"TODO"}}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Supply exactly one of `code` or `file`. File programs get the same four commands,
|
|
170
|
+
optional `data`, limits, deadlines and transaction semantics. Each invocation
|
|
171
|
+
rereads the file and starts a fresh guest; there is no implicit last-program
|
|
172
|
+
state, auto-replay, or retained heap. Paths inside the program still resolve from
|
|
173
|
+
the calling workspace, not the script directory. This runs a Nova program, not
|
|
174
|
+
an arbitrary JavaScript module or a Python/shell script.
|
|
175
|
+
|
|
176
|
+
Program files must be regular UTF-8 files inside the workspace, including symlink
|
|
177
|
+
targets. Invalid encoding, oversized input and syntax errors fail before commands;
|
|
178
|
+
no truncated prefix is executed. Review untrusted source before running it.
|
|
179
|
+
Use ordinary `edit` to revise saved programs. This is explicit source reuse, not
|
|
180
|
+
conversation compression: prior calls and read results remain intact. Creation
|
|
181
|
+
costs an additional call unless combined with other work, so prefer inline code
|
|
182
|
+
for short one-off operations. See [token measurements](docs/TOKEN_COSTS.md).
|
|
183
|
+
|
|
184
|
+
### Batch already-known continuations
|
|
185
|
+
|
|
186
|
+
~~~json
|
|
187
|
+
{
|
|
188
|
+
"programs": [
|
|
189
|
+
{"code": "return await edit(data.path,data.oldText,data.newText);", "data": {"path":"src/config.js","oldText":"limit = 8","newText":"limit = 16"}},
|
|
190
|
+
{"code": "return await bash(\"npm test\");"},
|
|
191
|
+
{"file": ".work/audit.js", "data": {"paths":["src/config.js"],"term":"limit"}}
|
|
192
|
+
],
|
|
193
|
+
"timeoutMs": 60000
|
|
194
|
+
}
|
|
195
|
+
~~~
|
|
196
|
+
|
|
197
|
+
Use programs instead of top-level code/file/data. Supply 1--32 entries, each with
|
|
198
|
+
code OR file and optional data; the JSON-encoded array must fit maxCodeChars.
|
|
199
|
+
Entries run sequentially in fresh guests and commit separately. A successful
|
|
200
|
+
entry can create the file executed by a later entry. No implicit retries,
|
|
201
|
+
reordering, shared heap or nested batches are introduced.
|
|
202
|
+
|
|
203
|
+
The batch stops on the first failed entry, cancellation/deadline, or exhausted
|
|
204
|
+
output/log/image budget. Earlier successful commits remain; only the active
|
|
205
|
+
program's uncommitted writes roll back. Admission errors throw before any program.
|
|
206
|
+
Execution failures return a **typed stop report**, rather than throwing away prior
|
|
207
|
+
results/images: isError and details.ok identify failure, details.programs contains
|
|
208
|
+
every attempted result, and details.attempted/total identifies unstarted work.
|
|
209
|
+
Single code/file invocations retain their existing throwing behavior.
|
|
210
|
+
|
|
211
|
+
The outer deadline, host-call budget, log allowance, text budget and image limits
|
|
212
|
+
are shared across the batch. Individual read budgets are not reduced. Every
|
|
213
|
+
attempted program's original text is returned in length-delimited blocks; ordinary
|
|
214
|
+
limits still disclose clipping. Images retain program/image labels. Split a plan
|
|
215
|
+
that would exceed the aggregate output budget.
|
|
216
|
+
|
|
217
|
+
Batch only continuations already chosen by the agent, such as edit then known
|
|
218
|
+
verification, or create then run known audits. Keep a separate call whenever new
|
|
219
|
+
source/results are needed to decide the next action. This does not lower reasoning
|
|
220
|
+
settings, hide observations, or infer a plan on the agent's behalf.
|
|
221
|
+
|
|
142
222
|
### Large inputs and report outputs
|
|
143
223
|
|
|
144
224
|
The default program limit is 48,000 UTF-16 code units (configurable via
|
|
@@ -159,17 +239,38 @@ output delivery; progress files survive shell execution but staged VFS writes ma
|
|
|
159
239
|
roll back.
|
|
160
240
|
|
|
161
241
|
Large returned objects are bounded previews, not retained artifacts. Select fields
|
|
162
|
-
and array windows before returning, rather than parsing a truncated preview
|
|
242
|
+
and array windows before returning, rather than parsing a truncated preview.
|
|
243
|
+
|
|
244
|
+
## JSON reports and targeted text audits
|
|
245
|
+
|
|
246
|
+
For JSON, select fields inside the read adapter, **before** output budgeting:
|
|
163
247
|
|
|
164
248
|
```js
|
|
165
|
-
const
|
|
166
|
-
return {verdict
|
|
249
|
+
const [verdict, values] = await read({path:"report.json",json:[".verdict",".values[5000:5003]"]});
|
|
250
|
+
return {verdict, values};
|
|
167
251
|
```
|
|
168
252
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
253
|
+
Selectors support "." (root), .field, .nested[0], .items[0:10], and .["quoted.key"].
|
|
254
|
+
Use json:true for the complete parsed value. Selectors are not full jq: pipes,
|
|
255
|
+
filters, wildcards and negative indices fail explicitly. Missing keys and indices
|
|
256
|
+
fail; false, zero and null remain values. Slices use an exclusive end and clamp to
|
|
257
|
+
array length. Only own JSON properties are traversed; nothing is evaluated.
|
|
258
|
+
|
|
259
|
+
Inputs are capped at 16 MiB, including staged files. JSON reads require regular
|
|
260
|
+
files and reject named pipes without waiting for a writer. The entire input must
|
|
261
|
+
be valid JSON before any selection. Each selector is budgeted before allocating
|
|
262
|
+
the next slice; sparse selector/path/edit arrays are rejected. Selected JSON must
|
|
263
|
+
fit the ordinary read budget or the
|
|
264
|
+
read throws; it is never returned as malformed/truncated JSON. Oversized unwindowed
|
|
265
|
+
plain .json reads also fail with a projection hint. Explicit offset/limit or
|
|
266
|
+
resolve:true still allow raw inspection, but line windows are not JSON documents.
|
|
267
|
+
Do not combine json with complete, line windows, or source views. External read
|
|
268
|
+
overrides reject JSON projection rather than silently ignoring the option.
|
|
269
|
+
|
|
270
|
+
For large Markdown/log path audits, use read(path,{about:"document path"}) or
|
|
271
|
+
explicit offset/limit, not complete:true. Larger JSON needs a streaming parser via
|
|
272
|
+
bash. Arbitrary returned objects still have bounded previews, not implicit
|
|
273
|
+
continuation handles.
|
|
173
274
|
|
|
174
275
|
## Execution and automatic batching
|
|
175
276
|
|
|
@@ -191,7 +292,12 @@ File changes are staged until program success. A throw before an external-mutati
|
|
|
191
292
|
barrier rolls them back. Shell execution flushes preceding changes; external shell
|
|
192
293
|
side effects cannot be rolled back. Stale commits fail explicitly rather than
|
|
193
294
|
silently overwriting successful concurrent changes. This is not a cross-process
|
|
194
|
-
filesystem lock.
|
|
295
|
+
filesystem lock. Outcomes explicitly report committed/rolledBack **file versions**
|
|
296
|
+
(counted per flush/checkpoint, not unique paths) and external-call attempts. A
|
|
297
|
+
successful inner checkpoint merges into the program, not necessarily onto disk.
|
|
298
|
+
Pending commits or failed recovery are reported as uncertain: inspect disk and
|
|
299
|
+
recovery backups before retrying. Import-based mutations and shell side effects
|
|
300
|
+
are outside the VFS counters; this is not a filesystem audit.
|
|
195
301
|
|
|
196
302
|
`edit(async () => {...})` creates a nested filesystem checkpoint. It returns
|
|
197
303
|
`{ok:true,committed:true,value}` on success or `{ok:false,committed:false,error}` on
|
|
@@ -212,6 +318,10 @@ outside the active callback are rejected. Await the checkpoint before proceeding
|
|
|
212
318
|
strings and result types are unchanged. This is output framing, not source
|
|
213
319
|
compression. It is chosen only when shorter in characters than escaped output;
|
|
214
320
|
it does not guarantee lower billed tokens for every tokenizer or input.
|
|
321
|
+
Nested multiline strings use the same approach: the complete value structure
|
|
322
|
+
references `raw[n]`, followed by length-delimited verbatim string blocks. Literal
|
|
323
|
+
`"raw[0]"` values stay quoted; duplicate source is never deduplicated. Small values
|
|
324
|
+
keep their existing format. Machine-facing result values are unchanged.
|
|
215
325
|
- Intermediate values stay inside CodeMode unless returned or logged. Final text,
|
|
216
326
|
errors and logs are bounded with explicit truncation. Details support rendering;
|
|
217
327
|
they are not a second model-facing transcript.
|
|
@@ -220,6 +330,12 @@ outside the active callback are rejected. Await the checkpoint before proceeding
|
|
|
220
330
|
|
|
221
331
|
Default limits are in `src/config/config.default.json`. Configuration loads from
|
|
222
332
|
`~/.pi/agent/supernova.json`, the configured host directory, or `PI_SUPERNOVA_CONFIG`.
|
|
333
|
+
|
|
334
|
+
Citation elision is **disabled by default** (`seenWindow: 0`): each result remains
|
|
335
|
+
self-contained within the normal output budgets. A positive `seenWindow` explicitly
|
|
336
|
+
opts into an experimental ledger with known retention gaps: hidden message details,
|
|
337
|
+
later context transforms and missing citation targets can invalidate its assumptions.
|
|
338
|
+
It is not a proven lossless optimization and is not recommended for production.
|
|
223
339
|
Text limits are character budgets, not tokenizer counts. `/supernova` reports
|
|
224
340
|
programs and output characters without labelling characters as tokens.
|
|
225
341
|
|
|
@@ -259,7 +375,9 @@ privileges. Do not run untrusted programs as though these adapters isolate them.
|
|
|
259
375
|
Pi preflights the outer `supernova` call. Internal primitives do not emit ordinary
|
|
260
376
|
native `tool_call` events, so third-party guards that only recognize top-level
|
|
261
377
|
`edit` or `bash` need CodeMode-aware handling. Configured exclusions and supported
|
|
262
|
-
host-session execution safeguards remain enforced.
|
|
378
|
+
host-session execution safeguards remain enforced. Guards inspecting code/file
|
|
379
|
+
inputs must also understand the programs array; its entries do not emit separate
|
|
380
|
+
top-level tool_call events. Actual-host smoke checks are
|
|
263
381
|
not a claim that every third-party permission extension has been validated.
|
|
264
382
|
|
|
265
383
|
## Development and evidence
|
|
@@ -284,6 +402,7 @@ arbitrary wall-clock assertions.
|
|
|
284
402
|
npm test --prefix packages/pi-supernova
|
|
285
403
|
npm run lint:supernova
|
|
286
404
|
npm run measure --prefix packages/pi-supernova
|
|
405
|
+
npm run test:tokens --prefix packages/pi-supernova
|
|
287
406
|
|
|
288
407
|
PI_SUPERNOVA_PI_ROOT=/path/to/pi-coding-agent \
|
|
289
408
|
PI_SUPERNOVA_OMP=/path/to/omp \
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-09-12
|
|
4
|
+
|
|
5
|
+
- Report overlapping `supernova` calls from every participant in the wave, including the first-started call that finishes last. Start-order or finish-order counters missed that side; a peak concurrent count resets when the wave drains. Sequential calls, `programs` batches, and failed programs still do not leak a split hint. The regression forces the slower first program so the last-finisher case cannot flake under load.
|
|
6
|
+
|
|
7
|
+
- Shrink the standing tool definition without compressing source or results. Duplicate object-form restatements, schema prose already covered by the command list, and discoverable operational asides are gone; signatures and safety rules stay in the always-sent reference. Frozen six-call traffic is 14,970 / 14,787 tokens (o200k / cl100k): 19.23% / 19.24% below d444eb7. The current-pass gate now requires 19% vs d444eb7.
|
|
8
|
+
|
|
9
|
+
- An unmatched or non-unique edit keeps the file and returns a numbered window of the actual source (16-line cap, same coordinates as a successful edit) so the next program can copy oldText without a blind re-read. Successful read/write/edit results are unchanged.
|
|
10
|
+
|
|
11
|
+
- A program that writes or edits and returns nothing still delivers those mutation receipts (numbered post-edit lines, `wrote` paths). Reads without a return stay a no-return hint and do not dump file contents. Explicit `return await edit(...)` is not duplicated.
|
|
12
|
+
|
|
13
|
+
- `edit(view, text)` replaces a `resolve:true` window by line span with CAS against the viewed bytes. Duplicate substrings no longer block a ranged edit; a stale view fails and rolls back. The silent receipt names that span (`edited path:2-2`), not a ±2 context window.
|
|
14
|
+
|
|
15
|
+
- A `resolve:true` snap of a declaration is that declaration's span, not the whole file just because the file fits the read budget. `edit(view, text)` then replaces the function, not the file. `edit(view, old, new)` is unique inside that span. A budget-clipped view (`nextOffset`) is not editable.
|
|
16
|
+
|
|
17
|
+
- Gravity: `read("symbol")` is the same view as `read({query, resolve:true})`. `read(path)` stays raw text. `looksLikePath` lives in `shared/decode.js` so guest and host share the identifier-vs-path rule.
|
|
18
|
+
|
|
19
|
+
- Nested declaration spans: a parent still includes its body (brace-matched from the opening line), one-line class methods resolve, and two exact same-name declarations in one file are ambiguous instead of snapping the first. Ambiguous candidates (same-file or cross-file) are that hit's span (signature, lines, text, context), not a clone of the first match's window. Span pick/slice live in `src/context/spans.js` for locate + host resolve.
|
|
20
|
+
|
|
21
|
+
- Do not subscribe a `context` observer when `seenWindow` is 0. A no-op listener still ran on every provider context event; opt-in retention windows still register.
|
|
22
|
+
|
|
23
|
+
- Encode the module BIND spine as a regression: acyclic imports, no upward edges, context and runtime stay siblings. host-bridge remains the fused INVOKE kernel.
|
|
24
|
+
|
|
25
|
+
- Drop guest/host RPC for `search` and `describe`, and stop returning unused `exec`/`patch`/`nova` bindings from the worker API. The guest still injects only read, write, edit, bash.
|
|
26
|
+
|
|
27
|
+
## [0.4.0] - 2026-09-10
|
|
28
|
+
|
|
29
|
+
- Disable citation elision by default (`seenWindow: 0`), including direct bridge/ledger defaults. A failure-first integration regression preserves complete results across hidden, reordered and removed context. Positive windows remain an explicit research opt-in, not a validated retention guarantee. The historical ledger measurements below describe that experimental mode only.
|
|
30
|
+
|
|
31
|
+
- Make the traffic gate able to see the retention ledger, and prove it can. The gate previously ran only a host that emits no lifecycle events, so it measured the conservative floor and could not observe the largest token lever in the package. It now also runs the frozen schedule against a production-shaped host that fires `context` before each request, comparing like for like against the unbatched baseline, and gates three things: an unobserved ceiling recorded after this pass, a floor requiring the observing host to beat the same schedule, and an anti-vacuity check requiring the fidelity assertion to have had a subject. Fidelity in that arm is asserted as elision-only rather than byte-equality: every surviving line must match in order and every citation must cover a run of exactly the lines it replaced.
|
|
32
|
+
- Add self-tests for the elision checker itself. A checker that cannot reject anything makes every gate that relies on it vacuous; seven failure-first cases (a vanished line, an overstated or understated citation, a sub-run citation, an invented line, a reordered elision) fail if the checker is weakened or reports that it saw nothing.
|
|
33
|
+
- Fix an information-loss bug the retention proof exposes: a program inside a `programs` batch could cite a peer in the same batch, whose result the model had not received yet. Nothing in a batch is collapsible against its own batch, and a regression now holds that line. The pre-existing frozen output assertion already caught this; it now has a named test.
|
|
34
|
+
- Record the observed-arm ceiling in `token-baseline.json` with provenance. The frozen workload is effectively read-once, so the ledger's saving on it is 0.77%/0.85%; repeat-heavy sessions measure 43.6% and are guarded by `tests/fidelity/ledger-retention.test.mjs`.
|
|
35
|
+
- Experimental only: retain the seen-ledger observation mechanism for research. Its earlier "retention proof" claim was invalid: metadata is not necessarily model-visible, context handlers can transform later, and a missing citation target is not rehydrated. The extension now subscribes to Pi's `context` hook and collapses a run only when those exact lines were observed in the messages about to be sent. The blanket `seenWindow: 0` existed because local cache residency cannot establish model-context residency; the pre-conversion host observation does not establish final-payload residency. Future collapse stops when lines disappear from the observation, but existing citations can still be dangling; a citation is never evidence of its own contents, and citations never nest. Observation costs ~1.7 ms per request on a 0.87 MB payload. On a 12-call repeated-read session: 42.8% fewer published result characters and 31.0% less cumulative replay. Changed lines are still never collapsed, explicit offset/limit reads stay pinned, and a host that never fires `context` publishes byte-identical results, so the frozen `events` and the batched arm of the gate are untouched; only a new observed-arm ceiling was added to the baseline.
|
|
36
|
+
- Consolidate overlapping tests into multi-operation failure-and-repair contracts covering JSON, saved programs, checkpoints, literal argv, images and concurrent workspaces. Retain distinct admission, isolation and resource-limit regressions.
|
|
37
|
+
- Fix truncation reporting for complete tool responses, including logs and wrapper metadata; make log-limit omissions visible in model-facing output.
|
|
38
|
+
- Remove duplicate startup guidance and batch wrapper metadata while retaining every original per-program result. The unchanged six-call benchmark uses another 5.15%/5.17% fewer tokens than d444eb7; add a request-hash guard against moving model decision boundaries.
|
|
39
|
+
|
|
40
|
+
- Add explicit sequential `programs` batches with fresh guests and separate commits. Preserve complete per-program text and earlier images in typed stop reports; share deadlines, host calls, logs and outer output/image limits. Reject malformed/nested/oversized plans before execution.
|
|
41
|
+
- Make the additional 40% token gate part of `npm test`, with a frozen post-previous-pass baseline, exact logical-result checks, both tokenizers, full tool-history replay and the final answer handoff. Measured 56.19%/56.26% fewer modeled tool tokens for the fixed workload; retain the full startup reference. No provider billing or model-quality claim.
|
|
42
|
+
|
|
43
|
+
- Add explicit workspace program-file input as an alternative to inline code, with fresh loading/guests, strict bounded UTF-8 admission and unchanged deadlines/transactions. No implicit replay or persistent heap.
|
|
44
|
+
- Extend verbatim string framing to nested source results, preserving all fields, types, duplicate strings and lengths; retain compact scalar output. Remove redundant guidance already present in parameter/command descriptions.
|
|
45
|
+
- Add reproducible two-tokenizer measurements and package comparisons in `TOKEN_COSTS.md`, including creation/definition overhead and explicit no-claim boundaries for billing and end-to-end quality.
|
|
46
|
+
|
|
47
|
+
- Stress follow-up: budget each JSON selector before allocating the next slice, reject non-regular JSON inputs without blocking on FIFO open, and reject sparse selector/path/edit arrays. Add a heap-limited host-survival regression, exact input boundaries, concurrent queried-resource isolation, and failed-recovery backup verification. The mixed stress lane now exercises literal input data and JSON projection.
|
|
48
|
+
|
|
49
|
+
- Add literal tool-level `data` input for Markdown/scripts/argv without nested JavaScript quoting; parse failures explicitly state no commands ran.
|
|
50
|
+
- Parse full JSON before bounded field/index/slice projection with `read({path,json})`, including session `?q=.answer` resources. Reject invalid selectors, missing fields, oversized inputs/selections and incompatible read options. Oversized unwindowed plain JSON reads fail with actionable guidance.
|
|
51
|
+
- Validate edit overloads before dispatch and show supported signatures, without touching a file on invalid input.
|
|
52
|
+
- Report committed/rolledBack file versions and external-call attempts on failure, and distinguish uncertain commit recovery from complete rollback.
|
|
53
|
+
- Advertise direct image viewing and targeted large-text reads in model-facing guidance. Add Spark papercut regressions through the registered tool and real worker.
|
|
54
|
+
|
|
3
55
|
## [0.3.2] - 2026-09-07
|
|
4
56
|
|
|
5
57
|
- Focus `read(path,{about})` on matching line windows in unstructured logs/text instead of returning a truncated unrelated prefix; report no matches explicitly.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Token usage and benchmarks
|
|
2
|
+
|
|
3
|
+
Supernova reduces repeated tool traffic through explicit program reuse and batching.
|
|
4
|
+
It can also reduce escaping in nested multiline results with lossless text framing.
|
|
5
|
+
These mechanisms do not summarize results, rewrite conversation history, or change
|
|
6
|
+
reasoning settings. Savings depend on the workload.
|
|
7
|
+
|
|
8
|
+
See the [API guide](../README.md) for program-file and batch usage.
|
|
9
|
+
|
|
10
|
+
## Reproduce
|
|
11
|
+
|
|
12
|
+
From a repository checkout with development dependencies installed:
|
|
13
|
+
|
|
14
|
+
~~~sh
|
|
15
|
+
npm run test:tokens --prefix packages/pi-supernova
|
|
16
|
+
npm test --prefix packages/pi-supernova
|
|
17
|
+
~~~
|
|
18
|
+
|
|
19
|
+
The benchmark uses js-tiktoken 1.0.21, pinned as a development dependency. It runs
|
|
20
|
+
real Supernova programs in temporary workspaces without provider calls or downloads.
|
|
21
|
+
The token regression gate also runs in the normal test suite.
|
|
22
|
+
|
|
23
|
+
## Workload
|
|
24
|
+
|
|
25
|
+
The baseline is a frozen, non-batched implementation snapshot with program-file
|
|
26
|
+
reuse and nested source framing already enabled. It is not a comparison against
|
|
27
|
+
a separately published release.
|
|
28
|
+
|
|
29
|
+
| Scenario | Baseline calls | Batched calls |
|
|
30
|
+
| --- | ---: | ---: |
|
|
31
|
+
| Inspect source, reproduce a failure, repair and verify | 4 | 3 |
|
|
32
|
+
| Inspect, update and verify a JSON report | 3 | 2 |
|
|
33
|
+
| Create an audit program and run it for five search terms | 6 | 1 |
|
|
34
|
+
| **Total** | **13** | **6** |
|
|
35
|
+
|
|
36
|
+
Both executions perform the same 13 logical programs. The batch schedule is
|
|
37
|
+
hand-authored: it groups known edit-then-verify and create-then-audit continuations,
|
|
38
|
+
while keeping decision points after inspection and the failing check separate.
|
|
39
|
+
No model chooses the schedule during this test. The runtime does not infer plans
|
|
40
|
+
or contain benchmark-specific paths, search terms, or expected results.
|
|
41
|
+
|
|
42
|
+
This workload deliberately includes repeated audits that benefit from batching.
|
|
43
|
+
It is a reproducible regression fixture, not a representative sample of all agent
|
|
44
|
+
tasks or a guarantee of savings when a model decides how to use the tool.
|
|
45
|
+
|
|
46
|
+
## Accounting
|
|
47
|
+
|
|
48
|
+
For each model request, the benchmark counts:
|
|
49
|
+
|
|
50
|
+
- The serialized Supernova definition: description, parameters and prompt guidance.
|
|
51
|
+
- All preceding tool arguments and complete result text in the request history.
|
|
52
|
+
- Newly generated tool arguments, serialized as JSON.
|
|
53
|
+
|
|
54
|
+
It also counts the definition and full tool history sent for the final answer
|
|
55
|
+
request. A newly produced tool result is counted when the next model request
|
|
56
|
+
consumes it, not twice. Program creation is included. The complete startup
|
|
57
|
+
reference is retained, so this workload needs no separate discovery call.
|
|
58
|
+
|
|
59
|
+
Formally, with definition cost D, generated argument cost A_i, result cost R_i,
|
|
60
|
+
and prior tool-history cost H_i = sum(A_j + R_j) for j < i:
|
|
61
|
+
|
|
62
|
+
~~~text
|
|
63
|
+
Total = sum(D + A_i + H_i, i = 1..N) + D + H_(N+1)
|
|
64
|
+
~~~
|
|
65
|
+
|
|
66
|
+
This assumes full tool-history replay. The JSON report includes per-scenario
|
|
67
|
+
breakdowns. Its results field records newly produced text for inspection; that
|
|
68
|
+
text contributes to totals through later history, not as a second charge.
|
|
69
|
+
|
|
70
|
+
## Measured results
|
|
71
|
+
|
|
72
|
+
Observed on macOS with Node v26.7.0.
|
|
73
|
+
|
|
74
|
+
| Tokenizer | Non-batched baseline | Batched baseline (d444eb7) | Current | Further reduction | Total reduction |
|
|
75
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
76
|
+
| o200k_base | 28,130 | 18,535 | 9,537 | **48.55%** | **66.10%** |
|
|
77
|
+
| cl100k_base | 27,841 | 18,310 | 9,420 | **48.55%** | **66.17%** |
|
|
78
|
+
|
|
79
|
+
The gate requires at least 40% reduction on **each tokenizer for the complete
|
|
80
|
+
workload**, not for every scenario individually. Token counts and reductions are
|
|
81
|
+
computed from the recorded baseline and fresh execution results, not constants
|
|
82
|
+
returned by the runtime. A second gate requires another 19% against the measured
|
|
83
|
+
batched baseline from commit d444eb7. Its six-call argument hash is pinned as well
|
|
84
|
+
as the original workload: removing a decision boundary cannot satisfy this gate.
|
|
85
|
+
|
|
86
|
+
### What changed after the batched baseline
|
|
87
|
+
|
|
88
|
+
The serialized definition falls from 1,068 to 577 tokens with o200k_base and from
|
|
89
|
+
1,057 to 572 with cl100k_base. Duplicate object-form restatements, parameter
|
|
90
|
+
prose already covered by the command list, and discoverable operational asides
|
|
91
|
+
were removed; command signatures and safety rules (`complete:true`, JSON 16 MiB /
|
|
92
|
+
no jq, array-read rejection, transactions, `programs` batch, edit oldText as an
|
|
93
|
+
exact substring, `edit(view,text)`) remain in the standing reference. No source
|
|
94
|
+
text or independent result is removed or compressed.
|
|
95
|
+
|
|
96
|
+
For the fixed six-call schedule, the accounting can also be written as:
|
|
97
|
+
|
|
98
|
+
~~~text
|
|
99
|
+
Total = (N+1)*D + sum((N-i+2)*A_i + (N-i+1)*R_i, i = 1..N)
|
|
100
|
+
~~~
|
|
101
|
+
|
|
102
|
+
Seven definition appearances still save 7*491 = 3,437 tokens with o200k_base versus
|
|
103
|
+
d444eb7's 1,068-token definition. Snap-to-span then changed the first repair
|
|
104
|
+
observation from a whole-file view to the `MAX_JSON_BYTES` declaration
|
|
105
|
+
(`lines:[3,3]`, `complete:false`). That smaller result is replayed through later
|
|
106
|
+
requests; no source or independent result is compressed or dropped. Frozen
|
|
107
|
+
programs, arguments and decision boundaries are unchanged. Combined with
|
|
108
|
+
batching, current o200k traffic is 9,558 vs d444eb7's 18,535 (48.43%).
|
|
109
|
+
|
|
110
|
+
The current definition is now *below* the non-batched baseline (577 vs 908
|
|
111
|
+
o200k_base). Batching still adds result framing. One-off calls should not be
|
|
112
|
+
assumed to benefit from the batch API.
|
|
113
|
+
|
|
114
|
+
The report also includes separate source-framing and argument-reuse comparisons.
|
|
115
|
+
Those component measurements are not total-session savings, and the reported
|
|
116
|
+
argument-only break-even excludes other request costs. Text framing is selected
|
|
117
|
+
by character length, not a runtime tokenizer; it need not reduce tokens for every
|
|
118
|
+
input or encoding.
|
|
119
|
+
|
|
120
|
+
## Benchmark integrity
|
|
121
|
+
|
|
122
|
+
The [baseline fixture](../tests/efficiency/token-baseline.json) contains the source
|
|
123
|
+
inputs, definition, workload hash, arguments and complete outputs. The
|
|
124
|
+
[runner](../tests/efficiency/workflow.mjs) executes the registered tool with real
|
|
125
|
+
workers and filesystem operations. It checks that:
|
|
126
|
+
|
|
127
|
+
- The workload hash matches the frozen baseline, and the six-call argument hash
|
|
128
|
+
matches the prior batched execution.
|
|
129
|
+
- Every original argument, complete logical result and expected failure matches.
|
|
130
|
+
- Batched output contains every original result, with no unaccounted outer text.
|
|
131
|
+
- No result is truncated, and final repaired source and JSON contents match.
|
|
132
|
+
|
|
133
|
+
Only run IDs, elapsed times and temporary workspace prefixes in write receipts
|
|
134
|
+
are normalized. Batch framing lengths are adjusted to match that normalized text.
|
|
135
|
+
The workload, batch schedule, recorded comparison totals and acceptance thresholds
|
|
136
|
+
are fixed test inputs, not production execution rules. The baseline is not regenerated by the benchmark.
|
|
137
|
+
|
|
138
|
+
Recorded baseline SHA-256:
|
|
139
|
+
|
|
140
|
+
~~~text
|
|
141
|
+
79a819eca82c8a5ff381e96b7669d8a5bf04fabbc8c10cf02f3a7c8817171b62
|
|
142
|
+
~~~
|
|
143
|
+
|
|
144
|
+
## Limitations
|
|
145
|
+
|
|
146
|
+
- These are local estimates of model tool-token traffic, not provider billing.
|
|
147
|
+
Provider-specific envelopes, unrelated user/system messages, reasoning tokens,
|
|
148
|
+
image token costs and cache discounts are excluded.
|
|
149
|
+
- There is no live-model A/B quality evaluation. Preserving observations and
|
|
150
|
+
reasoning settings does not establish unchanged end-to-end task quality.
|
|
151
|
+
- Batching is appropriate only for already-chosen continuations. Actions requiring
|
|
152
|
+
a new model decision must remain separate calls.
|
|
153
|
+
- Existing read, output, log, image and execution limits still apply. The
|
|
154
|
+
benchmark does not obtain savings by lowering them or hiding truncation.
|
|
155
|
+
|
|
156
|
+
## Design references
|
|
157
|
+
|
|
158
|
+
These sources informed the implementation choices; the measurements above compare
|
|
159
|
+
Supernova implementations only, not the performance of these packages.
|
|
160
|
+
|
|
161
|
+
| Reference | Mechanisms studied |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| [pi-codex-conversion 3.0.31](https://github.com/IgorWarzocha/howaboua-pi-stuff/tree/94eb6c0745e2f516bf19603f912f7b6478b43355) | Code transport, concise signatures and deferred discovery |
|
|
164
|
+
| [pi-codemcp](https://github.com/yolonir/pi-codemcp) | Saved call chains and intermediate results |
|
|
165
|
+
| [Ian Pascoe's pi-codemode](https://github.com/ian-pascoe/pi-extensions/tree/main/packages/pi-codemode) | Notebook state and tool declarations |
|
|
166
|
+
| [Nick Nisi's codemode](https://github.com/nicknisi/pi-extensions/tree/main/packages/codemode) | Named snippets and explicit composition |
|
|
167
|
+
| [Boozedog's pi-codemode 0.3.0](https://github.com/boozedog/pi-codemode/tree/1390c938ef4f23a0d50b814e7e3a14c03a08d39d) | Literal inputs and typed CLI capabilities |
|
|
168
|
+
| [pi-cache-optimizer 2.8.2](https://github.com/jiangge/pi-cache-optimizer) | Cache-prefix and prompt handling |
|
|
169
|
+
|
|
170
|
+
Unpinned repository links refer to inspected source, not independently verified
|
|
171
|
+
package versions. Supernova retains fresh guests, explicit transaction boundaries
|
|
172
|
+
and its general command surface rather than adopting persistent notebook state,
|
|
173
|
+
restricted CLI catalogs or provider/history rewriting.
|