pi-supernova 0.5.0 → 0.6.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 +73 -11
- package/docs/CHANGELOG.md +46 -0
- package/docs/TOKEN_COSTS.md +63 -29
- package/index.js +7 -4
- package/package.json +2 -2
- package/src/bridge/catalog.js +14 -10
- package/src/bridge/host-bridge.js +810 -145
- package/src/bridge/native-tools.js +16 -6
- package/src/context/evidence.js +13 -5
- package/src/context/fuzzy.js +34 -13
- package/src/context/outline.js +11 -2
- package/src/context/repo-index.js +150 -15
- package/src/context/search.js +70 -17
- package/src/context/snap.js +98 -46
- package/src/context/surface.js +15 -9
- package/src/fs/check.js +10 -2
- package/src/fs/patch.js +4 -2
- package/src/fs/vfs.js +133 -36
- package/src/fs/workspace.js +7 -1
- package/src/output/bottleneck.js +36 -11
- package/src/output/format.js +44 -29
- package/src/runtime/guest-worker.js +135 -39
- package/src/runtime/parallel.js +4 -1
- package/src/runtime/program-batch.js +17 -6
- package/src/runtime/program-file.js +6 -3
- package/src/runtime/reference.js +5 -5
- package/src/runtime/runtime.js +17 -6
- package/src/shared/decode.js +15 -3
- package/src/ui/omp-frame.js +11 -4
- package/src/ui/render.js +2 -2
package/README.md
CHANGED
|
@@ -12,6 +12,20 @@ Ordinary JavaScript control flow remains available; the guest command bindings
|
|
|
12
12
|
are only `read`, `edit`, `write`, and `bash`. Supernova supplies retrieval,
|
|
13
13
|
transactional file operations, batching, bounded results and the grouped nova UI.
|
|
14
14
|
|
|
15
|
+
## What is new in 0.6.0
|
|
16
|
+
|
|
17
|
+
- **Shared batch input:** supply top-level `data` once; each program gets an
|
|
18
|
+
independent copy unless it supplies its own replacement data.
|
|
19
|
+
- **Conflict protection:** byte snapshots survive partial reads and body-cache
|
|
20
|
+
eviction; receipt generation cannot silently rebase a pending write.
|
|
21
|
+
- **Read fidelity:** staged declarations remain discoverable in large/new files,
|
|
22
|
+
line windows preserve source endings, and `complete` always means the whole file.
|
|
23
|
+
- **Explicit failures:** incompatible read modes, budget-limited matches, captured
|
|
24
|
+
overrides and conflicting new-file aliases no longer silently change outcomes.
|
|
25
|
+
|
|
26
|
+
See the [changelog](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/docs/CHANGELOG.md)
|
|
27
|
+
and [token measurements](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/docs/TOKEN_COSTS.md).
|
|
28
|
+
|
|
15
29
|
## Install and update
|
|
16
30
|
|
|
17
31
|
Install the published package in your host:
|
|
@@ -29,9 +43,19 @@ pi install /path/to/pi-stack/packages/pi-supernova
|
|
|
29
43
|
|
|
30
44
|
Git pushes do not update npm installations. Publish the new npm version first;
|
|
31
45
|
then reinstall it in the host. Reinstall explicitly when an existing version
|
|
32
|
-
range excludes the new minor version (
|
|
46
|
+
range excludes the new minor version (`^0.5.0` excludes `0.6.0`). After 0.6.0 is
|
|
47
|
+
published, pin that release with:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pi install npm:pi-supernova@0.6.0
|
|
51
|
+
omp install npm:pi-supernova@0.6.0
|
|
52
|
+
```
|
|
33
53
|
|
|
34
|
-
|
|
54
|
+
In Pi, `pi list` shows the configured package sources. A local path uses that
|
|
55
|
+
checkout directly; an npm source uses the installed npm copy. Do not assume that
|
|
56
|
+
pushing a checkout or running `/reload` updates the copy executing in your host.
|
|
57
|
+
|
|
58
|
+
Both host manifests use `index.js`. The old `src/bridge/pi-extension.ts` path
|
|
35
59
|
remains a compatibility entrypoint but no longer imports Pi tool factories.
|
|
36
60
|
After updating JavaScript sources, fully exit Pi and resume in a new process.
|
|
37
61
|
Pi 0.85.1 can retain native ESM modules across `/reload`, even after its extension
|
|
@@ -54,7 +78,7 @@ settings. The runtime does not silently rewrite your tool policy.
|
|
|
54
78
|
| `read` | `read({query,resolve:true})`; same view as `read("symbol")`: status, path, line, lines, text, complete |
|
|
55
79
|
| `read` | `read({query,evidence:true})`; ranked evidence with provenance; optional `path` scopes discovery |
|
|
56
80
|
| `read` | `read({path,outline:true})`; structural declarations |
|
|
57
|
-
| `read` | `read([path1,path2])`; up to 64 paths, ordered values
|
|
81
|
+
| `read` | `read([path1,path2])`; up to 64 paths, ordered values; rejects if any path fails |
|
|
58
82
|
| `edit` | `edit(path,oldText,newText)`, `edit({path,edits:[{oldText,newText}]})`; unique in the file |
|
|
59
83
|
| `edit` | `edit(view,text)` CAS-replaces that span; `edit(view,old,new)` is unique inside it |
|
|
60
84
|
| `edit` | `edit({path,patch})`; unified patch application |
|
|
@@ -75,7 +99,8 @@ Source questions locate a declaration in one command. An exact
|
|
|
75
99
|
declaration match uses one bounded direct ripgrep search, without a prerequisite
|
|
76
100
|
file listing, persistent index, embeddings or summarization. A transient filename
|
|
77
101
|
listing is a fallback for unmatched content or unresolved bare filenames. Natural-language
|
|
78
|
-
questions reuse lexical stemming.
|
|
102
|
+
questions reuse lexical stemming. Source questions and focused `about` reads
|
|
103
|
+
accept at most 16 keywords. Ripgrep must be available on PATH.
|
|
79
104
|
|
|
80
105
|
`read(path)` stays raw text. `read("symbol")` is the same view as
|
|
81
106
|
`read({query, resolve:true})` — not the file, not a path/range header:
|
|
@@ -90,7 +115,13 @@ The view contains `status`, `path`, the matching `line`, span `lines`, unchanged
|
|
|
90
115
|
`text`, `complete`, and `nextOffset` when a budget clip continues. A declaration
|
|
91
116
|
snap is that span (`complete` is false unless the span is the whole file). Uncertain
|
|
92
117
|
results report `ambiguous`, `not_found` or `incomplete` with no selected path.
|
|
93
|
-
Use `{path: directory, about: question}` to narrow the scope.
|
|
118
|
+
Use `{path: directory, about: question}` to narrow the scope. Scoping a query
|
|
119
|
+
does not relabel a selected span as a complete file. Newly staged files and large
|
|
120
|
+
staged source participate in discovery before commit. Raw offset/limit windows
|
|
121
|
+
preserve LF/CRLF endings and the final newline; focused views add line labels.
|
|
122
|
+
A matching window too large for the output budget is reported as budget-limited,
|
|
123
|
+
not as an absent match. Do not combine incompatible modes such as `outline:true`
|
|
124
|
+
and `evidence:true`.
|
|
94
125
|
|
|
95
126
|
Ordinary reads stay self-contained. Outlines and graph evidence remain explicit
|
|
96
127
|
options, not mandatory stages of source resolution. Ordinary calls also get:
|
|
@@ -122,6 +153,14 @@ For intentionally writing literal marker documentation only, opt in with
|
|
|
122
153
|
`write({path,content,allowReadArtifacts:true})`. This is a data-loss guard, not
|
|
123
154
|
full dataflow tracking or a security sandbox.
|
|
124
155
|
|
|
156
|
+
Read/modify/write conflict checks retain a signature of the actual disk bytes,
|
|
157
|
+
including for partial and large-file reads. A fresh explicit text read refreshes
|
|
158
|
+
that observation; internal receipt reads and body-cache eviction do not. Commits
|
|
159
|
+
reject changed content and conflicting symlink aliases, including new file paths.
|
|
160
|
+
These checks do not provide a cross-process lock or make shell/import mutations
|
|
161
|
+
transactional. Extensionless filenames also support `complete:true`, for example
|
|
162
|
+
`read({path:"LICENSE",complete:true})`.
|
|
163
|
+
|
|
125
164
|
Explicit read arrays reject missing/failed paths. For typed partial outcomes use
|
|
126
165
|
`Promise.allSettled(paths.map(path => read(path)))`. Successful arrays remain arrays.
|
|
127
166
|
For literal file content or scripts, prefer the optional tool-level `data` parameter:
|
|
@@ -136,8 +175,9 @@ For literal file content or scripts, prefer the optional tool-level `data` param
|
|
|
136
175
|
}
|
|
137
176
|
```
|
|
138
177
|
|
|
139
|
-
`data` crosses the worker boundary as JSON, never as JavaScript source.
|
|
140
|
-
JSON-encoded length is capped separately at `maxCodeChars`;
|
|
178
|
+
`data` crosses the worker boundary as JSON, never as JavaScript source. For a
|
|
179
|
+
single program its JSON-encoded length is capped separately at `maxCodeChars`;
|
|
180
|
+
batches use the combined admission budget described below. Split larger inputs.
|
|
141
181
|
The binding exists only when supplied, so older programs declaring their own `data`
|
|
142
182
|
remain valid. Syntax errors run no commands and give quoting guidance. For inline
|
|
143
183
|
source, use `String.raw` (escaping backtick delimiters) or JSON-quoted strings.
|
|
@@ -179,7 +219,7 @@ no truncated prefix is executed. Review untrusted source before running it.
|
|
|
179
219
|
Use ordinary `edit` to revise saved programs. This is explicit source reuse, not
|
|
180
220
|
conversation compression: prior calls and read results remain intact. Creation
|
|
181
221
|
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).
|
|
222
|
+
for short one-off operations. See [token measurements](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/docs/TOKEN_COSTS.md).
|
|
183
223
|
|
|
184
224
|
### Batch already-known continuations
|
|
185
225
|
|
|
@@ -194,12 +234,32 @@ for short one-off operations. See [token measurements](docs/TOKEN_COSTS.md).
|
|
|
194
234
|
}
|
|
195
235
|
~~~
|
|
196
236
|
|
|
197
|
-
Use programs instead of top-level code/file
|
|
198
|
-
code OR file and optional data
|
|
237
|
+
Use programs instead of top-level code/file. Supply 1--32 entries, each with
|
|
238
|
+
code OR file and optional data. Top-level data supplies an optional default for
|
|
239
|
+
each entry; explicit entry data replaces it entirely, including null, false, 0
|
|
240
|
+
and empty strings. Every guest receives its own copy, not a shared mutable heap.
|
|
241
|
+
The JSON-encoded array (or `{programs,data}` when defaults are supplied) must fit
|
|
242
|
+
maxCodeChars. Common input counts once; result representations and output limits are unchanged.
|
|
199
243
|
Entries run sequentially in fresh guests and commit separately. A successful
|
|
200
244
|
entry can create the file executed by a later entry. No implicit retries,
|
|
201
245
|
reordering, shared heap or nested batches are introduced.
|
|
202
246
|
|
|
247
|
+
For independent audits that use the same inputs, send them once:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"data": {"paths": ["src/a.js", "src/b.js"]},
|
|
252
|
+
"programs": [
|
|
253
|
+
{"code": "return await read(data.paths);"},
|
|
254
|
+
{"code": "return await Promise.all(data.paths.map(path => read({path, outline:true})));"}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
This avoids repeating literal arguments, without a compression codec or result elision.
|
|
260
|
+
Mutating `data` in one guest cannot affect the next. An entry with `data:null`
|
|
261
|
+
receives null, not the shared object; there is no implicit object merge.
|
|
262
|
+
|
|
203
263
|
The batch stops on the first failed entry, cancellation/deadline, or exhausted
|
|
204
264
|
output/log/image budget. Earlier successful commits remain; only the active
|
|
205
265
|
program's uncommitted writes roll back. Admission errors throw before any program.
|
|
@@ -266,6 +326,8 @@ plain .json reads also fail with a projection hint. Explicit offset/limit or
|
|
|
266
326
|
resolve:true still allow raw inspection, but line windows are not JSON documents.
|
|
267
327
|
Do not combine json with complete, line windows, or source views. External read
|
|
268
328
|
overrides reject JSON projection rather than silently ignoring the option.
|
|
329
|
+
Other read options, even false-valued flags, do not bypass a captured external
|
|
330
|
+
read executor; its policy, transforms and failures remain authoritative.
|
|
269
331
|
|
|
270
332
|
For large Markdown/log path audits, use read(path,{about:"document path"}) or
|
|
271
333
|
explicit offset/limit, not complete:true. Larger JSON needs a streaming parser via
|
|
@@ -424,7 +486,7 @@ not hard real-time guarantees.
|
|
|
424
486
|
It excludes model latency, provider tokens and prewarm time; it is not a universal
|
|
425
487
|
comparison against every CodeMode implementation.
|
|
426
488
|
|
|
427
|
-
See [the changelog](docs/CHANGELOG.md) for changes and compatibility notes.
|
|
489
|
+
See [the changelog](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/docs/CHANGELOG.md) for changes and compatibility notes.
|
|
428
490
|
|
|
429
491
|
## Research and prior art
|
|
430
492
|
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-09-15
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Shared literal input for `programs`: top-level `data` defaults each entry, while
|
|
8
|
+
explicit entry data replaces it entirely, including falsy values. Every fresh
|
|
9
|
+
guest receives its own copy. The combined JSON admission budget counts common
|
|
10
|
+
input once; deadlines, host-call limits, separate commits and stop reports stay
|
|
11
|
+
unchanged. No implicit object merge, shared heap or inferred plan is introduced.
|
|
12
|
+
|
|
13
|
+
### Hardened execution and reads
|
|
14
|
+
|
|
15
|
+
- Keep byte-accurate conflict snapshots independent of receipt/body caches.
|
|
16
|
+
Explicit rereads refresh observations; internal diff reads and cache eviction do
|
|
17
|
+
not rebase pending writes. Partial and focused reads retain full-file signatures,
|
|
18
|
+
including above 16 MiB, and invalid UTF-8 no longer causes a false conflict.
|
|
19
|
+
- Canonicalize new-file destinations before checking conflicting symlink aliases,
|
|
20
|
+
while preserving the existing logical paths in workspace-change notifications.
|
|
21
|
+
- Preserve read/mutation/checkpoint ordering across coalesced read waves. Tighten
|
|
22
|
+
input validation, cancellation handling and bounded output without reusing an
|
|
23
|
+
executed worker or reducing individual independent-read budgets.
|
|
24
|
+
- Keep captured read overrides authoritative when options are supplied. Align
|
|
25
|
+
native/guest evidence results and path-array aliases; reject incompatible modes
|
|
26
|
+
and enforce the same focused-query keyword cap for disk and staged content.
|
|
27
|
+
- Discover newly staged declarations in file-scoped queries and large overlays.
|
|
28
|
+
Preserve line endings, EOF characters and post-edit line coordinates. Distinguish
|
|
29
|
+
absent matches from matches that exceed the view budget. `complete` consistently
|
|
30
|
+
means the whole file; extensionless paths support `complete:true`.
|
|
31
|
+
|
|
32
|
+
### Documentation and verification
|
|
33
|
+
|
|
34
|
+
- Document shared-input examples, commit/rollback and override boundaries, and the
|
|
35
|
+
need for a full host restart after JavaScript updates. `/reload` can retain old
|
|
36
|
+
native ESM modules; pushing GitHub does not update an npm installation.
|
|
37
|
+
- Restore the historical token fixture and hash-lock it. Version the single
|
|
38
|
+
terminating-newline expectation separately, without changing historical traffic,
|
|
39
|
+
programs, decision boundaries or acceptance thresholds.
|
|
40
|
+
- Add failure-first regressions for reviewed and newly found defects. Correct
|
|
41
|
+
oversized fixtures, non-finite timeout inputs and misleading test descriptions.
|
|
42
|
+
- Measure shared-input audits with identical complete outputs: 16,309 to 5,499
|
|
43
|
+
tokens (o200k_base) and 14,649 to 5,197 (cl100k_base), including replay, result
|
|
44
|
+
framing and added standing guidance. These are workload-specific non-compressive
|
|
45
|
+
savings, not provider-billing or live-model quality claims. See
|
|
46
|
+
[token measurements](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/docs/TOKEN_COSTS.md)
|
|
47
|
+
for the unchanged historical gates, accounting and reproduction commands.
|
|
48
|
+
|
|
3
49
|
## [0.5.0] - 2026-09-12
|
|
4
50
|
|
|
5
51
|
- 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.
|
package/docs/TOKEN_COSTS.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Token usage and benchmarks
|
|
2
2
|
|
|
3
|
-
Supernova reduces repeated tool traffic through explicit program reuse
|
|
3
|
+
Supernova reduces repeated tool traffic through explicit program reuse, batching
|
|
4
|
+
and shared batch input defaults.
|
|
4
5
|
It can also reduce escaping in nested multiline results with lossless text framing.
|
|
5
6
|
These mechanisms do not summarize results, rewrite conversation history, or change
|
|
6
7
|
reasoning settings. Savings depend on the workload.
|
|
7
8
|
|
|
8
|
-
See the [API guide](
|
|
9
|
+
See the [API guide](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/README.md) for program-file and batch usage.
|
|
9
10
|
|
|
10
11
|
## Reproduce
|
|
11
12
|
|
|
@@ -69,12 +70,12 @@ text contributes to totals through later history, not as a second charge.
|
|
|
69
70
|
|
|
70
71
|
## Measured results
|
|
71
72
|
|
|
72
|
-
Observed on macOS
|
|
73
|
+
Observed for 0.6.0 on 2026-09-15, on an Apple M5 Max running macOS and Node v26.7.0.
|
|
73
74
|
|
|
74
75
|
| Tokenizer | Non-batched baseline | Batched baseline (d444eb7) | Current | Further reduction | Total reduction |
|
|
75
76
|
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
76
|
-
| o200k_base | 28,130 | 18,535 | 9,
|
|
77
|
-
| cl100k_base | 27,841 | 18,310 | 9,
|
|
77
|
+
| o200k_base | 28,130 | 18,535 | 9,843 | **46.90%** | **65.01%** |
|
|
78
|
+
| cl100k_base | 27,841 | 18,310 | 9,726 | **46.88%** | **65.07%** |
|
|
78
79
|
|
|
79
80
|
The gate requires at least 40% reduction on **each tokenizer for the complete
|
|
80
81
|
workload**, not for every scenario individually. Token counts and reductions are
|
|
@@ -83,15 +84,12 @@ returned by the runtime. A second gate requires another 19% against the measured
|
|
|
83
84
|
batched baseline from commit d444eb7. Its six-call argument hash is pinned as well
|
|
84
85
|
as the original workload: removing a decision boundary cannot satisfy this gate.
|
|
85
86
|
|
|
86
|
-
###
|
|
87
|
+
### Definition and result accounting
|
|
87
88
|
|
|
88
|
-
The serialized definition
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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.
|
|
89
|
+
The current serialized definition is 631 tokens with o200k_base and 626 with
|
|
90
|
+
cl100k_base, versus 908 and 901 in the frozen non-batched baseline. It retains
|
|
91
|
+
command signatures, complete-read and JSON limits, array-read failure rules,
|
|
92
|
+
transaction boundaries, batch defaults and edit/view guidance on every request.
|
|
95
93
|
|
|
96
94
|
For the fixed six-call schedule, the accounting can also be written as:
|
|
97
95
|
|
|
@@ -99,17 +97,9 @@ For the fixed six-call schedule, the accounting can also be written as:
|
|
|
99
97
|
Total = (N+1)*D + sum((N-i+2)*A_i + (N-i+1)*R_i, i = 1..N)
|
|
100
98
|
~~~
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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.
|
|
100
|
+
The definition is counted seven times, including the final handoff. Batch result
|
|
101
|
+
framing and every attempted program's text are counted too. One-off calls should
|
|
102
|
+
not be assumed to benefit from batching.
|
|
113
103
|
|
|
114
104
|
The report also includes separate source-framing and argument-reuse comparisons.
|
|
115
105
|
Those component measurements are not total-session savings, and the reported
|
|
@@ -117,28 +107,70 @@ argument-only break-even excludes other request costs. Text framing is selected
|
|
|
117
107
|
by character length, not a runtime tokenizer; it need not reduce tokens for every
|
|
118
108
|
input or encoding.
|
|
119
109
|
|
|
110
|
+
## Shared batch input: a separate 0.6.0 measurement
|
|
111
|
+
|
|
112
|
+
Eight independent audit programs use the same list of 48 source paths. The before
|
|
113
|
+
arm repeats the literal `data` in every entry; the after arm supplies it once at
|
|
114
|
+
the top level. Both execute the same programs and return the same complete source
|
|
115
|
+
strings and typed results. The before request fits the existing admission cap;
|
|
116
|
+
this is not a comparison against a hypothetical request that could never run.
|
|
117
|
+
|
|
118
|
+
| Tokenizer | Repeated-input traffic | Shared-input traffic | Reduction | Arguments before / after | Unchanged result tokens |
|
|
119
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
120
|
+
| o200k_base | 16,309 | 5,499 | **66.28%** | 6,461 / 1,043 | 2,151 |
|
|
121
|
+
| cl100k_base | 14,649 | 5,197 | **64.52%** | 5,684 / 945 | 2,055 |
|
|
122
|
+
|
|
123
|
+
Each arm has one tool invocation followed by the final answer request:
|
|
124
|
+
|
|
125
|
+
~~~text
|
|
126
|
+
Total = 2*D + 2*A + R
|
|
127
|
+
~~~
|
|
128
|
+
|
|
129
|
+
Arguments are charged when generated and when replayed; the complete result is
|
|
130
|
+
charged on handoff. The new standing guidance adds 13 definition tokens per
|
|
131
|
+
request (618 to 631 / 613 to 626), and that cost is included in the after totals.
|
|
132
|
+
There is no source compression, result elision, hidden output or lost decision
|
|
133
|
+
boundary. Programs receive fresh data copies, not a shared mutable heap.
|
|
134
|
+
|
|
135
|
+
The gate requires at least 70% less argument traffic and 60% less replay-inclusive
|
|
136
|
+
traffic in each encoding, plus equality of the complete normalized output. This
|
|
137
|
+
workload deliberately exercises repeated input; it is not an average task-cost
|
|
138
|
+
estimate. The original 13-program/six-call benchmark remains separate and intact.
|
|
139
|
+
|
|
120
140
|
## Benchmark integrity
|
|
121
141
|
|
|
122
|
-
The [baseline fixture](
|
|
142
|
+
The [baseline fixture](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/tests/efficiency/token-baseline.json) contains the source
|
|
123
143
|
inputs, definition, workload hash, arguments and complete outputs. The
|
|
124
|
-
[runner](
|
|
144
|
+
[runner](https://github.com/AdityaVG13/pi-stack/blob/main/packages/pi-supernova/tests/efficiency/workflow.mjs) executes the registered tool with real
|
|
125
145
|
workers and filesystem operations. It checks that:
|
|
126
146
|
|
|
127
147
|
- The workload hash matches the frozen baseline, and the six-call argument hash
|
|
128
148
|
matches the prior batched execution.
|
|
129
|
-
- Every original argument
|
|
149
|
+
- Every original argument and expected failure matches; complete logical results
|
|
150
|
+
match the explicit current newline contract described below.
|
|
130
151
|
- Batched output contains every original result, with no unaccounted outer text.
|
|
131
152
|
- No result is truncated, and final repaired source and JSON contents match.
|
|
132
153
|
|
|
133
154
|
Only run IDs, elapsed times and temporary workspace prefixes in write receipts
|
|
134
155
|
are normalized. Batch framing lengths are adjusted to match that normalized text.
|
|
135
156
|
The workload, batch schedule, recorded comparison totals and acceptance thresholds
|
|
136
|
-
are fixed test inputs, not production execution rules. The baseline is not regenerated
|
|
157
|
+
are fixed test inputs, not production execution rules. The baseline is not regenerated
|
|
158
|
+
by the benchmark and is checked against its SHA-256 before execution.
|
|
159
|
+
|
|
160
|
+
Contract v2 preserves the terminating newline of one selected source line. The
|
|
161
|
+
runner derives that single expected-output correction from the frozen input, not
|
|
162
|
+
from candidate output. The historical fixture and its traffic counts stay
|
|
163
|
+
untouched; programs, arguments, failures and decision boundaries are unchanged.
|
|
164
|
+
The shared-input comparison separately requires equal complete result text in
|
|
165
|
+
both arms, after only run-metadata normalization.
|
|
166
|
+
|
|
167
|
+
The README and these docs ship in the npm tarball. Benchmarks and test fixtures
|
|
168
|
+
remain in the GitHub checkout, so their links above use GitHub URLs.
|
|
137
169
|
|
|
138
170
|
Recorded baseline SHA-256:
|
|
139
171
|
|
|
140
172
|
~~~text
|
|
141
|
-
|
|
173
|
+
96964f990f481ac05afaefdd02001bd15f61835a8381349a61e38c06209d7508
|
|
142
174
|
~~~
|
|
143
175
|
|
|
144
176
|
## Limitations
|
|
@@ -150,6 +182,8 @@ Recorded baseline SHA-256:
|
|
|
150
182
|
reasoning settings does not establish unchanged end-to-end task quality.
|
|
151
183
|
- Batching is appropriate only for already-chosen continuations. Actions requiring
|
|
152
184
|
a new model decision must remain separate calls.
|
|
185
|
+
- The report also has an experimental citation-elision arm. It is disabled by
|
|
186
|
+
default and is not the source of the non-compressive savings reported here.
|
|
153
187
|
- Existing read, output, log, image and execution limits still apply. The
|
|
154
188
|
benchmark does not obtain savings by lowering them or hiding truncation.
|
|
155
189
|
|
package/index.js
CHANGED
|
@@ -67,7 +67,10 @@ export function progressEmitter(onUpdate) {
|
|
|
67
67
|
const wait = PROGRESS_FRAME_MS - (performance.now() - lastSent);
|
|
68
68
|
|
|
69
69
|
if (wait <= 0) send();
|
|
70
|
-
else
|
|
70
|
+
else {
|
|
71
|
+
timer = setTimeout(send, wait);
|
|
72
|
+
timer.unref?.();
|
|
73
|
+
}
|
|
71
74
|
};
|
|
72
75
|
|
|
73
76
|
emit.flush = () => {
|
|
@@ -228,7 +231,7 @@ export function registerCodeMode(pi) {
|
|
|
228
231
|
execute: async function execute(_id, params, signal, onUpdate, ctx, budget) {
|
|
229
232
|
if (params?.programs !== undefined) return runProgramBatch(_id,params,signal,onUpdate,ctx,config,execute);
|
|
230
233
|
cancelWarmTimer();
|
|
231
|
-
const runCwd = ctx?.cwd
|
|
234
|
+
const runCwd = isString(ctx?.cwd) && ctx.cwd ? ctx.cwd : cwd;
|
|
232
235
|
const runController = new AbortController();
|
|
233
236
|
const abortRun = () => runController.abort(signal?.reason);
|
|
234
237
|
|
|
@@ -258,7 +261,7 @@ export function registerCodeMode(pi) {
|
|
|
258
261
|
cwd: runCwd,
|
|
259
262
|
data: params?.data,
|
|
260
263
|
nova: makeNovaApi(runBridge, abortRun),
|
|
261
|
-
config: { ...config, maxLogLines: Math.max(0,config.maxLogLines-(budget?.logLines ?? 0)), timeoutMs:
|
|
264
|
+
config: { ...config, maxLogLines: Math.max(0,config.maxLogLines-(budget?.logLines ?? 0)), timeoutMs: params?.timeoutMs === undefined ? config.timeoutMs : Number(params.timeoutMs) },
|
|
262
265
|
signal: runController.signal,
|
|
263
266
|
onTimeout: abortRun,
|
|
264
267
|
});
|
|
@@ -347,7 +350,7 @@ export function registerCodeMode(pi) {
|
|
|
347
350
|
pi.on("session_start", (_event, ctx) => {
|
|
348
351
|
stopped = false;
|
|
349
352
|
|
|
350
|
-
|
|
353
|
+
cwd = ctx && isString(ctx.cwd) && ctx.cwd ? ctx.cwd : process.cwd();
|
|
351
354
|
// A new session is a new model context: nothing has been seen yet.
|
|
352
355
|
bridge.bindCallContext(ctx);
|
|
353
356
|
bridge.ledger.reset();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-supernova",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "CodeMode for Pi and OMP: read, edit, write and bash, with transactional files, source views and shared-input program batches.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "AdityaVG13",
|
|
7
7
|
"license": "MIT",
|
package/src/bridge/catalog.js
CHANGED
|
@@ -4,22 +4,24 @@ import { isString, isObject } from "../shared/decode.js";
|
|
|
4
4
|
const NATIVE_TOOL_DEFINITIONS = [
|
|
5
5
|
{
|
|
6
6
|
name: "read",
|
|
7
|
-
description: "Read files, images or directories. JSON selectors project full documents within output budgets. Source questions locate and open source directly; resolve returns structured source/status without guessing.",
|
|
7
|
+
description: "Read files, images or directories (directory reads return entries). JSON selectors project full documents within output budgets. Source questions locate and open source directly; resolve returns structured source/status without guessing.",
|
|
8
8
|
parameters: { type: "object", properties: {
|
|
9
|
-
path: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }], description: "Workspace-relative file or directory, source question, or
|
|
9
|
+
path: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" }, maxItems: 64 }], description: "Workspace-relative file or directory, source question, or up to 64 paths" },
|
|
10
10
|
target: { anyOf: [{ type: "string" }, { type: "array" }], description: "File path/query or array of paths" },
|
|
11
11
|
offset: { type: "number", description: "One-based starting line" },
|
|
12
12
|
limit: { type: "number", description: "Maximum lines to return" },
|
|
13
|
-
about: { type: "string", description: "Question or symbol: expand file bodies, or locate
|
|
14
|
-
query: { type: "string", description: "Source question; optional path scopes the search directory" },
|
|
13
|
+
about: { type: "string", description: "Question or symbol (at most 16 keywords): expand file bodies, or locate/open source inside a directory" },
|
|
14
|
+
query: { type: "string", description: "Source question (at most 16 keywords); optional path scopes the search directory" },
|
|
15
|
+
outline: { type: "boolean", description: "Return a compact structural outline for the target file" },
|
|
16
|
+
evidence: { type: "boolean", description: "Rank source spans answering the target/path question" },
|
|
15
17
|
resolve: { type: "boolean", description: "Return structured source/status for a direct resolve-to-edit handoff" },
|
|
16
18
|
complete: { type: "boolean", description: "Fail unless the entire requested file fits without clipping" },
|
|
17
|
-
json: { anyOf: [{ type: "boolean" }, { type: "string" }, { type: "array", items: { type: "string" } }], description: "Parse
|
|
19
|
+
json: { anyOf: [{ type: "boolean" }, { type: "string" }, { type: "array", items: { type: "string" }, minItems: 1, maxItems: 64 }], description: "Parse complete JSON input up to 16 MiB, then select .field, .items[0:3], quoted keys, true, or 1-64 selectors. Oversized selections fail, never clip." },
|
|
18
20
|
} },
|
|
19
21
|
},
|
|
20
22
|
{
|
|
21
23
|
name: "write", description: "Write UTF-8 content to a workspace file.",
|
|
22
|
-
parameters: { type: "object", properties: { path: { type: "string" }, content: { type: "string" }, allowReadArtifacts: { type: "boolean", description: "Explicit opt-in for intentionally writing literal truncation-marker text" } }, required: ["path", "content"] },
|
|
24
|
+
parameters: { type: "object", properties: { path: { type: "string" }, content: { type: "string" }, append: { type: "boolean", description: "Append to an existing file instead of replacing it" }, allowReadArtifacts: { type: "boolean", description: "Explicit opt-in for intentionally writing literal truncation-marker text" } }, required: ["path", "content"] },
|
|
23
25
|
},
|
|
24
26
|
{
|
|
25
27
|
name: "edit", description: "Apply unique text replacements to a workspace file; returns the post-edit lines, a structural check, and references to changed declarations.",
|
|
@@ -53,7 +55,7 @@ const NATIVE_TOOL_DEFINITIONS = [
|
|
|
53
55
|
},
|
|
54
56
|
{
|
|
55
57
|
name: "bash", description: "Run a shell command inside the workspace and capture bounded output.",
|
|
56
|
-
parameters: { type: "object", properties: { command: { type: "string" }, cwd: { type: "string" }, timeoutMs: { type: "number" } }, required: ["command"] },
|
|
58
|
+
parameters: { type: "object", properties: { command: { type: "string" }, args: { type: "array", items: { type: "string" }, description: "Literal argv without shell interpretation (POSIX)" }, cwd: { type: "string" }, timeoutMs: { type: "number" } }, required: ["command"] },
|
|
57
59
|
},
|
|
58
60
|
{
|
|
59
61
|
name: "grep", description: "Search file contents. Smart-case regex; definition lines first (marked *); fuzzy fallback when nothing matches literally.",
|
|
@@ -178,7 +180,9 @@ export function searchCatalog(catalog, query, limit = 12) {
|
|
|
178
180
|
|
|
179
181
|
scored.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name));
|
|
180
182
|
|
|
181
|
-
|
|
183
|
+
const capped = Math.min(64, Math.max(1, Math.floor(Number(limit)) || 1));
|
|
184
|
+
|
|
185
|
+
return scored.slice(0, capped).map(({ score: _s, ...hit }) => hit);
|
|
182
186
|
}
|
|
183
187
|
|
|
184
188
|
/** Optimal string alignment distance: insert/delete/substitute/adjacent-transpose cost 1. */
|
|
@@ -202,7 +206,7 @@ function editDistance(a, b) {
|
|
|
202
206
|
|
|
203
207
|
/** Closest tool names for a mistyped name: substring hits first, then a length-scaled edit distance. */
|
|
204
208
|
function suggestNames(name, candidates, limit = 3) {
|
|
205
|
-
const needle = String(name || "").toLowerCase();
|
|
209
|
+
const needle = String(name || "").toLowerCase().slice(0, 128);
|
|
206
210
|
|
|
207
211
|
if (!needle) return [];
|
|
208
212
|
const maxDistance = Math.max(1, Math.floor(needle.length / 3));
|
|
@@ -228,7 +232,7 @@ function suggestNames(name, candidates, limit = 3) {
|
|
|
228
232
|
}
|
|
229
233
|
|
|
230
234
|
export function unknownToolMessage(name, candidates) {
|
|
231
|
-
const close = suggestNames(name, candidates);
|
|
235
|
+
const close = suggestNames(name, candidates.filter(isString));
|
|
232
236
|
const hint = close.length ? ` Did you mean ${close.map((c) => JSON.stringify(c)).join(", ")}?` : "";
|
|
233
237
|
|
|
234
238
|
return `unknown tool "${name}".${hint} Check the command name and configured tool exclusions.`;
|