pi-smart-compact 7.9.0 → 7.9.2
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/CHANGELOG.md +29 -0
- package/README.md +11 -10
- package/dist/constants.d.ts +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +177 -59
- package/dist/ui/overlays.d.ts.map +1 -1
- package/dist/utils/cache.d.ts +11 -0
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/extraction.d.ts.map +1 -1
- package/dist/utils/fingerprint.d.ts +12 -2
- package/dist/utils/fingerprint.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts +16 -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.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [7.9.1] - 2026-05-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **`/smart-compact` race condition** — Added `waitForIdle()` to slash command handler. Previously the command could execute concurrently with agent streaming since extension commands bypass the input queue.
|
|
7
|
+
- **Tool `skipCompact` safety** — `ctx.compact()` internally calls `this.abort()`, which would kill the running agent loop if called from within a tool. Tool path now correctly keeps `skipCompact: true` and caches summary in `pendingRef` for the next natural compact.
|
|
8
|
+
- **Tool context-usage guard** — Tool now checks `getContextUsage()` before running and returns early with token info if context is too small.
|
|
9
|
+
- **Tool description enriched** — Better description and parameter hints so the agent knows when and how to call `smart_compact`.
|
|
10
|
+
|
|
11
|
+
## [7.9.0] - 2026-05-17
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **40 TypeScript strict-mode errors resolved** — `bunx tsc --noEmit` now passes cleanly with zero errors against latest `@earendil-works/pi-ai`, `pi-coding-agent`, `pi-tui` peer types.
|
|
15
|
+
- **`notify()` level mismatch** — `"success"` is not a valid level in `ExtensionUIContext.notify()`. All instances mapped to `"info"`.
|
|
16
|
+
- **`UserMessage.timestamp` mandatory** — 10 inline message objects across `explore.ts`, `synthesize.ts`, `verify.ts` were missing the required `timestamp: Date.now()` field.
|
|
17
|
+
- **`AgentToolResult.details` mandatory** — All tool return objects in `index.ts` now include explicit `details: undefined`.
|
|
18
|
+
- **`SelectList.selectedIndex` private accessor** — Replaced with `setSelectedIndex()` in `overlays.ts`.
|
|
19
|
+
- **`ThemeColor` union vs arbitrary string** — `theme.fg()` cast to `(c: string, t: string) => string` in overlays for dynamic color lookup.
|
|
20
|
+
- **`CacheAwareOptions` not assignable to `ProviderStreamOptions`** — Added explicit cast in `cache.ts`.
|
|
21
|
+
- **`blocks: unknown` after `Array.isArray`** — Explicit `unknown[]` typing in `extraction.ts` and `pruning.ts`.
|
|
22
|
+
- **`ExtensionContext` vs `ExtensionCommandContext`** — Proper `as unknown as` double-cast in `index.ts` for tool and hook contexts.
|
|
23
|
+
- **`apiKey?: string` (optional) used as `string`** — Extracted `apiKey` and `apiHeaders` as separate non-optional variables after guard check in `core.ts`.
|
|
24
|
+
- **`pendingRef.value` type narrowed to `never`** — TypeScript control flow after `pendingRef.value = null` prevented re-reading after `runSmartCompact`. Fixed with explicit cast.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- **`/smart-compact` command now uses `waitForIdle()`** — Prevents race condition when slash command is entered while agent is streaming. Agent finishes current turn before compaction starts.
|
|
28
|
+
- **Tool (`smart_compact`) keeps `skipCompact: true`** — Mid-turn compaction via `ctx.compact()` would abort the running agent loop (`this.abort()` internally). Tool prepares summary in `pendingRef` for the next natural compact to apply.
|
|
29
|
+
- **Tool description enriched** — Better description, parameter descriptions, and context-usage guard help the agent decide when to call smart_compact.
|
|
30
|
+
- **README.md updated** — version 7.9.0, module count 18, line count ~5,091, typecheck status now passing, added `logger.ts` and `type-guards.ts` to source table.
|
|
31
|
+
|
|
3
32
|
## [7.8.0] - 2026-05-17
|
|
4
33
|
|
|
5
34
|
### Fixed
|
package/README.md
CHANGED
|
@@ -57,12 +57,12 @@ The extension keeps a short-lived pending compaction in memory, then hands that
|
|
|
57
57
|
|
|
58
58
|
**Observed from the current codebase (`README`, `src/`, `test/`, `package.json`)**
|
|
59
59
|
|
|
60
|
-
- **Package version:** `7.
|
|
60
|
+
- **Package version:** `7.9.1`
|
|
61
61
|
- **Runtime entrypoint:** `dist/index.js`
|
|
62
62
|
- **Source entrypoint:** `src/index.ts`
|
|
63
|
-
- **Source modules:**
|
|
63
|
+
- **Source modules:** 18 TypeScript files under `src/`
|
|
64
64
|
- **Tests:** 9 test files, **93 passing tests**
|
|
65
|
-
- **Approx repo footprint:** ~5,
|
|
65
|
+
- **Approx repo footprint:** ~5,091 lines across `src/` + `test/`
|
|
66
66
|
- **Documentation asset:** `docs/assets/pi-smart-compact.png`
|
|
67
67
|
- **Published package files:** `dist/`, `docs/`, `README.md`, `LICENSE`, `CHANGELOG.md`
|
|
68
68
|
|
|
@@ -72,9 +72,9 @@ The extension keeps a short-lived pending compaction in memory, then hands that
|
|
|
72
72
|
| --- | --- | --- |
|
|
73
73
|
| `bun test` | ✅ Pass | 93/93 tests passing |
|
|
74
74
|
| `bun run build` | ✅ Pass | Bundles `src/index.ts` to `dist/index.js` |
|
|
75
|
-
| `bun run typecheck` |
|
|
75
|
+
| `bun run typecheck` | ✅ Pass | Strict TypeScript compatibility clean |
|
|
76
76
|
|
|
77
|
-
So the project is currently **buildable
|
|
77
|
+
So the project is currently **buildable, tested, and typecheck-clean**.
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
@@ -348,11 +348,13 @@ That pending summary is valid for **5 minutes** and is consumed by:
|
|
|
348
348
|
| `src/utils/cache.ts` | Metrics, cache-aware LLM options, extraction cache |
|
|
349
349
|
| `src/utils/damage.ts` | Post-compaction regression signal detection |
|
|
350
350
|
| `src/utils/extraction.ts` | Deterministic extraction and open-loop detection |
|
|
351
|
+
| `src/utils/logger.ts` | Centralized logging with shared prefix |
|
|
351
352
|
| `src/utils/fingerprint.ts` | Cross-session project fingerprinting |
|
|
352
353
|
| `src/utils/helpers.ts` | Config loading, backups, batching, prompt helpers |
|
|
353
354
|
| `src/utils/pruning.ts` | Redundancy pruning before compaction |
|
|
354
355
|
| `src/utils/state.ts` | Compaction state persistence and delta logic |
|
|
355
356
|
| `src/utils/tokens.ts` | Provider capabilities and token estimation |
|
|
357
|
+
| `src/utils/type-guards.ts` | Shared type guard functions |
|
|
356
358
|
|
|
357
359
|
### Tests
|
|
358
360
|
|
|
@@ -589,10 +591,9 @@ The current codebase includes these safeguards:
|
|
|
589
591
|
|
|
590
592
|
To keep this README aligned with the repository's **actual** current state:
|
|
591
593
|
|
|
592
|
-
1.
|
|
593
|
-
2. **
|
|
594
|
-
3. **The
|
|
595
|
-
4. **The extension depends on Pi runtime APIs and peer packages** (`@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, `typebox`).
|
|
594
|
+
1. **One legacy test filename remains:** `test/semantic-compact.test.ts`.
|
|
595
|
+
2. **The package is published from `dist/`**, not directly from `src/`. Source and tests are not included in the package tarball.
|
|
596
|
+
3. **The extension depends on Pi runtime APIs and peer packages** (`@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, `typebox`).
|
|
596
597
|
|
|
597
598
|
---
|
|
598
599
|
|
|
@@ -629,7 +630,7 @@ rm -rf dist && mkdir dist && bun build ./src/index.ts --outdir ./dist --target b
|
|
|
629
630
|
bun run typecheck
|
|
630
631
|
```
|
|
631
632
|
|
|
632
|
-
At the moment, this command
|
|
633
|
+
At the moment, this command passes cleanly.
|
|
633
634
|
|
|
634
635
|
### Typical local path inside Pi
|
|
635
636
|
|
package/dist/constants.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Constants, prompts, and profile defaults.
|
|
3
3
|
*/
|
|
4
4
|
import type { CompressionProfile, ProfileConfig } from "./types.ts";
|
|
5
|
-
export declare const VERSION = "7.9.
|
|
5
|
+
export declare const VERSION = "7.9.1";
|
|
6
6
|
export declare const CHARS_PER_TOKEN = 3.8;
|
|
7
7
|
export declare const COMPACT_SYSTEM_PREFIX: string;
|
|
8
8
|
export declare const PROFILES: Record<CompressionProfile, ProfileConfig>;
|
package/dist/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EACV,kBAAkB,EAAE,iBAAiB,EAEtC,MAAM,YAAY,CAAC;AAsBpB,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,uBAAuB,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE;QAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EACV,kBAAkB,EAAE,iBAAiB,EAEtC,MAAM,YAAY,CAAC;AAsBpB,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,uBAAuB,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE;QAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgW9E"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,iCAAiC,CAAC;AAwC7F,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,iCAAiC,CAAC;AAwC7F,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,YAAY,QA2I7D"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/constants.ts
|
|
3
|
-
var VERSION = "7.9.
|
|
3
|
+
var VERSION = "7.9.1";
|
|
4
4
|
var CHARS_PER_TOKEN = 3.8;
|
|
5
5
|
var COMPACT_SYSTEM_PREFIX = "You are an expert conversation summarizer for a coding agent. " + "Produce structured markdown summaries. " + "Follow output format exactly. " + "Use EXACT names \u2014 never paraphrase code identifiers. " + "Trust deterministic extraction data over intuition.";
|
|
6
6
|
var PROFILES = {
|
|
@@ -197,6 +197,33 @@ function debug(msg, ...args) {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// src/utils/helpers.ts
|
|
200
|
+
function validateSmartCompactConfig(sc) {
|
|
201
|
+
const VALID_PROFILES = ["light", "balanced", "aggressive"];
|
|
202
|
+
if ("profile" in sc && !VALID_PROFILES.includes(sc.profile)) {
|
|
203
|
+
warn("smart-compact config: invalid profile '" + sc.profile + "', expected light|balanced|aggressive. Using default 'balanced'.");
|
|
204
|
+
delete sc.profile;
|
|
205
|
+
}
|
|
206
|
+
if ("autoTrigger" in sc && typeof sc.autoTrigger !== "boolean") {
|
|
207
|
+
warn("smart-compact config: autoTrigger must be boolean, got " + typeof sc.autoTrigger);
|
|
208
|
+
delete sc.autoTrigger;
|
|
209
|
+
}
|
|
210
|
+
if ("backupEnabled" in sc && typeof sc.backupEnabled !== "boolean") {
|
|
211
|
+
warn("smart-compact config: backupEnabled must be boolean, got " + typeof sc.backupEnabled);
|
|
212
|
+
delete sc.backupEnabled;
|
|
213
|
+
}
|
|
214
|
+
if ("summaryModel" in sc && sc.summaryModel !== null && typeof sc.summaryModel !== "string") {
|
|
215
|
+
warn("smart-compact config: summaryModel must be string|null, got " + typeof sc.summaryModel);
|
|
216
|
+
delete sc.summaryModel;
|
|
217
|
+
}
|
|
218
|
+
if ("segmentationModel" in sc && sc.segmentationModel !== null && typeof sc.segmentationModel !== "string") {
|
|
219
|
+
warn("smart-compact config: segmentationModel must be string|null, got " + typeof sc.segmentationModel);
|
|
220
|
+
delete sc.segmentationModel;
|
|
221
|
+
}
|
|
222
|
+
if ("profiles" in sc && (typeof sc.profiles !== "object" || sc.profiles === null || Array.isArray(sc.profiles))) {
|
|
223
|
+
warn("smart-compact config: profiles must be an object, got " + typeof sc.profiles);
|
|
224
|
+
delete sc.profiles;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
200
227
|
var _cfg = null;
|
|
201
228
|
var _cfgMtime = 0;
|
|
202
229
|
function loadConfig() {
|
|
@@ -207,6 +234,7 @@ function loadConfig() {
|
|
|
207
234
|
return _cfg;
|
|
208
235
|
const raw = JSON.parse(fs.readFileSync(p, "utf-8"));
|
|
209
236
|
const sc = raw[CONFIG_KEY] ?? raw[CONFIG_KEY_ALT] ?? {};
|
|
237
|
+
validateSmartCompactConfig(sc);
|
|
210
238
|
const merged = { ...DEFAULT_CONFIG, ...sc };
|
|
211
239
|
if (sc.profiles)
|
|
212
240
|
merged.profiles = { ...PROFILES, ...sc.profiles };
|
|
@@ -372,6 +400,24 @@ function buildExtractionContext(extraction, forRange) {
|
|
|
372
400
|
].join(`
|
|
373
401
|
`);
|
|
374
402
|
}
|
|
403
|
+
function inferSessionType(extraction, report) {
|
|
404
|
+
if (report?.sessionType)
|
|
405
|
+
return report.sessionType;
|
|
406
|
+
const hasModifications = extraction.modifiedFiles.length > 0;
|
|
407
|
+
const hasUnresolvedErrors = extraction.errors.some((e) => !e.resolved);
|
|
408
|
+
const hasResolvedErrors = extraction.errors.some((e) => e.resolved);
|
|
409
|
+
const hasReadsOnly = extraction.readFiles.length > 2 && !hasModifications;
|
|
410
|
+
const hasDecisions = extraction.decisions.length > 0;
|
|
411
|
+
if (hasUnresolvedErrors && (hasModifications || hasResolvedErrors))
|
|
412
|
+
return "debugging";
|
|
413
|
+
if (hasReadsOnly && !hasDecisions)
|
|
414
|
+
return "review";
|
|
415
|
+
if (hasDecisions && !hasModifications && !hasUnresolvedErrors)
|
|
416
|
+
return "discussion";
|
|
417
|
+
if (hasModifications)
|
|
418
|
+
return "implementation";
|
|
419
|
+
return "implementation";
|
|
420
|
+
}
|
|
375
421
|
function buildExplorationContext(report) {
|
|
376
422
|
if (!report.mainGoal && !report.crossReferences.length && !report.enrichedConstraints.length)
|
|
377
423
|
return "";
|
|
@@ -649,15 +695,28 @@ function loadCachedExtraction(sessionId) {
|
|
|
649
695
|
}
|
|
650
696
|
}
|
|
651
697
|
function mergeExtractions(base, delta, baseMsgCount) {
|
|
698
|
+
const offsetErrors = delta.errors.map((e) => ({ ...e, index: e.index + baseMsgCount }));
|
|
699
|
+
const offsetDecisions = delta.decisions.map((d) => ({ ...d, index: d.index + baseMsgCount }));
|
|
700
|
+
const offsetConstraints = delta.constraints.map((c) => ({ ...c, index: c.index + baseMsgCount }));
|
|
701
|
+
const offsetTopics = delta.topics.map((t) => ({
|
|
702
|
+
...t,
|
|
703
|
+
startIndex: t.startIndex + baseMsgCount,
|
|
704
|
+
endIndex: t.endIndex + baseMsgCount
|
|
705
|
+
}));
|
|
706
|
+
const offsetTimeline = delta.timeline.map((t) => ({ ...t, index: t.index + baseMsgCount }));
|
|
707
|
+
const offsetModifiedFiles = delta.modifiedFiles.map((f) => ({
|
|
708
|
+
...f,
|
|
709
|
+
lastModifiedIndex: f.lastModifiedIndex + baseMsgCount
|
|
710
|
+
}));
|
|
652
711
|
return {
|
|
653
|
-
modifiedFiles: [...new Map([...base.modifiedFiles, ...
|
|
712
|
+
modifiedFiles: [...new Map([...base.modifiedFiles, ...offsetModifiedFiles].map((f) => [f.path, f])).values()],
|
|
654
713
|
readFiles: [...new Set([...base.readFiles, ...delta.readFiles])],
|
|
655
714
|
deletedFiles: [...new Set([...base.deletedFiles, ...delta.deletedFiles])],
|
|
656
|
-
errors: [...base.errors, ...
|
|
657
|
-
decisions: [...base.decisions, ...
|
|
658
|
-
constraints: [...base.constraints, ...
|
|
659
|
-
topics: [...base.topics, ...
|
|
660
|
-
timeline: [...base.timeline, ...
|
|
715
|
+
errors: [...base.errors, ...offsetErrors],
|
|
716
|
+
decisions: [...base.decisions, ...offsetDecisions],
|
|
717
|
+
constraints: [...base.constraints, ...offsetConstraints],
|
|
718
|
+
topics: [...base.topics, ...offsetTopics],
|
|
719
|
+
timeline: [...base.timeline, ...offsetTimeline],
|
|
661
720
|
mainGoal: delta.mainGoal ?? base.mainGoal,
|
|
662
721
|
lastUserMessages: delta.lastUserMessages.length > 0 ? delta.lastUserMessages : base.lastUserMessages,
|
|
663
722
|
lastErrors: delta.lastErrors.length > 0 ? delta.lastErrors : base.lastErrors,
|
|
@@ -782,7 +841,8 @@ function catalogErrors(msgs, _tcIdx) {
|
|
|
782
841
|
for (const err of errors) {
|
|
783
842
|
for (let j = err.index + 1;j < Math.min(msgs.length, err.index + 6); j++) {
|
|
784
843
|
if (msgs[j]?.role === "assistant") {
|
|
785
|
-
const
|
|
844
|
+
const rawBlocks = msgs[j]?.content;
|
|
845
|
+
const blocks = Array.isArray(rawBlocks) ? rawBlocks : [];
|
|
786
846
|
for (const b of blocks) {
|
|
787
847
|
if (isToolCallBlock(b) && b.name === err.tool) {
|
|
788
848
|
err.retryAttempted = true;
|
|
@@ -1123,7 +1183,7 @@ function buildCompactionState(extraction, openLoops, report, nextActions, critic
|
|
|
1123
1183
|
})),
|
|
1124
1184
|
nextActions,
|
|
1125
1185
|
criticalContext,
|
|
1126
|
-
sessionType: report
|
|
1186
|
+
sessionType: inferSessionType(extraction, report),
|
|
1127
1187
|
compactionVersion: VERSION,
|
|
1128
1188
|
updatedAt: Date.now()
|
|
1129
1189
|
};
|
|
@@ -1312,7 +1372,8 @@ function pruneRedundant(msgs) {
|
|
|
1312
1372
|
for (let idx = 0;idx < msgs.length; idx++) {
|
|
1313
1373
|
if (msgs[idx].role !== "assistant")
|
|
1314
1374
|
continue;
|
|
1315
|
-
const
|
|
1375
|
+
const rawBlocks = msgs[idx].content;
|
|
1376
|
+
const blocks = Array.isArray(rawBlocks) ? rawBlocks : [];
|
|
1316
1377
|
const hasToolCall = blocks.some((b) => isToolCallBlock(b));
|
|
1317
1378
|
if (hasToolCall)
|
|
1318
1379
|
continue;
|
|
@@ -1390,22 +1451,73 @@ var FRAMEWORK_SIGNALS = [
|
|
|
1390
1451
|
function getFingerprintPath(projectId) {
|
|
1391
1452
|
return path5.join(FINGERPRINT_DIR, projectId + ".json");
|
|
1392
1453
|
}
|
|
1454
|
+
var NOISE_PATH_RE = /(?:node_modules|[/\\]\.pi[/\\]agent|[/\\]\.cache|[/\\]\.npm|[/\\]\.bun|[/\\]\.git[/\\])/;
|
|
1455
|
+
function isProjectPath(filePath) {
|
|
1456
|
+
return !NOISE_PATH_RE.test(filePath);
|
|
1457
|
+
}
|
|
1458
|
+
function hashProjectId(seed) {
|
|
1459
|
+
return "proj-" + crypto3.createHash("sha256").update(seed).digest("hex").slice(0, 12);
|
|
1460
|
+
}
|
|
1461
|
+
function deriveFromAbsolutePaths(paths) {
|
|
1462
|
+
const segments = paths.map((p) => p.replace(/^\/+/, "").split("/").filter(Boolean)).filter((s) => s.length >= 3);
|
|
1463
|
+
if (segments.length < 2)
|
|
1464
|
+
return deriveFromRelativePaths(paths);
|
|
1465
|
+
const dirCounts = new Map;
|
|
1466
|
+
for (const segs of segments) {
|
|
1467
|
+
for (let depth = 3;depth <= segs.length; depth++) {
|
|
1468
|
+
const prefix = segs.slice(0, depth).join("/");
|
|
1469
|
+
dirCounts.set(prefix, (dirCounts.get(prefix) ?? 0) + 1);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
const threshold = Math.ceil(segments.length * 0.5);
|
|
1473
|
+
const candidates = [...dirCounts.entries()].filter(([, count]) => count >= threshold).sort((a, b) => {
|
|
1474
|
+
const depthDiff = b[0].split("/").length - a[0].split("/").length;
|
|
1475
|
+
if (depthDiff !== 0)
|
|
1476
|
+
return depthDiff;
|
|
1477
|
+
return b[1] - a[1];
|
|
1478
|
+
});
|
|
1479
|
+
if (candidates.length)
|
|
1480
|
+
return hashProjectId(candidates[0][0]);
|
|
1481
|
+
const sorted = [...segments].sort((a, b) => a.length - b.length);
|
|
1482
|
+
let commonDepth = 0;
|
|
1483
|
+
for (let d = 0;d < sorted[0].length; d++) {
|
|
1484
|
+
if (segments.every((s) => s[d] === sorted[0][d]))
|
|
1485
|
+
commonDepth = d + 1;
|
|
1486
|
+
else
|
|
1487
|
+
break;
|
|
1488
|
+
}
|
|
1489
|
+
return hashProjectId(sorted[0].slice(0, Math.max(commonDepth, 3)).join("/"));
|
|
1490
|
+
}
|
|
1491
|
+
function deriveFromRelativePaths(paths) {
|
|
1492
|
+
const topEntries = [...new Set(paths.map((p) => p.split("/").filter(Boolean)[0]).filter(Boolean))].sort();
|
|
1493
|
+
const dir2Counts = new Map;
|
|
1494
|
+
for (const p of paths) {
|
|
1495
|
+
const segs = p.split("/").filter(Boolean);
|
|
1496
|
+
if (segs.length >= 2) {
|
|
1497
|
+
const d2 = segs.slice(0, 2).join("/");
|
|
1498
|
+
dir2Counts.set(d2, (dir2Counts.get(d2) ?? 0) + 1);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
const stableDirs = [...dir2Counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([d]) => d).sort();
|
|
1502
|
+
const fingerprint = topEntries.join(",") + "|" + stableDirs.join(",");
|
|
1503
|
+
return hashProjectId(fingerprint);
|
|
1504
|
+
}
|
|
1393
1505
|
function deriveProjectId(extraction) {
|
|
1394
1506
|
const allPaths = [
|
|
1395
1507
|
...extraction.modifiedFiles.map((f) => f.path),
|
|
1396
1508
|
...extraction.readFiles
|
|
1397
|
-
];
|
|
1509
|
+
].filter(isProjectPath);
|
|
1398
1510
|
if (!allPaths.length)
|
|
1399
1511
|
return "unknown";
|
|
1400
|
-
const
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1512
|
+
const absolutePaths = allPaths.filter((p) => p.startsWith("/"));
|
|
1513
|
+
const relativePaths = allPaths.filter((p) => !p.startsWith("/"));
|
|
1514
|
+
if (absolutePaths.length >= 2) {
|
|
1515
|
+
return deriveFromAbsolutePaths(absolutePaths);
|
|
1516
|
+
}
|
|
1517
|
+
if (relativePaths.length >= 2) {
|
|
1518
|
+
return deriveFromRelativePaths(relativePaths);
|
|
1405
1519
|
}
|
|
1406
|
-
|
|
1407
|
-
const hash = crypto3.createHash("sha256").update(topRoot).digest("hex").slice(0, 12);
|
|
1408
|
-
return "proj-" + hash;
|
|
1520
|
+
return hashProjectId(allPaths.sort().join("|"));
|
|
1409
1521
|
}
|
|
1410
1522
|
function detectLanguage(extraction) {
|
|
1411
1523
|
const extCounts = new Map;
|
|
@@ -1832,7 +1944,7 @@ async function exploreConversation(llmMessages, extraction, model, auth, prevSum
|
|
|
1832
1944
|
}
|
|
1833
1945
|
const probeResp = await trackedComplete("explore", model, {
|
|
1834
1946
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
1835
|
-
messages: [{ role: "user", content: [{ type: "text", text: userContent }] }],
|
|
1947
|
+
messages: [{ role: "user", content: [{ type: "text", text: userContent }], timestamp: Date.now() }],
|
|
1836
1948
|
tools: EXPLORATION_TOOLS
|
|
1837
1949
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, signal }, model.provider));
|
|
1838
1950
|
const toolCalls = probeResp.content.filter((c) => c.type === "toolCall");
|
|
@@ -1929,7 +2041,7 @@ User steering: ` + userNote : "");
|
|
|
1929
2041
|
try {
|
|
1930
2042
|
const resp = await trackedComplete("explore-retry", model, {
|
|
1931
2043
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
1932
|
-
messages: [{ role: "user", content: [{ type: "text", text: retryPrompt }] }]
|
|
2044
|
+
messages: [{ role: "user", content: [{ type: "text", text: retryPrompt }], timestamp: Date.now() }]
|
|
1933
2045
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, maxTokens: Math.min(4096, getProviderCaps(model.provider).maxOutputTokens), signal }, model.provider));
|
|
1934
2046
|
const text = resp.content.filter((c) => c.type === "text").map((c) => c.text).join("").trim();
|
|
1935
2047
|
return parseExplorationReport(text, llmMessages);
|
|
@@ -1967,7 +2079,7 @@ Output ONLY JSON: {"mainGoal":"...","sessionType":"implementation|review|debuggi
|
|
|
1967
2079
|
try {
|
|
1968
2080
|
const resp = await trackedComplete("explore-direct", model, {
|
|
1969
2081
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
1970
|
-
messages: [{ role: "user", content: [{ type: "text", text: prompt }] }]
|
|
2082
|
+
messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
|
|
1971
2083
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, maxTokens: Math.min(4096, getProviderCaps(model.provider).maxOutputTokens), signal }, model.provider));
|
|
1972
2084
|
const text = resp.content.filter((c) => c.type === "text").map((c) => c.text).join(`
|
|
1973
2085
|
`).trim();
|
|
@@ -2042,7 +2154,7 @@ function chunkLlmMessages(msgs, boundaries, pc) {
|
|
|
2042
2154
|
async function singlePassCompact(convText, extraction, report, prevContext, model, auth, signal) {
|
|
2043
2155
|
const extractionCtx = buildExtractionContext(extraction);
|
|
2044
2156
|
const explorationCtx = report ? buildExplorationContext(report) : "";
|
|
2045
|
-
const sessionType = report
|
|
2157
|
+
const sessionType = inferSessionType(extraction, report);
|
|
2046
2158
|
const sessionInstruction = SESSION_TYPE_INSTRUCTIONS[sessionType] ?? SESSION_TYPE_INSTRUCTIONS.implementation;
|
|
2047
2159
|
const adaptedPrefix = SINGLE_PASS_PREFIX + `
|
|
2048
2160
|
Session-specific instructions:
|
|
@@ -2051,8 +2163,8 @@ Session-specific instructions:
|
|
|
2051
2163
|
const resp = await trackedComplete("single-pass", model, {
|
|
2052
2164
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
2053
2165
|
messages: [
|
|
2054
|
-
{ role: "user", content: [{ type: "text", text: adaptedPrefix }] },
|
|
2055
|
-
{ role: "user", content: [{ type: "text", text: dynamicSuffix }] }
|
|
2166
|
+
{ role: "user", content: [{ type: "text", text: adaptedPrefix }], timestamp: Date.now() },
|
|
2167
|
+
{ role: "user", content: [{ type: "text", text: dynamicSuffix }], timestamp: Date.now() }
|
|
2056
2168
|
]
|
|
2057
2169
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, maxTokens: getProviderCaps(model.provider).maxOutputTokens, signal }, model.provider));
|
|
2058
2170
|
const summary = resp.content.filter((c) => c.type === "text").map((c) => c.text).join(`
|
|
@@ -2082,8 +2194,8 @@ async function summarizeBatch(batch, extraction, model, auth, signal) {
|
|
|
2082
2194
|
const resp = await trackedComplete("batch", model, {
|
|
2083
2195
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
2084
2196
|
messages: [
|
|
2085
|
-
{ role: "user", content: [{ type: "text", text: BATCH_PROMPT_PREFIX }] },
|
|
2086
|
-
{ role: "user", content: [{ type: "text", text: dynamicSuffix }] }
|
|
2197
|
+
{ role: "user", content: [{ type: "text", text: BATCH_PROMPT_PREFIX }], timestamp: Date.now() },
|
|
2198
|
+
{ role: "user", content: [{ type: "text", text: dynamicSuffix }], timestamp: Date.now() }
|
|
2087
2199
|
]
|
|
2088
2200
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, maxTokens: Math.min(4096, getProviderCaps(model.provider).maxOutputTokens), signal }, model.provider));
|
|
2089
2201
|
const output = resp.content.filter((c) => c.type === "text").map((c) => c.text).join(`
|
|
@@ -2123,8 +2235,8 @@ async function assembleLLM(summaries, extraction, report, model, auth, budget, p
|
|
|
2123
2235
|
const resp = await trackedComplete("assemble", model, {
|
|
2124
2236
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
2125
2237
|
messages: [
|
|
2126
|
-
{ role: "user", content: [{ type: "text", text: ASSEMBLY_PROMPT_PREFIX }] },
|
|
2127
|
-
{ role: "user", content: [{ type: "text", text: dynamicSuffix }] }
|
|
2238
|
+
{ role: "user", content: [{ type: "text", text: ASSEMBLY_PROMPT_PREFIX }], timestamp: Date.now() },
|
|
2239
|
+
{ role: "user", content: [{ type: "text", text: dynamicSuffix }], timestamp: Date.now() }
|
|
2128
2240
|
]
|
|
2129
2241
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, maxTokens: Math.min(budget, getProviderCaps(model.provider).maxOutputTokens), signal }, model.provider));
|
|
2130
2242
|
return resp.content.filter((c) => c.type === "text").map((c) => c.text).join(`
|
|
@@ -2337,7 +2449,7 @@ Return the COMPLETE updated summary with missing items integrated. Keep the same
|
|
|
2337
2449
|
try {
|
|
2338
2450
|
const resp = await trackedComplete("patch", model, {
|
|
2339
2451
|
systemPrompt: COMPACT_SYSTEM_PREFIX,
|
|
2340
|
-
messages: [{ role: "user", content: [{ type: "text", text: patchPrompt }] }]
|
|
2452
|
+
messages: [{ role: "user", content: [{ type: "text", text: patchPrompt }], timestamp: Date.now() }]
|
|
2341
2453
|
}, cacheOpts({ apiKey: auth.apiKey, headers: auth.headers, maxTokens: 8192, signal }));
|
|
2342
2454
|
const patched = resp.content.filter((c) => c.type === "text").map((c) => c.text).join(`
|
|
2343
2455
|
`).trim();
|
|
@@ -2398,7 +2510,7 @@ async function selectModel(ctx, opts) {
|
|
|
2398
2510
|
scrollInfo: (t) => theme.fg("dim", t),
|
|
2399
2511
|
noMatch: (t) => theme.fg("warning", t)
|
|
2400
2512
|
});
|
|
2401
|
-
sel.
|
|
2513
|
+
sel.setSelectedIndex(opts.defaultModelIndex);
|
|
2402
2514
|
sel.onSelect = (item) => done(item.value);
|
|
2403
2515
|
sel.onCancel = () => done(null);
|
|
2404
2516
|
c.addChild(sel);
|
|
@@ -2447,7 +2559,7 @@ async function selectProfile(ctx, selectedModel, opts) {
|
|
|
2447
2559
|
scrollInfo: (t) => theme.fg("dim", t),
|
|
2448
2560
|
noMatch: (t) => theme.fg("warning", t)
|
|
2449
2561
|
});
|
|
2450
|
-
sel.
|
|
2562
|
+
sel.setSelectedIndex(1);
|
|
2451
2563
|
sel.onSelect = (item) => done(item.value);
|
|
2452
2564
|
sel.onCancel = () => done(null);
|
|
2453
2565
|
c.addChild(sel);
|
|
@@ -2472,8 +2584,7 @@ function showProgressOverlay(ctx, state) {
|
|
|
2472
2584
|
const progress = Math.round(state.phase / 4 * 100);
|
|
2473
2585
|
const name = phaseNames[state.phase - 1] ?? "?";
|
|
2474
2586
|
const detail = state.detail ? " (" + state.detail + ")" : "";
|
|
2475
|
-
|
|
2476
|
-
ctx.ui.notify("EESV [" + progress + "%] Phase " + state.phase + "/4: " + name + detail, type);
|
|
2587
|
+
ctx.ui.notify("EESV [" + progress + "%] Phase " + state.phase + "/4: " + name + detail, state.phase >= 4 ? "info" : "info");
|
|
2477
2588
|
}
|
|
2478
2589
|
async function showResultScreen(ctx, details, extraction) {
|
|
2479
2590
|
await ctx.ui.custom((tui, theme, _kb, done) => {
|
|
@@ -2615,6 +2726,8 @@ async function runSmartCompact(opts) {
|
|
|
2615
2726
|
ctx.ui.notify("Auth failed", "error");
|
|
2616
2727
|
return;
|
|
2617
2728
|
}
|
|
2729
|
+
const apiKey = auth.apiKey;
|
|
2730
|
+
const apiHeaders = auth.headers;
|
|
2618
2731
|
const usage = ctx.getContextUsage();
|
|
2619
2732
|
const totalTokens = usage?.tokens ?? 0;
|
|
2620
2733
|
if (!totalTokens || totalTokens < MIN_TOKEN_THRESHOLD) {
|
|
@@ -2624,7 +2737,7 @@ async function runSmartCompact(opts) {
|
|
|
2624
2737
|
return;
|
|
2625
2738
|
}
|
|
2626
2739
|
const notify = (msg, type = "info") => {
|
|
2627
|
-
ctx.ui.notify(msg, type);
|
|
2740
|
+
ctx.ui.notify(msg, type === "success" ? "info" : type);
|
|
2628
2741
|
};
|
|
2629
2742
|
const ctrl = new AbortController;
|
|
2630
2743
|
const signal = ctrl.signal;
|
|
@@ -2654,7 +2767,7 @@ async function runSmartCompact(opts) {
|
|
|
2654
2767
|
isRunning.value = false;
|
|
2655
2768
|
return;
|
|
2656
2769
|
}
|
|
2657
|
-
const firstKeptId = msgs[keepFrom]?.id ?? msgs[msgs.length - 1]?.id
|
|
2770
|
+
const firstKeptId = msgs[keepFrom]?.id ?? msgs[msgs.length - 1]?.id;
|
|
2658
2771
|
if (!autoTriggered) {
|
|
2659
2772
|
showProgressOverlay(ctx, { phase: 1, phaseName: "Extract", detail: "Preparing...", model: modelLabel, profile });
|
|
2660
2773
|
}
|
|
@@ -2698,7 +2811,7 @@ async function runSmartCompact(opts) {
|
|
|
2698
2811
|
if (!autoTriggered)
|
|
2699
2812
|
showProgressOverlay(ctx, { phase: 2, phaseName: "Explore", detail: "Single-pass (" + convTokens.toLocaleString() + "t)", model: modelLabel, profile, extraction });
|
|
2700
2813
|
try {
|
|
2701
|
-
const r = await singlePassCompact(convText, extraction, null, prevContext + projectCtx, summaryModel, { apiKey
|
|
2814
|
+
const r = await singlePassCompact(convText, extraction, null, prevContext + projectCtx, summaryModel, { apiKey, headers: apiHeaders }, signal);
|
|
2702
2815
|
finalSummary = r.summary;
|
|
2703
2816
|
method = "single-pass";
|
|
2704
2817
|
llmCalls = r.llmCalls;
|
|
@@ -2763,7 +2876,7 @@ async function runSmartCompact(opts) {
|
|
|
2763
2876
|
const concurrency = caps.concurrencyLimit;
|
|
2764
2877
|
if (totalBatches <= 1) {
|
|
2765
2878
|
try {
|
|
2766
|
-
summaries.push(...await summarizeBatch(batches[0], extraction, summaryModel, { apiKey
|
|
2879
|
+
summaries.push(...await summarizeBatch(batches[0], extraction, summaryModel, { apiKey, headers: apiHeaders }, signal));
|
|
2767
2880
|
} catch (err) {
|
|
2768
2881
|
summaries.push(...batches[0].map((ch) => ({
|
|
2769
2882
|
topic: ch.topic,
|
|
@@ -2786,7 +2899,7 @@ async function runSmartCompact(opts) {
|
|
|
2786
2899
|
const wavePromises = waveBatches.map(async (batch, i) => {
|
|
2787
2900
|
const idx = wave + i;
|
|
2788
2901
|
try {
|
|
2789
|
-
results[idx] = await summarizeBatch(batch, extraction, summaryModel, { apiKey
|
|
2902
|
+
results[idx] = await summarizeBatch(batch, extraction, summaryModel, { apiKey, headers: apiHeaders }, signal);
|
|
2790
2903
|
} catch (err) {
|
|
2791
2904
|
errors[idx] = err instanceof Error ? err : new Error(String(err));
|
|
2792
2905
|
results[idx] = batch.map((ch) => ({
|
|
@@ -2818,7 +2931,7 @@ async function runSmartCompact(opts) {
|
|
|
2818
2931
|
showProgressOverlay(ctx, { phase: 3, phaseName: "Synthesize", detail: "Assembling...", model: modelLabel, profile, extraction, totalBatches: batches.length });
|
|
2819
2932
|
let assemblyCalls = 1;
|
|
2820
2933
|
try {
|
|
2821
|
-
const r = await assembleLLM(summaries, extraction, explorationReport, summaryModel, { apiKey
|
|
2934
|
+
const r = await assembleLLM(summaries, extraction, explorationReport, summaryModel, { apiKey, headers: apiHeaders }, pc.summaryBudgetTokens, prevContext, signal);
|
|
2822
2935
|
if (r?.startsWith("##"))
|
|
2823
2936
|
finalSummary = r;
|
|
2824
2937
|
else
|
|
@@ -2842,7 +2955,7 @@ async function runSmartCompact(opts) {
|
|
|
2842
2955
|
if (!recheck.ok && recheck.score < 75) {
|
|
2843
2956
|
notify("Phase 4 Verify: deterministic patch insufficient (score=" + recheck.score + "), trying LLM patch", "warning");
|
|
2844
2957
|
try {
|
|
2845
|
-
finalSummary = await patchSummary(finalSummary, recheck.gaps, summaryModel, { apiKey
|
|
2958
|
+
finalSummary = await patchSummary(finalSummary, recheck.gaps, summaryModel, { apiKey, headers: apiHeaders }, signal);
|
|
2846
2959
|
llmCalls++;
|
|
2847
2960
|
} catch (err) {
|
|
2848
2961
|
warn("LLM patch failed", err);
|
|
@@ -2941,7 +3054,7 @@ async function runSmartCompact(opts) {
|
|
|
2941
3054
|
customInstructions: "Use pre-computed smart summary from /smart-compact",
|
|
2942
3055
|
onComplete: () => {
|
|
2943
3056
|
if (!autoTriggered)
|
|
2944
|
-
ctx.ui.notify("Applied \u2713", "
|
|
3057
|
+
ctx.ui.notify("Applied \u2713", "info");
|
|
2945
3058
|
},
|
|
2946
3059
|
onError: (e) => {
|
|
2947
3060
|
if (!autoTriggered)
|
|
@@ -2996,6 +3109,7 @@ function smartCompactExtension(pi) {
|
|
|
2996
3109
|
return m.length ? m : null;
|
|
2997
3110
|
},
|
|
2998
3111
|
handler: async (args, ctx) => {
|
|
3112
|
+
await ctx.waitForIdle();
|
|
2999
3113
|
try {
|
|
3000
3114
|
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
3001
3115
|
const flags = tokens.map((t) => t.toLowerCase());
|
|
@@ -3072,11 +3186,11 @@ function smartCompactExtension(pi) {
|
|
|
3072
3186
|
return;
|
|
3073
3187
|
if (!isRunning.value) {
|
|
3074
3188
|
await runSmartCompact({ ctx, summaryModel: sumModel, segModel: segModel ?? sumModel, profile: config.profile, pendingRef, isRunning, autoTriggered: true });
|
|
3075
|
-
|
|
3076
|
-
|
|
3189
|
+
const pending = pendingRef.value;
|
|
3190
|
+
if (pending) {
|
|
3077
3191
|
pendingRef.value = null;
|
|
3078
3192
|
pendingRef.createdAt = 0;
|
|
3079
|
-
return { compaction: { summary:
|
|
3193
|
+
return { compaction: { summary: pending.summary, firstKeptEntryId: pending.firstKeptEntryId, tokensBefore: pending.tokensBefore, details: pending.details } };
|
|
3080
3194
|
}
|
|
3081
3195
|
}
|
|
3082
3196
|
} catch (e) {
|
|
@@ -3086,15 +3200,15 @@ function smartCompactExtension(pi) {
|
|
|
3086
3200
|
pi.registerTool({
|
|
3087
3201
|
name: "smart_compact",
|
|
3088
3202
|
label: "Smart Compact",
|
|
3089
|
-
description: "EESV smart compaction v" + VERSION + " with deterministic extraction, exploration, and verification.",
|
|
3203
|
+
description: "EESV smart compaction v" + VERSION + " with deterministic extraction, exploration, and verification. Compacts the conversation into a structured summary preserving goals, decisions, open loops, modified files, and critical context. Call this when the conversation is getting long \u2014 the tool internally checks context usage and skips if not needed. Prefer this over default compact.",
|
|
3090
3204
|
promptSnippet: "Smart compaction",
|
|
3091
|
-
promptGuidelines: ["Use for long conversations.
|
|
3205
|
+
promptGuidelines: ["Use for long conversations. Prefer over default compact."],
|
|
3092
3206
|
parameters: {
|
|
3093
3207
|
type: "object",
|
|
3094
3208
|
properties: {
|
|
3095
|
-
profile: { type: "string", description: "light, balanced, or aggressive" },
|
|
3096
|
-
verbose: { type: "boolean" },
|
|
3097
|
-
dry_run: { type: "boolean" }
|
|
3209
|
+
profile: { type: "string", description: "light, balanced, or aggressive. Default: balanced." },
|
|
3210
|
+
verbose: { type: "boolean", description: "Show detailed pipeline output." },
|
|
3211
|
+
dry_run: { type: "boolean", description: "Run the pipeline but skip applying the compaction." }
|
|
3098
3212
|
}
|
|
3099
3213
|
},
|
|
3100
3214
|
async execute(_id, params, _sig, _onUp, ctx) {
|
|
@@ -3103,25 +3217,29 @@ function smartCompactExtension(pi) {
|
|
|
3103
3217
|
const dryRun = !!params.dry_run;
|
|
3104
3218
|
const config = loadConfig();
|
|
3105
3219
|
const resolvedProfile = profile ?? config.profile;
|
|
3220
|
+
const cmdCtx = ctx;
|
|
3221
|
+
const usage = ctx.getContextUsage?.();
|
|
3222
|
+
const totalTokens = usage?.tokens ?? 0;
|
|
3223
|
+
if (!totalTokens || totalTokens < MIN_TOKEN_THRESHOLD) {
|
|
3224
|
+
const pct = ctx.model && totalTokens ? Math.round(totalTokens / ctx.model.contextWindow * 100) : 0;
|
|
3225
|
+
return { content: [{ type: "text", text: "Context is not large enough for compaction (" + totalTokens.toLocaleString() + " tokens, " + pct + "%). No action needed." }], details: undefined };
|
|
3226
|
+
}
|
|
3106
3227
|
const cur = "model" in ctx ? ctx.model : undefined;
|
|
3107
|
-
const { segModel, sumModel } = resolveModels(
|
|
3228
|
+
const { segModel, sumModel } = resolveModels(cmdCtx, cur, config);
|
|
3108
3229
|
if (!sumModel) {
|
|
3109
|
-
return { content: [{ type: "text", text: "Error: Could not resolve model." }] };
|
|
3230
|
+
return { content: [{ type: "text", text: "Error: Could not resolve model." }], details: undefined };
|
|
3110
3231
|
}
|
|
3111
3232
|
try {
|
|
3112
3233
|
const toolStart = Date.now();
|
|
3113
|
-
await runSmartCompact({ ctx, summaryModel: sumModel, segModel: segModel ?? sumModel, profile: resolvedProfile, verbose, dryRun, pendingRef, isRunning, autoTriggered: true, skipCompact: true });
|
|
3234
|
+
await runSmartCompact({ ctx: cmdCtx, summaryModel: sumModel, segModel: segModel ?? sumModel, profile: resolvedProfile, verbose, dryRun, pendingRef, isRunning, autoTriggered: true, skipCompact: true });
|
|
3114
3235
|
const toolSecs = ((Date.now() - toolStart) / 1000).toFixed(1);
|
|
3115
3236
|
if (pendingRef.value) {
|
|
3116
|
-
return { content: [{ type: "text", text: "Smart summary
|
|
3117
|
-
|
|
3118
|
-
Now run tree compact to apply \u2014 the session_before_compact hook will use this summary.
|
|
3119
|
-
TTL: ` + Math.round(PENDING_TTL_MS / 60000) + " minutes." }] };
|
|
3237
|
+
return { content: [{ type: "text", text: "Smart summary prepared (" + resolvedProfile + "). Tokens: " + (pendingRef.value.tokensBefore ?? 0).toLocaleString() + " \u2014 summary cached for " + Math.round(PENDING_TTL_MS / 60000) + " min. The next /compact will use this summary automatically." }], details: undefined };
|
|
3120
3238
|
}
|
|
3121
|
-
return { content: [{ type: "text", text: "Compaction finished (" + resolvedProfile + ") but no summary was generated." }] };
|
|
3239
|
+
return { content: [{ type: "text", text: "Compaction finished (" + resolvedProfile + ") but no summary was generated." }], details: undefined };
|
|
3122
3240
|
} catch (error) {
|
|
3123
3241
|
const msg = error instanceof Error ? error.message : String(error);
|
|
3124
|
-
return { content: [{ type: "text", text: "Compaction error: " + msg }] };
|
|
3242
|
+
return { content: [{ type: "text", text: "Compaction error: " + msg }], details: undefined };
|
|
3125
3243
|
}
|
|
3126
3244
|
}
|
|
3127
3245
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/ui/overlays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAC9C,mBAAmB,EAAE,oBAAoB,EAC1C,MAAM,aAAa,CAAC;AAIrB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/ui/overlays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAC9C,mBAAmB,EAAE,oBAAoB,EAC1C,MAAM,aAAa,CAAC;AAIrB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAS7F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAO5G;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA8C7B;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,aAAa,EAAE,WAAW,EAC1B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA4CpC;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAM5F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,uBAAuB,EAC5B,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,oBAAoB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsJf;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAAG,IAAI,CAAC,CAMrE"}
|
package/dist/utils/cache.d.ts
CHANGED
|
@@ -22,6 +22,17 @@ export declare function getMetricsSummary(): {
|
|
|
22
22
|
export declare function trackedComplete(phase: LLMCallMetric["phase"], model: Model<Api>, reqBody: Context, opts: CacheAwareOptions): Promise<AssistantMessage>;
|
|
23
23
|
export declare function saveCachedExtraction(sessionId: string, extraction: StructuredExtraction, msgCount: number): void;
|
|
24
24
|
export declare function loadCachedExtraction(sessionId: string): CachedExtraction | null;
|
|
25
|
+
/**
|
|
26
|
+
* Merge a delta extraction into a base extraction, offsetting all
|
|
27
|
+
* index-bearing fields so they align with the global message array.
|
|
28
|
+
*
|
|
29
|
+
* When `extractStructured` is called on `msgs.slice(cached.lastMessageIndex + 1)`
|
|
30
|
+
* the delta's indexes start at 0 in the slice — but in the full conversation
|
|
31
|
+
* they start at `baseMsgCount` (= `cached.messageCount` = `cached.lastMessageIndex + 1`).
|
|
32
|
+
*
|
|
33
|
+
* Without this offset, incremental extraction produces corrupted indexes that
|
|
34
|
+
* break timeline ordering, topic segmentation, and downstream verification.
|
|
35
|
+
*/
|
|
25
36
|
export declare function mergeExtractions(base: StructuredExtraction, delta: StructuredExtraction, baseMsgCount: number): StructuredExtraction;
|
|
26
37
|
export declare function appendMetricsLog(sessionId: string): void;
|
|
27
38
|
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG5G,OAAO,EAAY,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAO5G,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAOhH;AAKD,wBAAgB,YAAY,IAAI,IAAI,CAAyB;AAC7D,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAA4F;AAChJ,wBAAgB,UAAU,IAAI,aAAa,EAAE,CAA0B;AAEvE,wBAAgB,iBAAiB,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAYpK;AAGD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;AAQD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQhH;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ/E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG5G,OAAO,EAAY,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAO5G,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAOhH;AAKD,wBAAgB,YAAY,IAAI,IAAI,CAAyB;AAC7D,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAA4F;AAChJ,wBAAgB,UAAU,IAAI,aAAa,EAAE,CAA0B;AAEvE,wBAAgB,iBAAiB,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAYpK;AAGD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;AAQD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQhH;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,CA8BpI;AAGD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOxD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../../src/utils/extraction.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK7F,oCAAoC;AACpC,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQpD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,CAapE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG;IAAE,QAAQ,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAiC/J;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,oBAAoB,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../../src/utils/extraction.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK7F,oCAAoC;AACpC,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQpD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,CAapE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG;IAAE,QAAQ,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAiC/J;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CA4CxG;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAyB9G;AAYD,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAcvF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,SAAK,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CA8ClJ;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAc1H;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,GAAG,IAAI,CAOjE;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,GAAG,QAAQ,EAAE,CAoFjG;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,aAAa,GAAG,oBAAoB,CAgB7F"}
|
|
@@ -13,8 +13,18 @@ export interface ProjectFingerprint {
|
|
|
13
13
|
updatedAt: number;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Generate a project ID from file paths in the extraction.
|
|
17
|
-
*
|
|
16
|
+
* Generate a stable project ID from file paths in the extraction.
|
|
17
|
+
*
|
|
18
|
+
* Strategy (in priority order):
|
|
19
|
+
* 1. **Noise filtering** — exclude node_modules, .cache, .pi/agent, etc.
|
|
20
|
+
* 2. **Absolute paths** (≥ 2) — deep ancestor with majority vote
|
|
21
|
+
* 3. **Relative paths** (≥ 2) — directory structure fingerprint
|
|
22
|
+
* 4. **Fallback** — hash all paths together
|
|
23
|
+
*
|
|
24
|
+
* ⚠️ Breaking change: this replaces the previous shallow-root algorithm
|
|
25
|
+
* that caused cross-project contamination
|
|
26
|
+
* (e.g. hash("root") → proj-4813494d, hash("/Users") → proj-a2a0ee2c).
|
|
27
|
+
* Old fingerprint/state files will be orphaned and expire via TTL.
|
|
18
28
|
*/
|
|
19
29
|
export declare function deriveProjectId(extraction: StructuredExtraction): string;
|
|
20
30
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/utils/fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/utils/fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AA8ID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,oBAAoB,GAAG,MAAM,CAuBxE;AAoDD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CASnF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,IAAI,CAuBN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAQlF"}
|
package/dist/utils/helpers.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* General helpers: config, backup, batching, preprocessing.
|
|
3
3
|
*/
|
|
4
|
-
import type { CompactConfig, ChunkSummary, LlmChunk, StructuredExtraction, ExplorationReport, SessionMessageEntry } from "../types.ts";
|
|
4
|
+
import type { CompactConfig, ChunkSummary, LlmChunk, StructuredExtraction, ExplorationReport, SessionType, SessionMessageEntry } from "../types.ts";
|
|
5
5
|
export declare function loadConfig(): CompactConfig;
|
|
6
6
|
export declare function backupConversation(convText: string, sessionId: string): string | null;
|
|
7
7
|
export declare function getPreviousCompactionContext(branch: unknown[]): string;
|
|
@@ -18,5 +18,20 @@ export declare function buildExtractionContext(extraction: StructuredExtraction,
|
|
|
18
18
|
start: number;
|
|
19
19
|
end: number;
|
|
20
20
|
}): string;
|
|
21
|
+
/**
|
|
22
|
+
* Infer session type from extraction data when exploration report is absent.
|
|
23
|
+
*
|
|
24
|
+
* Previously defaulted blindly to "implementation", which caused review-only
|
|
25
|
+
* and discussion-only sessions to be summarized with the wrong prompt strategy.
|
|
26
|
+
*
|
|
27
|
+
* Heuristic priority:
|
|
28
|
+
* 1. If exploration report provides a classification → trust it
|
|
29
|
+
* 2. Active errors + code changes → debugging
|
|
30
|
+
* 3. Reads only, no modifications → review
|
|
31
|
+
* 4. Decisions but no code changes → discussion
|
|
32
|
+
* 5. Code modifications → implementation
|
|
33
|
+
* 6. Fallback → implementation (most common agent activity)
|
|
34
|
+
*/
|
|
35
|
+
export declare function inferSessionType(extraction: StructuredExtraction, report: ExplorationReport | null): SessionType;
|
|
21
36
|
export declare function buildExplorationContext(report: ExplorationReport): string;
|
|
22
37
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAsB,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA0CxK,wBAAgB,UAAU,IAAI,aAAa,CAkB1C;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUrF;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAQtE;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CA0B5F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKhE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,EAAE,CASjF;AAqCD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM;;;;;EAYnF;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAU1H;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,iBAAiB,GAAG,IAAI,GAC/B,WAAW,CAeb;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAYzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pruning.d.ts","sourceRoot":"","sources":["../../src/utils/pruning.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAQD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"pruning.d.ts","sourceRoot":"","sources":["../../src/utils/pruning.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAQD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,CAyGhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/utils/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/utils/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAe,MAAM,aAAa,CAAC;AAWnH;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAKnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAe7E;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,oBAAoB,EAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EAAE,EACrB,eAAe,EAAE,MAAM,EAAE,GACxB,eAAe,CAgDjB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAsBrF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oCAAoC;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,qBAAqB;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAmD7F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA+BjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CA2BlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-smart-compact",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.2",
|
|
4
4
|
"description": "EESV smart compaction extension for Pi Coding Agent — deterministic extraction, exploration, synthesis, verification with redundancy pruning, project fingerprinting, and damage detection.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"CHANGELOG.md"
|
|
41
41
|
],
|
|
42
42
|
"scripts": {
|
|
43
|
-
"build": "rm -rf dist && mkdir dist && bun build ./src/index.ts --outdir ./dist --target bun --external '@earendil-works/*' --external 'typebox' &&
|
|
43
|
+
"build": "rm -rf dist && mkdir dist && bun build ./src/index.ts --outdir ./dist --target bun --external '@earendil-works/*' --external 'typebox' && bunx tsc --emitDeclarationOnly --outDir dist",
|
|
44
44
|
"test": "bun test",
|
|
45
45
|
"typecheck": "bunx tsc --noEmit"
|
|
46
46
|
},
|