pi-smart-compact 8.0.5 → 8.0.7
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/ARCHITECTURE.md +513 -0
- package/CHANGELOG.md +29 -0
- package/README.md +99 -68
- package/SECURITY.md +8 -3
- package/dist/app/mode-policy.d.ts +0 -1
- package/dist/app/mode-policy.d.ts.map +1 -1
- package/dist/app/preflight.d.ts +16 -2
- package/dist/app/preflight.d.ts.map +1 -1
- package/dist/app/run-smart-compact.d.ts.map +1 -1
- package/dist/app/steps/extract.d.ts.map +1 -1
- package/dist/app/steps/state.d.ts.map +1 -1
- package/dist/app/steps/synthesize.d.ts.map +1 -1
- package/dist/app/steps/verify.d.ts.map +1 -1
- package/dist/app/steps/window.d.ts +3 -1
- package/dist/app/steps/window.d.ts.map +1 -1
- package/dist/constants.d.ts +18 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/domain/telemetry.d.ts +3 -0
- package/dist/domain/telemetry.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +969 -652
- package/dist/infra/context-graph.d.ts.map +1 -1
- package/dist/infra/fs.d.ts +1 -1
- package/dist/infra/fs.d.ts.map +1 -1
- package/dist/infra/git.d.ts.map +1 -1
- package/dist/infra/session-identity.d.ts +4 -0
- package/dist/infra/session-identity.d.ts.map +1 -1
- package/dist/phases/verify.d.ts.map +1 -1
- package/dist/provider-eval.js +113 -22
- package/dist/provider-scenario-eval.js +151 -108
- package/dist/telemetry-report.js +138 -41
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/dashboard-insights.d.ts.map +1 -1
- package/dist/ui/overlays.d.ts +1 -1
- package/dist/ui/overlays.d.ts.map +1 -1
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/extraction.d.ts +5 -0
- package/dist/utils/extraction.d.ts.map +1 -1
- package/dist/utils/fingerprint.d.ts +1 -1
- package/dist/utils/fingerprint.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/utils/pruning.d.ts.map +1 -1
- package/dist/utils/state.d.ts +4 -3
- package/dist/utils/state.d.ts.map +1 -1
- package/dist/utils/tokens.d.ts.map +1 -1
- package/docs/MIGRATING_TO_V8.md +32 -14
- package/docs/RELEASE.md +13 -10
- package/package.json +2 -1
- package/dist/app/explore-wrap.d.ts +0 -8
- package/dist/app/explore-wrap.d.ts.map +0 -1
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
System-level design of `pi-smart-compact`. This is the maintainer-facing
|
|
4
|
+
companion to the user-facing [`README.md`](./README.md).
|
|
5
|
+
|
|
6
|
+
> **Job:** not to produce a generic recap, but to preserve the agent's working
|
|
7
|
+
> state so the next turn can continue with minimal loss.
|
|
8
|
+
|
|
9
|
+
## Design ideas
|
|
10
|
+
|
|
11
|
+
The design combines three ideas:
|
|
12
|
+
|
|
13
|
+
- **Agentic compaction** — let the system inspect the session, not just summarize it.
|
|
14
|
+
- **Kamradt-style chunking** — segment large conversations into coherent units before synthesis.
|
|
15
|
+
- **EESV** — **Extract → Explore → Synthesize → Verify**: facts first, synthesis second, verification last.
|
|
16
|
+
|
|
17
|
+
## Integration surfaces
|
|
18
|
+
|
|
19
|
+
Registered in [`src/index.ts`](./src/index.ts). See the README for usage; this
|
|
20
|
+
section is about lifecycle.
|
|
21
|
+
|
|
22
|
+
| Surface | Lifecycle |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `/smart-compact` | Manual command. Explainable target-first preflight or direct args. Bypasses the adaptive pressure gate, not yield/verification gates. |
|
|
25
|
+
| `session_before_compact` | Auto hook. Returns/stages a pending summary or runs under pressure; durable commit waits for matching `session_compact`. |
|
|
26
|
+
| `smart_compact` tool | Agent-callable. Prepares a pending summary; never compacts mid-turn. |
|
|
27
|
+
| `smart_recall` tool | Searches only the current project's bounded context graph; same session/branch ranks first. |
|
|
28
|
+
| `smart_save_memory` tool | Persists one explicit user-confirmed project fact after secret/PII scrubbing. |
|
|
29
|
+
|
|
30
|
+
A short-lived pending compaction is staged in the [`PendingSlot`](#pending-compaction-slot)
|
|
31
|
+
and handed to Pi when compaction is applied.
|
|
32
|
+
|
|
33
|
+
### Host dependency boundary
|
|
34
|
+
|
|
35
|
+
Pi core modules and `typebox` are wildcard peers supplied by the running host;
|
|
36
|
+
they are neither bundled nor duplicated as versioned development dependencies.
|
|
37
|
+
The lockfile pins a reproducible local baseline, and `bun run compat:pi [version]`
|
|
38
|
+
validates another Pi release in an isolated temporary workspace.
|
|
39
|
+
|
|
40
|
+
## Pipeline at a glance
|
|
41
|
+
|
|
42
|
+
```mermaid
|
|
43
|
+
flowchart LR
|
|
44
|
+
A[Active Pi context] --> B[Keep recent tail]
|
|
45
|
+
B --> C[Extract deterministic facts]
|
|
46
|
+
C --> D{Complex enough?}
|
|
47
|
+
D -- No --> E[Single-pass synthesis]
|
|
48
|
+
D -- Yes --> F[Explore + segment]
|
|
49
|
+
F --> G[Chunked synthesis]
|
|
50
|
+
E --> H[Verify + repair]
|
|
51
|
+
G --> H
|
|
52
|
+
H --> I[Open loops + delta + state]
|
|
53
|
+
I --> Y{Target + ≥10% yield?}
|
|
54
|
+
Y -- No --> X[Reject; conversation unchanged]
|
|
55
|
+
Y -- Yes --> J[Pending compaction returned to Pi]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The orchestrator ([`src/app/run-smart-compact.ts`](./src/app/run-smart-compact.ts))
|
|
59
|
+
threads a typed context through ten stages:
|
|
60
|
+
|
|
61
|
+
| # | Stage | Module | Transition |
|
|
62
|
+
| ---: | --- | --- | --- |
|
|
63
|
+
| 1 | prepare | `app/steps/prepare.ts` | config + auth + provider caps |
|
|
64
|
+
| 2 | window | `app/steps/window.ts` | pick the prefix to compact |
|
|
65
|
+
| 3 | recover | `app/steps/recover.ts` | restore log-truncated messages |
|
|
66
|
+
| 4 | tier | `app/steps/tier.ts` | choose none / light / full |
|
|
67
|
+
| 5 | extract | `app/steps/extract.ts` | prune + deterministic extraction + cache |
|
|
68
|
+
| 6 | synthesize | `app/steps/synthesize.ts` | single-pass or EESV |
|
|
69
|
+
| 7 | verify | `app/steps/verify.ts` | structural verify + repair |
|
|
70
|
+
| 8 | state | `app/steps/state.ts` + `domain/yield-gate.ts` | state/open loops/delta + final yield proof |
|
|
71
|
+
| 9 | persist | `app/steps/persist.ts` | stage pending, apply compaction |
|
|
72
|
+
| 10 | metrics | `app/steps/metrics.ts` | success / failure record |
|
|
73
|
+
|
|
74
|
+
## The typed stage machine
|
|
75
|
+
|
|
76
|
+
[`src/app/run-context.ts`](./src/app/run-context.ts) models the pipeline context
|
|
77
|
+
as a **state machine of branded intersection types**. Each step accepts the
|
|
78
|
+
previous stage type and returns the next, so reordering or skipping a step is a
|
|
79
|
+
**compile-time error**, not a runtime crash:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
RcBase
|
|
83
|
+
→ PreparedRc (after prepare)
|
|
84
|
+
→ WindowedRc (after window)
|
|
85
|
+
→ RecoveredRc (after recover)
|
|
86
|
+
→ TieredRc (after tier)
|
|
87
|
+
→ ExtractedRc (after extract)
|
|
88
|
+
→ SynthesizedRc (after synthesize)
|
|
89
|
+
→ VerifiedRc (after verify)
|
|
90
|
+
→ StatedRc (after state)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Each stage adds a `_prepared` / `_windowed` / … discriminator field that is
|
|
94
|
+
**never read at runtime** — it exists only to carry the type-level proof.
|
|
95
|
+
Mutation is preserved: a step mutates its input object and casts it to the
|
|
96
|
+
next stage (no per-step copy of ~30 fields). The final alias
|
|
97
|
+
`RunContext = StatedRc` keeps post-`buildState` consumers readable.
|
|
98
|
+
|
|
99
|
+
This is what lets `applyCompaction` read `rc.details` with zero `!` non-null
|
|
100
|
+
assertions: the type system proves `buildState` has run.
|
|
101
|
+
|
|
102
|
+
## Core execution model
|
|
103
|
+
|
|
104
|
+
### Entry and context gate
|
|
105
|
+
|
|
106
|
+
`src/index.ts` resolves models, parses command arguments, and routes work into
|
|
107
|
+
`runSmartCompact()`. Before any expensive work, the system checks context size
|
|
108
|
+
against the threshold in `src/constants.ts`. Auto / tool runs are skipped while
|
|
109
|
+
context is small; manual `/smart-compact` uses an absolute adaptive safety tail
|
|
110
|
+
rather than a percentage of large model windows. Its decision-card preflight
|
|
111
|
+
is built from the same config snapshot, calibrated estimator, adaptive profile,
|
|
112
|
+
active branch, and pure window planner as execution. It compares exactly Fast,
|
|
113
|
+
Balanced, and Thorough; `M` changes the summary route and replans all three,
|
|
114
|
+
while `D` reveals technical estimator/boundary details. A plan must meet the
|
|
115
|
+
tail target and at least 10% projected net savings before any model call. A
|
|
116
|
+
pending summary for the same session is reused instead of invoking the pipeline
|
|
117
|
+
again. `auto` is not a fourth policy: it selects one of the three from context
|
|
118
|
+
pressure and deterministic extraction risk.
|
|
119
|
+
|
|
120
|
+
Model routes are stage-specific but never inferred from mode. With no explicit
|
|
121
|
+
configuration, Explore, Synthesize, and Verify all use the selected Pi model.
|
|
122
|
+
`segmentationModel`, `summaryModel`, and `verificationModel` can independently
|
|
123
|
+
override those routes. `prepareRun()` resolves credentials once per distinct
|
|
124
|
+
provider/model route; call metrics preserve the actual route.
|
|
125
|
+
|
|
126
|
+
### Keep window and preprocessing
|
|
127
|
+
|
|
128
|
+
`app/steps/window.ts` starts from Pi's compaction-aware
|
|
129
|
+
`buildContextEntries()` view, never the append-only session history, and builds
|
|
130
|
+
a content-free `CompactionWindowPlan` from the selected mode budget:
|
|
131
|
+
|
|
132
|
+
- **hard `toolCall` / `toolResult` guard** — never orphan a result from its call
|
|
133
|
+
- **soft recent-user/checkpoint/topical preferences** — retain raw only when the resulting suffix still fits the planned budget
|
|
134
|
+
- **yield contract** — projected replacement must meet its target and save at least 10% after reserving the summary budget
|
|
135
|
+
|
|
136
|
+
The same pure planner powers manual preflight and execution. A soft boundary is
|
|
137
|
+
recorded as relaxed rather than silently overriding the target. Long turns may
|
|
138
|
+
be summarized through their older prefix; if the nominal cut lands inside a
|
|
139
|
+
tool exchange, the planner either retains the complete pair within budget or
|
|
140
|
+
advances past it so the complete exchange is summarized. If no safe hard
|
|
141
|
+
boundary can meet the target, automatic/tool runs normally return control to
|
|
142
|
+
Pi's native compactor before any LLM call. An already-overflowed context is
|
|
143
|
+
the safety exception: measured usage is mapped across active messages and EESV
|
|
144
|
+
keeps chunked recovery instead of sending an oversized one-shot prompt to
|
|
145
|
+
native summarization. Manual runs use the profile's absolute adaptive tail, so
|
|
146
|
+
model-window size cannot turn an explicit command into a full-context no-op.
|
|
147
|
+
|
|
148
|
+
Before summarization the pipeline serializes the full selected conversation,
|
|
149
|
+
scrubs it, and writes that pre-prune backup; it then prunes redundant messages,
|
|
150
|
+
loads the previous verified summary plus bounded continuity state, checks the
|
|
151
|
+
incremental extraction cache, and loads the project fingerprint.
|
|
152
|
+
|
|
153
|
+
### Extract
|
|
154
|
+
|
|
155
|
+
Primary: [`src/utils/extraction.ts`](./src/utils/extraction.ts). **Zero LLM calls.**
|
|
156
|
+
|
|
157
|
+
Deterministically pulls: modified / read / deleted files, tool and bash-like
|
|
158
|
+
errors, retry / resolution signals, explicit & implicit decisions, constraints
|
|
159
|
+
and preferences, heuristic topic segments, timeline events, the main goal, and
|
|
160
|
+
open loops. **This is the ground truth** that synthesis and verification trust.
|
|
161
|
+
|
|
162
|
+
### Explore
|
|
163
|
+
|
|
164
|
+
Primary: [`src/phases/explore.ts`](./src/phases/explore.ts). Optional — runs only
|
|
165
|
+
in `thorough` mode or when `auto` selects that policy from deterministic risk. The model inspects
|
|
166
|
+
the conversation through a small toolset: message ranges, conversation search,
|
|
167
|
+
recent user messages, local context around an index, file-change lookups, and
|
|
168
|
+
error chains. Tool support is runtime-probed once and cached per run; if a
|
|
169
|
+
provider has no function calling, the system falls back to a direct structured
|
|
170
|
+
analysis path. The growing tool conversation is capped at three rounds, each
|
|
171
|
+
response is capped where the provider supports output limits, and the shared
|
|
172
|
+
prefix uses short-lived prompt caching.
|
|
173
|
+
|
|
174
|
+
### Synthesize
|
|
175
|
+
|
|
176
|
+
Primary: [`src/phases/synthesize.ts`](./src/phases/synthesize.ts). Three paths:
|
|
177
|
+
|
|
178
|
+
- **Deterministic zero-call** — high-confidence Fast extractions.
|
|
179
|
+
- **Single-pass** — when the compacted conversation fits under the configured threshold.
|
|
180
|
+
- **Hierarchical** — for larger sessions: merge available boundaries → split oversized semantic chunks → batch by token budget → summarize batches → assemble.
|
|
181
|
+
|
|
182
|
+
Behaviors: session-aware prompting, decision propagation across later batches,
|
|
183
|
+
mode-specific single-pass thresholds and output limits, provider-aware
|
|
184
|
+
concurrency (wave scheduling), aggregate prompt-token reservation, and a
|
|
185
|
+
deterministic fallback assembly when any budget or LLM call fails.
|
|
186
|
+
|
|
187
|
+
### Verify
|
|
188
|
+
|
|
189
|
+
Primary: [`src/phases/verify.ts`](./src/phases/verify.ts). Scores the summary
|
|
190
|
+
against the deterministic extraction. It checks for missing modified files,
|
|
191
|
+
missing unresolved errors, missing high-confidence constraints, weak goal
|
|
192
|
+
coverage, missing structure sections, suspicious fabricated file references,
|
|
193
|
+
done/unresolved inconsistencies, missing explicit decisions, and missing
|
|
194
|
+
open-loop coverage.
|
|
195
|
+
|
|
196
|
+
**Repair order is intentional:** (1) deterministic patch first (free,
|
|
197
|
+
idempotent) → (2) one LLM patch only in `thorough` mode if still insufficient
|
|
198
|
+
→ (3) replace lower-scoring output with the deterministic quality floor → (4)
|
|
199
|
+
reject unless final verification has no gaps and meets the verified threshold.
|
|
200
|
+
Final verification runs again after continuity injection. The final scalar is
|
|
201
|
+
reported as repaired **verification coverage**, alongside the pre-repair source
|
|
202
|
+
score and fallback provenance; it is not labeled as raw synthesis quality.
|
|
203
|
+
Polarity checks are symmetric: adding negation to a positive fact is rejected
|
|
204
|
+
just as removing negation from a prohibition is. Unresolved-error source
|
|
205
|
+
snippets and fallback-rendered evidence share `summaryEvidenceLine()`, so
|
|
206
|
+
Markdown prefixes and multiline wrapping cannot create false missing-error gaps.
|
|
207
|
+
|
|
208
|
+
## EESV hardening and control surfaces
|
|
209
|
+
|
|
210
|
+
- **Canonical summary IR** accepts recognized H1/H2/H3 headings, preserves Progress subsections, and merges duplicate canonical kinds before state mutation.
|
|
211
|
+
- **Typed verification gaps** drive mandatory deterministic repair; collision-aware path needles prevent basename cross-satisfaction. Provenance is persisted and shown before optional approval.
|
|
212
|
+
- **Fine tool semantics** separate read/search/list/mutate/delete/execute operations. Pruning deduplicates only identical idempotent access signatures.
|
|
213
|
+
- **Unified token planning** uses a run-bound estimator with bounded process-shared provider/model calibration, counts structured tool-call arguments, preserves an adaptive recent tail, targets mode-specific post-compaction headroom, reserves 25% of the synthesis allowance for deterministic post-summary state sections, and reserves/reconciles every request against the mode's aggregate prompt/output-token caps.
|
|
214
|
+
- **Security boundaries** scrub high-confidence secrets before provider calls and durable cache/backup/state writes; PII scrubbing is opt-in.
|
|
215
|
+
- **Policy controls** include focus weighting, exact call/latency budgets, fail-closed manual approval, online damage monitoring, and persisted open-loop overrides.
|
|
216
|
+
- **Release gate** (`bun run gate`) covers adversarial parser, verification, tool, cache, budget, scrub and damage fixtures.
|
|
217
|
+
|
|
218
|
+
## State, caching & persistence
|
|
219
|
+
|
|
220
|
+
Post-verification, `app/steps/state.ts` + `src/utils/state.ts` enrich the
|
|
221
|
+
summary, then `domain/yield-gate.ts` measures the final replacement. Planning
|
|
222
|
+
has already reserved the bounded post-synthesis enrichment band by reducing the
|
|
223
|
+
retained tail; missing the original target or 10% net-saving floor still throws
|
|
224
|
+
before a `StatedRc` can reach staging/apply. `session_before_compact` only stages a passing candidate; after
|
|
225
|
+
the host emits the matching `session_compact`, `app/steps/persist.ts` commits
|
|
226
|
+
reusable state and success telemetry. Aborted/unconfirmed candidates write
|
|
227
|
+
neither, and the UI reports `Applied` only after that correlated commit.
|
|
228
|
+
`ui/error-format.ts` converts verification/yield failures to one bounded,
|
|
229
|
+
content-free diagnostic and collapses unknown multiline errors; full stacks are
|
|
230
|
+
suppressed by default and emitted only under explicit `DEBUG=smart-compact`.
|
|
231
|
+
Manual execution uses a two-line widget: a colored EESV phase chain plus a
|
|
232
|
+
phase-specific action brief. Before Apply it explicitly says the conversation
|
|
233
|
+
is unchanged. Routine info toasts are hidden unless `verbose`; handled provider,
|
|
234
|
+
watchdog, Explore, batch, and assembly failures switch to deterministic fallback
|
|
235
|
+
without printing raw messages. Auto-trigger rejection logs are also debug-only,
|
|
236
|
+
leaving one content-free safe-fallback notice in the UI.
|
|
237
|
+
|
|
238
|
+
| Concern | Where | Notes |
|
|
239
|
+
| --- | --- | --- |
|
|
240
|
+
| Open-loop injection | `utils/state.ts` | inserted before Next Steps via the canonical parser |
|
|
241
|
+
| `CompactionState` | `utils/state.ts` | conservatively merged and bounded across goal wording changes; newer file evidence resolves delete/present contradictions |
|
|
242
|
+
| Continuity Ledger | `utils/state.ts` | prior facts carry forward until positive resolution evidence or an explicit override; goal shifts become non-destructive breadcrumbs |
|
|
243
|
+
| Cross-compaction delta | `utils/state.ts` | "Changes Since Last Compaction" section |
|
|
244
|
+
| Incremental extraction cache | `utils/cache.ts` + `utils/id-fingerprint.ts` | bounded SHA-256 prefix fingerprint + tail; safe only when the pruned prefix still matches |
|
|
245
|
+
| Synthesis cache | `infra/synthesis-cache.ts` | behavior key includes normalized focus, route, mode, budgets, and reasoning |
|
|
246
|
+
| Session-log recovery | `utils/session-log.ts` | streaming JSONL parse; bypasses pi-toolkit truncation by entry-id mapping |
|
|
247
|
+
| Project fingerprint | `utils/fingerprint.ts` | locked read/merge/write; language/framework/key dirs stay bounded across sessions |
|
|
248
|
+
| Damage detection | `utils/damage.ts` | best-effort post-compaction regression signals |
|
|
249
|
+
| Context graph | `infra/context-graph.ts` | SQLite FTS5 facts + file edges; 2,000 non-structural nodes per project |
|
|
250
|
+
|
|
251
|
+
Apply-confirmed verified state is queued and duplicate updates coalesce only
|
|
252
|
+
for the exact project/session/branch head, then indexed on the next event-loop
|
|
253
|
+
turn so SQLite work is not part of the native
|
|
254
|
+
compaction hook's latency. `infra/context-graph.ts` adapts the same synchronous
|
|
255
|
+
query/transaction contract to `bun:sqlite` in Bun tests and `node:sqlite`
|
|
256
|
+
`DatabaseSync` in Pi's Node runtime; the packed release audit exercises both.
|
|
257
|
+
The referenced queue timer survives extension
|
|
258
|
+
shutdown/reload in the process; graph data is derived and a later cumulative
|
|
259
|
+
state safely supersedes a missed update after a hard process kill. Fact occurrences are branch-head scoped; state, recall, and resolution use the
|
|
260
|
+
complete host-visible branch ancestry before equivalent facts are deduplicated.
|
|
261
|
+
Schema v1 preserves user-confirmed manual memory but resets older derived
|
|
262
|
+
compaction nodes once so sibling branches cannot inherit a last-writer identity.
|
|
263
|
+
Recall starts from FTS5 lexical matches, expands one hop
|
|
264
|
+
through file-reference edges, then applies session, branch, fact-kind,
|
|
265
|
+
confidence, recency, and explicit-memory weights. Exact equivalent facts are
|
|
266
|
+
deduplicated before bounded output. Resolved/superseded state is removed from
|
|
267
|
+
the active FTS index; another project's rows are never eligible.
|
|
268
|
+
|
|
269
|
+
**Important retention limits:** pending in-memory compaction 5 min · exploration
|
|
270
|
+
tool-support cache 1 h / 128 routes · token calibration 128 routes · extraction
|
|
271
|
+
cache 1 h · compaction state 7 d · context graph 2,000 non-structural fact nodes
|
|
272
|
+
and 500 active manual memories per project · remediation hints 7 d · metrics and damage
|
|
273
|
+
JSONL logs 5 MiB each.
|
|
274
|
+
|
|
275
|
+
## Concurrency & safety model
|
|
276
|
+
|
|
277
|
+
The extension is built to run safely alongside other Pi sessions and other
|
|
278
|
+
extensions.
|
|
279
|
+
|
|
280
|
+
### Pending-compaction slot
|
|
281
|
+
|
|
282
|
+
[`src/app/pending-slot.ts`](./src/app/pending-slot.ts) is an encapsulated,
|
|
283
|
+
host-agnostic state cell (one producer, one consumer, single-threaded event
|
|
284
|
+
loop). `consume()` returns a discriminated result:
|
|
285
|
+
|
|
286
|
+
| `ConsumeResult.kind` | Meaning |
|
|
287
|
+
| --- | --- |
|
|
288
|
+
| `ok` | fresh payload for this session |
|
|
289
|
+
| `empty` | nothing staged |
|
|
290
|
+
| `expired` | older than the 5-minute TTL |
|
|
291
|
+
| `mismatch` | staged by a **different** session (cross-session leak guard) |
|
|
292
|
+
|
|
293
|
+
Session identity comes from [`infra/session-identity.ts`](./src/infra/session-identity.ts):
|
|
294
|
+
a real id when the host exposes one, otherwise a per-call unforgeable
|
|
295
|
+
`unresolved:<uuid>` — two unresolved sessions can never collide.
|
|
296
|
+
|
|
297
|
+
### Cancellation deadlines
|
|
298
|
+
|
|
299
|
+
Some providers ignore `AbortSignal`. The auto-trigger therefore uses a shared
|
|
300
|
+
[`ExternalCancellation`](./src/app/run-smart-compact.ts) handle as a second line
|
|
301
|
+
of defense: an outer `setTimeout` fires `abort()` and sets `timedOut`, and every
|
|
302
|
+
side-effect gate in the orchestrator checks that flag before writing state or
|
|
303
|
+
applying compaction. The caller waits for safe pipeline unwind; no unsafe
|
|
304
|
+
`Promise.race` hard return can leave work running past the hook lifecycle.
|
|
305
|
+
|
|
306
|
+
### Filesystem & concurrency
|
|
307
|
+
|
|
308
|
+
JSON/text cache writes use [`src/infra/fs.ts`](./src/infra/fs.ts): private
|
|
309
|
+
artifact directories are 0700 and files are 0600; atomic temp-file + rename
|
|
310
|
+
prevents half-truncated readers but intentionally does not claim fsync/power-loss
|
|
311
|
+
durability. Append/trim operations use a `mkdir`-based cross-process lock and
|
|
312
|
+
fail closed if ownership cannot be acquired, so sessions cannot interleave
|
|
313
|
+
bytes. SQLite supplies its own WAL durability. Native continuity handoffs are
|
|
314
|
+
one-shot, bounded, and keyed by project + session + branch head.
|
|
315
|
+
|
|
316
|
+
## Provider awareness
|
|
317
|
+
|
|
318
|
+
[`src/utils/tokens.ts`](./src/utils/tokens.ts) keeps a per-provider capability
|
|
319
|
+
table (Anthropic, OpenAI, Google, DeepSeek, MiniMax, Xiaomi, Mistral, xAI, …)
|
|
320
|
+
with unknowns falling back to a safe default + fuzzy alias matching. Each entry
|
|
321
|
+
drives pipeline behavior:
|
|
322
|
+
|
|
323
|
+
| Capability | Drives |
|
|
324
|
+
| --- | --- |
|
|
325
|
+
| `maxOutputTokens` | caps synthesis / patch budgets |
|
|
326
|
+
| `supportsTools` (`true \| false \| "probe"`) | exploration tool-call probing |
|
|
327
|
+
| `concurrencyLimit` | batch synthesis wave scheduling |
|
|
328
|
+
| `cacheStrategy` | prompt-cache retention per call |
|
|
329
|
+
| `timeoutMultiplier` | auto-trigger hard-timeout headroom |
|
|
330
|
+
| `singlePassTokenMultiplier` | single-pass vs chunked threshold |
|
|
331
|
+
| `tokenRatioEstimate` | token estimation; refined by per-(provider,model) **EMA calibration** |
|
|
332
|
+
|
|
333
|
+
The Codex limiter is hybrid. Custom Codex endpoints receive
|
|
334
|
+
`max_output_tokens` through Pi AI's payload hook. The ChatGPT subscription
|
|
335
|
+
endpoint rejects every wire output-cap field, so it uses a derived 15–90s
|
|
336
|
+
per-call stream watchdog plus a visible-output ceiling; aborts route to the
|
|
337
|
+
phase's deterministic fallback.
|
|
338
|
+
|
|
339
|
+
### Provider evaluation and routing evidence
|
|
340
|
+
|
|
341
|
+
[`src/domain/provider-evaluation.ts`](./src/domain/provider-evaluation.ts)
|
|
342
|
+
collapses call telemetry into Explore/Synthesize/Verify routes and compares
|
|
343
|
+
provider/models across a deterministic context-pressure × tool-density matrix.
|
|
344
|
+
Only an explicitly attributed pre-repair synthesis score contributes route
|
|
345
|
+
quality; a run's final verifier score is never copied into Explore/Verify.
|
|
346
|
+
Legacy or operational-only routes still contribute latency and reliability.
|
|
347
|
+
Recommendations require minimum samples, ≥80% call reliability, and ≥50%
|
|
348
|
+
stage-local quality coverage, shrink toward neutral under low confidence, and
|
|
349
|
+
are advisory only.
|
|
350
|
+
They never mutate config or replace the selected model. The opt-in live harness
|
|
351
|
+
runs three identical bounded continuity scenarios across explicitly named
|
|
352
|
+
models.
|
|
353
|
+
|
|
354
|
+
### Privacy-safe telemetry and canary decisions
|
|
355
|
+
|
|
356
|
+
[`src/domain/telemetry.ts`](./src/domain/telemetry.ts) maps raw exceptions to a
|
|
357
|
+
content-free failure taxonomy, aggregates schema-v2 run quality without IDs or
|
|
358
|
+
conversation data, and compares an explicitly tagged `canary` cohort against
|
|
359
|
+
`stable` history. Reports expose total/applied counts; only non-dry,
|
|
360
|
+
host-confirmed applied outcomes count toward promotion. A deterministic green
|
|
361
|
+
release check is not promotion evidence. The gate returns Hold, Rollback, or
|
|
362
|
+
Promote from applied sample/quality coverage plus failure, verifier quality, p95
|
|
363
|
+
latency, token, heuristic-fallback, and post-compaction-damage thresholds.
|
|
364
|
+
Damage observations join their originating compaction by local run id, dedupe
|
|
365
|
+
per run, and require ≥70% stable/canary coverage before promotion. It is
|
|
366
|
+
advisory: rollout selection, configuration changes, and rollback remain external.
|
|
367
|
+
|
|
368
|
+
Dashboard trust calculations live in
|
|
369
|
+
[`src/ui/dashboard-insights.ts`](./src/ui/dashboard-insights.ts). Data
|
|
370
|
+
Confidence is an auditable 100-point score over sample size, schema-v2
|
|
371
|
+
coverage, verifier-quality coverage, required-field completeness, and
|
|
372
|
+
freshness; ≥85 is the high-confidence target. TUI and HTML surfaces share the
|
|
373
|
+
same quality-repair, stage/provider/model, failure-taxonomy, and
|
|
374
|
+
stable-vs-canary aggregates. Missing/legacy evidence lowers the score and
|
|
375
|
+
produces remediation guidance instead of being imputed.
|
|
376
|
+
|
|
377
|
+
## Dependency injection
|
|
378
|
+
|
|
379
|
+
[`src/infra/services.ts`](./src/infra/services.ts) is a per-`runSmartCompact`
|
|
380
|
+
service bag. Metrics, budgets, scrubbers, and prompt namespaces are isolated per
|
|
381
|
+
run. Production shares only bounded provider/model capability and calibration
|
|
382
|
+
knowledge, which contains no conversation/session data; tests use isolated
|
|
383
|
+
stores by default:
|
|
384
|
+
|
|
385
|
+
| Service | Role |
|
|
386
|
+
| --- | --- |
|
|
387
|
+
| `clock` | injectable wall clock (deterministic tests) |
|
|
388
|
+
| `llm` | LLM client seam (production does not replay failed requests) |
|
|
389
|
+
| `toolSupport` | process-shared in production; explicit unsupported capability, 1 h TTL / 128 routes |
|
|
390
|
+
| `metrics` | bounded metrics sink |
|
|
391
|
+
| `extractionCacheStats` | hit / miss counters |
|
|
392
|
+
| `tokenCalibration` | process-shared bounded per-(provider,model) EMA factors |
|
|
393
|
+
| `compactSessionId` | per-run prompt-cache namespace |
|
|
394
|
+
|
|
395
|
+
## Layer responsibilities
|
|
396
|
+
|
|
397
|
+
The code is organized into six layers, each with a single responsibility.
|
|
398
|
+
|
|
399
|
+
### Entry layer
|
|
400
|
+
|
|
401
|
+
| File | Responsibility |
|
|
402
|
+
| --- | --- |
|
|
403
|
+
| `src/index.ts` | extension registration, command parsing, auto-trigger hook |
|
|
404
|
+
| `src/constants.ts` | version, thresholds, prompts, config keys |
|
|
405
|
+
| `src/types.ts` | shared types and discriminated unions |
|
|
406
|
+
| `domain/provider-evaluation.ts` | advisory provider scenario matrix and route telemetry aggregation |
|
|
407
|
+
| `domain/telemetry.ts` | privacy-safe aggregates, failure taxonomy, and canary rollback gates |
|
|
408
|
+
|
|
409
|
+
### Orchestration layer (`src/app/`)
|
|
410
|
+
|
|
411
|
+
| File | Responsibility |
|
|
412
|
+
| --- | --- |
|
|
413
|
+
| `app/run-smart-compact.ts` | top-level pipeline orchestrator |
|
|
414
|
+
| `app/run-context.ts` | typed stage chain (`RcBase → … → StatedRc`) |
|
|
415
|
+
| `app/mode-policy.ts` | Auto selector and finite Fast/Balanced/Thorough policies; legacy Aggressive maps to Fast |
|
|
416
|
+
| `app/pending-slot.ts` | encapsulated pending-compaction state cell |
|
|
417
|
+
| `app/steps/prepare.ts` | resolve config, auth, provider caps |
|
|
418
|
+
| `app/steps/window.ts` | pick the prefix of messages to compact |
|
|
419
|
+
| `app/steps/recover.ts` | recover full content for log-truncated messages |
|
|
420
|
+
| `app/steps/tier.ts` | choose compaction tier (none / light / full) |
|
|
421
|
+
| `app/steps/extract.ts` | pruning + deterministic extraction with incremental cache |
|
|
422
|
+
| `app/steps/synthesize.ts` | single-pass / EESV synthesis |
|
|
423
|
+
| `app/steps/verify.ts` | structural verification + repair |
|
|
424
|
+
| `app/steps/state.ts` | enrich summary with state machine + open loops |
|
|
425
|
+
| `app/steps/persist.ts` | apply compaction, save fingerprint, persist state |
|
|
426
|
+
| `app/steps/metrics.ts` | record success / failure metrics |
|
|
427
|
+
|
|
428
|
+
### Domain layer (`src/domain/`)
|
|
429
|
+
|
|
430
|
+
Pure semantics — no I/O, no async, no globals.
|
|
431
|
+
|
|
432
|
+
| File | Responsibility |
|
|
433
|
+
| --- | --- |
|
|
434
|
+
| `domain/summary-schema.ts` | canonical section kinds + heading classification |
|
|
435
|
+
| `domain/summary-parse.ts` | parse/render canonical H1/H2/H3 sections; merge duplicates; placement (`before`/`after`) |
|
|
436
|
+
| `domain/tool-semantics.ts` | fine tool operation taxonomy with broad compatibility wrapper |
|
|
437
|
+
| `domain/scrub.ts` | pure secret/PII redaction primitives and run-scoped scrubber |
|
|
438
|
+
|
|
439
|
+
### Algorithm layer (`src/phases/`)
|
|
440
|
+
|
|
441
|
+
| File | Responsibility |
|
|
442
|
+
| --- | --- |
|
|
443
|
+
| `phases/explore.ts` | targeted exploration with tool-call probing |
|
|
444
|
+
| `phases/synthesize.ts` | chunking, single-pass compact, batch summarization, assembly |
|
|
445
|
+
| `phases/verify.ts` | typed gap detection, collision-safe coverage, deterministic/LLM repair |
|
|
446
|
+
|
|
447
|
+
### Infrastructure layer (`src/infra/`)
|
|
448
|
+
|
|
449
|
+
All external-world interaction.
|
|
450
|
+
|
|
451
|
+
| File | Responsibility |
|
|
452
|
+
| --- | --- |
|
|
453
|
+
| `infra/fs.ts` | atomic writes, advisory locks |
|
|
454
|
+
| `infra/paths.ts` | canonical cache/session/backup paths |
|
|
455
|
+
| `infra/git.ts` | cached git-root discovery |
|
|
456
|
+
| `infra/clock.ts` | injectable wall clock |
|
|
457
|
+
| `infra/llm-client.ts` | LLM seam, custom-Codex wire cap, and ChatGPT Codex stream watchdog |
|
|
458
|
+
| `infra/services.ts` | per-run services container |
|
|
459
|
+
| `infra/session-identity.ts` | robust session-id resolution with opaque `unresolved:` fallback |
|
|
460
|
+
| `infra/ai-messages.ts` | boundary adapters between `LlmMessage` and pi-ai `Message` |
|
|
461
|
+
|
|
462
|
+
### Utility layer (`src/utils/`)
|
|
463
|
+
|
|
464
|
+
| File | Responsibility |
|
|
465
|
+
| --- | --- |
|
|
466
|
+
| `utils/extraction.ts` | deterministic fact extraction (files, errors, decisions) |
|
|
467
|
+
| `utils/pruning.ts` | redundancy removal on the message list |
|
|
468
|
+
| `utils/state.ts` | structured state, open loops, delta, pinned-path preservation |
|
|
469
|
+
| `utils/helpers.ts` | config, backups, batching, shared helpers, backup list/restore |
|
|
470
|
+
| `utils/cache.ts` | metrics log + extraction prefix cache |
|
|
471
|
+
| `utils/fingerprint.ts` | project fingerprinting (language, framework, deps) |
|
|
472
|
+
| `utils/damage.ts` | post-compaction regression signals + remediation hints |
|
|
473
|
+
| `utils/id-fingerprint.ts` | compact SHA-256 fingerprint of entry-id arrays |
|
|
474
|
+
| `utils/file-needles.ts` | path-suffix needles for error→file attribution |
|
|
475
|
+
| `utils/file-ref-detect.ts` | fabricated file-reference detection (SemVer-rejecting) |
|
|
476
|
+
| `utils/session-log.ts` | streaming JSONL parser for the Pi session log |
|
|
477
|
+
| `utils/tokens.ts` | per-(provider,model) token estimation with EMA calibration |
|
|
478
|
+
| `utils/type-guards.ts` | runtime validators for cross-version compatibility |
|
|
479
|
+
| `utils/logger.ts` | stderr-prefixed log shim |
|
|
480
|
+
| `utils/lru.ts` | small bounded LRU cache primitive |
|
|
481
|
+
|
|
482
|
+
### UI layer (`src/ui/`)
|
|
483
|
+
|
|
484
|
+
| File | Responsibility |
|
|
485
|
+
| --- | --- |
|
|
486
|
+
| `ui/overlays.ts` | progressive preflight, semantic phase progress, approval review, and dashboard screens |
|
|
487
|
+
| `ui/dashboard-format.ts` | shared pure formatters for metrics surfaces |
|
|
488
|
+
| `ui/dashboard-insights.ts` | Data Confidence, quality/provider drilldowns, and canary trust views |
|
|
489
|
+
| `ui/metrics-report.ts` | text report + local HTML metrics dashboard |
|
|
490
|
+
|
|
491
|
+
## Design principles
|
|
492
|
+
|
|
493
|
+
The architecture intentionally biases toward safety:
|
|
494
|
+
|
|
495
|
+
- deterministic extraction before any synthesis
|
|
496
|
+
- adaptive exploration instead of always-on tool use
|
|
497
|
+
- verified file lists and error context
|
|
498
|
+
- deterministic repair before additional LLM calls
|
|
499
|
+
- hallucinated file-reference detection
|
|
500
|
+
- stateful tracking of open loops and cross-compaction deltas
|
|
501
|
+
- tool-driven compaction never compacts mid-turn
|
|
502
|
+
- summaries preserve exact file paths and identifiers where possible
|
|
503
|
+
- the recent tail stays live outside the compacted region
|
|
504
|
+
|
|
505
|
+
## Extending the system
|
|
506
|
+
|
|
507
|
+
When adding features, prefer this order:
|
|
508
|
+
|
|
509
|
+
1. extract more deterministic signal if possible
|
|
510
|
+
2. enrich exploration only when needed
|
|
511
|
+
3. keep synthesis prompts structured and bounded
|
|
512
|
+
4. strengthen verification before increasing model dependence
|
|
513
|
+
5. update tests and docs in the same change
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@
|
|
|
4
4
|
|
|
5
5
|
No changes yet.
|
|
6
6
|
|
|
7
|
+
## [8.0.7] - 2026-08-08
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Window planning now reserves 25% of the LLM summary allowance for deterministic verification, delta, open-loop, and continuity sections added after synthesis. The reported `29,355t` versus `28,008t` near-target failure now plans a smaller retained tail and lands below the original hard target; the exact post-summary target gate and 10% minimum-saving floor remain fail-closed.
|
|
12
|
+
- Auto risk refinement changes analysis depth without mutating the already-planned profile/output allowance, preventing a late Fast/Balanced/Thorough profile switch from invalidating the target contract. Manual preflight now scans and tokenizes the active branch once for all three mode previews.
|
|
13
|
+
- Continuity now uses the latest substantive user request, parses host-compacted `Goal` sections, ignores acknowledgement-only turns, and treats free-form goal changes as non-destructive breadcrumbs. Prior errors, loops, next actions, and critical context remain active until positive resolution evidence or an explicit override; LLM goal paraphrases cannot silently resolve them.
|
|
14
|
+
- Known transient provider/invocation diagnostics no longer become durable blockers, while project test failures that mention HTTP 429 remain real errors. Initial and merged open-loop state is capped with active, high-priority work ahead of resolved history.
|
|
15
|
+
- File status follows newer successful access/mutation/delete evidence. Existing paths are removed from legacy `deletedFiles` state before persistence, eliminating the three false deletions observed in the v8.0.6 production run.
|
|
16
|
+
- Context-graph facts now use branch-head occurrences and lineage-scoped resolution, preventing equivalent sibling-branch facts from overwriting or closing each other. Schema v1 preserves manual memories while resetting older derived compaction nodes once.
|
|
17
|
+
- Release audit accepts both legacy-array and npm 12 object-shaped `npm pack --json` output, and the unsupported source-only Git install instruction was removed.
|
|
18
|
+
- Result and approval UX now labels `100/100` as post-repair verification coverage, shows the raw source score, and explicitly identifies deterministic safety-fallback runs instead of presenting repaired coverage as raw synthesis quality.
|
|
19
|
+
- Verification now rejects polarity changes symmetrically, and bounded absence never resolves continuity facts.
|
|
20
|
+
- Backups contain the complete selected pre-prune conversation after scrubbing; private artifact directories/files enforce `0700`/`0600`.
|
|
21
|
+
- Project memory fails closed when cwd is exactly HOME or the filesystem root, displays the complete scrubbed value for host confirmation, and caps active manual facts at 500 per project.
|
|
22
|
+
- Continuity and context-graph resolution use full visible branch ancestry; focus participates in synthesis cache identity, and project fingerprints use bounded locked updates.
|
|
23
|
+
- Canary reports total/applied runs and requires non-dry applied telemetry; deterministic green checks never imply `PROMOTE`.
|
|
24
|
+
- Auto timeout remains a cancellation deadline that waits for safe pipeline unwind, and yield failures use the canonical `yield` telemetry kind.
|
|
25
|
+
|
|
26
|
+
## [8.0.6] - 2026-08-07
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Replaced the dense flat `/smart-compact` preflight with a bordered decision card: context pressure, prominent `[M] Change` summary-model route, and side-by-side after-size/saving estimates for exactly Fast, Balanced, and Thorough. The selected plan keeps only outcome, retention, and hard safety guarantees visible; `D` reveals estimator, target, boundary, and route internals.
|
|
31
|
+
- Consolidated execution into three monotonic policies: Fast is the quickest/most compact 10K-tail policy, Balanced is the 20K-tail default, and Thorough is the 30K-tail high-fidelity policy with Explore and optional LLM repair. Legacy `aggressive` inputs map to Fast with a deprecation warning rather than appearing as a fourth mode.
|
|
32
|
+
- Manual runs now show a two-line semantic live brief: the colored Extract → Explore → Synthesize → Verify → Apply chain plus meaningful actions such as topic mapping, batch compression, continuity assembly, deterministic repair, and correlated Apply. Before Apply it explicitly states that the conversation is unchanged.
|
|
33
|
+
- Replaced routine phase toasts and per-batch provider/watchdog warnings with the live brief and content-free aggregated fallback status. Expected single-pass, Explore, batch, and assembly fallbacks no longer print raw provider messages or request IDs; auto-trigger verification failures emit one concise safe-fallback notice instead of evidence-bearing stderr lines. Full diagnostics remain opt-in through `DEBUG=smart-compact`.
|
|
34
|
+
- Fixed deterministic verification of Markdown-prefixed multiline errors (`> npm…`, list/heading prefixes): verification now canonicalizes the source snippet with the same safe one-line transform used by fallback rendering. The captured 259,782-token session replay now plans ~26,267 tokens after, repairs the remaining fabricated-file finding, and reaches 100/100 with 0 gaps even when every synthesis batch uses deterministic fallback.
|
|
35
|
+
|
|
7
36
|
## [8.0.5] - 2026-08-07
|
|
8
37
|
|
|
9
38
|
### Fixed
|