pi-mega-compact 0.11.4 → 0.11.5
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/dist/extensions/dashboard-server/api-contracts/endpoints.js +19 -0
- package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
- package/dist/extensions/dashboard-server/index-reader.js +6 -2
- package/dist/extensions/dashboard-server/routes-cache.js +115 -55
- package/dist/extensions/dashboard-server/routes-memory.js +51 -0
- package/dist/extensions/dashboard-server/routes-repo.js +2 -2
- package/dist/extensions/dashboard-server/routes-setup.js +162 -0
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +7 -1
- package/dist/extensions/mega-commands.js +189 -1
- package/dist/extensions/mega-config.js +2 -0
- package/dist/extensions/mega-events/agent-handlers.js +19 -4
- package/dist/extensions/mega-events/compact-handlers.js +1 -0
- package/dist/extensions/mega-events/context-handler.js +37 -92
- package/dist/extensions/mega-events/context-hwm.js +51 -0
- package/dist/extensions/mega-events/error-classifier.js +16 -5
- package/dist/extensions/mega-events/mirror-append.js +107 -0
- package/dist/extensions/mega-events/outage-advisor.js +7 -1
- package/dist/extensions/mega-events/perf-handler.js +51 -1
- package/dist/extensions/mega-events/recall-tail.js +59 -0
- package/dist/extensions/mega-events/session-handlers.js +15 -8
- package/dist/extensions/mega-runtime/reset-runtime.js +5 -0
- package/dist/extensions/mega-runtime/runtime.js +6 -0
- package/dist/src/embedder.js +41 -2
- package/dist/src/memoryStats.js +75 -0
- package/dist/src/prefix-break.js +43 -0
- package/dist/src/pricing.js +1 -1
- package/dist/src/store/sqlite/perf-samples.js +144 -16
- package/dist/src/store/turns/memory-store.js +8 -0
- package/dist/src/store/turns/sqlite-store.js +14 -3
- package/dist/src/store/turns/types.js +18 -1
- package/dist/src/store/vectorIndex.js +26 -5
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-BoL7qBOJ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-BoL7qBOJ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/AchievementsTab-BFDE3HYc.js +2 -0
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-BFDE3HYc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-DDFE-ckA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-DDFE-ckA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-B6UxZ7PM.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-B6UxZ7PM.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js → GameTab-DehUX-KE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-DehUX-KE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-0GWRt4wn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-0GWRt4wn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-C3rwMVsN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-C3rwMVsN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-39O9_x5j.js +2 -0
- package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-39O9_x5j.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-DXDTCi3r.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-DXDTCi3r.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BAw972BV.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BAw972BV.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-Cf5mGIdl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-Cf5mGIdl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
- package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{index-BX0bcgLu.js → index-4gQ7auad.js} +10 -10
- package/extensions/dashboard-client/dist/assets/index-4gQ7auad.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-DNgMuyP6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-DNgMuyP6.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/App.tsx +4 -0
- package/extensions/dashboard-client/src/api/client.ts +14 -0
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
- package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
- package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +1 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +355 -0
- package/extensions/dashboard-client/tsconfig.json +3 -2
- package/extensions/dashboard-client/vite.config.ts +2 -0
- package/extensions/dashboard-server/api-contracts/endpoints.ts +36 -3
- package/extensions/dashboard-server/api-contracts/index.ts +7 -0
- package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
- package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
- package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
- package/extensions/dashboard-server/api-contracts/setup.ts +58 -0
- package/extensions/dashboard-server/index-reader.ts +138 -121
- package/extensions/dashboard-server/routes-cache.ts +161 -85
- package/extensions/dashboard-server/routes-memory.ts +63 -0
- package/extensions/dashboard-server/routes-repo.ts +36 -36
- package/extensions/dashboard-server/routes-setup.ts +181 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +6 -0
- package/extensions/mega-commands.ts +211 -1
- package/extensions/mega-config.ts +10 -0
- package/extensions/mega-events/agent-handlers.ts +20 -4
- package/extensions/mega-events/compact-handlers.ts +1 -0
- package/extensions/mega-events/context-handler.ts +45 -110
- package/extensions/mega-events/context-hwm.ts +85 -0
- package/extensions/mega-events/error-classifier.ts +15 -4
- package/extensions/mega-events/mirror-append.ts +155 -0
- package/extensions/mega-events/outage-advisor.ts +11 -5
- package/extensions/mega-events/perf-handler.ts +79 -5
- package/extensions/mega-events/recall-tail.ts +88 -0
- package/extensions/mega-events/session-handlers.ts +14 -7
- package/extensions/mega-runtime/helpers.ts +12 -0
- package/extensions/mega-runtime/reset-runtime.ts +5 -0
- package/extensions/mega-runtime/runtime.ts +6 -0
- package/package.json +5 -2
- package/src/embedder.ts +42 -2
- package/src/memoryStats.ts +107 -0
- package/src/prefix-break.ts +83 -0
- package/src/pricing.ts +2 -2
- package/src/store/sqlite/perf-samples.ts +215 -22
- package/src/store/turns/memory-store.ts +10 -1
- package/src/store/turns/sqlite-store.ts +27 -15
- package/src/store/turns/types.ts +21 -0
- package/src/store/vectorIndex.ts +33 -4
- package/dist/extensions/conflict-scan.test.js +0 -115
- package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
- package/dist/extensions/dashboard-server/html.test.js +0 -52
- package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
- package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
- package/dist/extensions/dashboard-server/server.test.js +0 -120
- package/dist/extensions/dashboard-server-s32.test.js +0 -181
- package/dist/extensions/dashboard-server.test.js +0 -339
- package/dist/extensions/mega-cache-replay.test.js +0 -400
- package/dist/extensions/mega-compact-s38.test.js +0 -1383
- package/dist/extensions/mega-compact.test.js +0 -1112
- package/dist/extensions/mega-events.test.js +0 -47
- package/dist/extensions/mega-game-cmds.test.js +0 -163
- package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
- package/dist/extensions/mega-runtime/state.test.js +0 -266
- package/dist/extensions/mega-runtime/widget.test.js +0 -343
- package/dist/extensions/mega-shutdown-widget.test.js +0 -121
- package/dist/extensions/mega-teamrun.test.js +0 -156
- package/dist/extensions/mega-trim.test.js +0 -58
- package/dist/extensions/mega-turn-store.test.js +0 -68
- package/dist/src/boundary.test.js +0 -170
- package/dist/src/compact.test.js +0 -78
- package/dist/src/config/themes.test.js +0 -94
- package/dist/src/dedup/dedup.test.js +0 -41
- package/dist/src/dedup/l1.test.js +0 -50
- package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
- package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
- package/dist/src/dedup/raptor/multilevel.test.js +0 -238
- package/dist/src/dedup/raptor/promote.test.js +0 -69
- package/dist/src/dedup/raptor/raptor.test.js +0 -248
- package/dist/src/dedup/raptor/retrieval.test.js +0 -95
- package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
- package/dist/src/dedup/sprint12.test.js +0 -219
- package/dist/src/dedup-engine.test.js +0 -472
- package/dist/src/driftDetection.test.js +0 -87
- package/dist/src/e2e.test.js +0 -698
- package/dist/src/engine.test.js +0 -111
- package/dist/src/extractive.test.js +0 -147
- package/dist/src/fork.test.js +0 -81
- package/dist/src/game/scoring.test.js +0 -98
- package/dist/src/httpEmbedder.test.js +0 -277
- package/dist/src/importance.test.js +0 -372
- package/dist/src/intent.test.js +0 -78
- package/dist/src/log.test.js +0 -42
- package/dist/src/mechanical-fix.test.js +0 -65
- package/dist/src/memory.test.js +0 -70
- package/dist/src/memoryConsolidate.test.js +0 -38
- package/dist/src/memoryOps.test.js +0 -129
- package/dist/src/memoryRecall.test.js +0 -171
- package/dist/src/memoryRoundtrip.test.js +0 -137
- package/dist/src/metrics/turns.test.js +0 -152
- package/dist/src/mirror/mirror.test.js +0 -185
- package/dist/src/raptor-inject-summaries.test.js +0 -162
- package/dist/src/ratio.bench.test.js +0 -897
- package/dist/src/recall.integration.test.js +0 -77
- package/dist/src/recall.test.js +0 -379
- package/dist/src/sprint14.test.js +0 -219
- package/dist/src/sprint4x-rag-verification.test.js +0 -93
- package/dist/src/store/compression.test.js +0 -139
- package/dist/src/store/memoryIndex.test.js +0 -51
- package/dist/src/store/migrate.test.js +0 -139
- package/dist/src/store/pgOpenGuard.test.js +0 -74
- package/dist/src/store/phase01.test.js +0 -81
- package/dist/src/store/phase04.test.js +0 -54
- package/dist/src/store/sprint10.test.js +0 -186
- package/dist/src/store/sqlite/game-achievements.test.js +0 -67
- package/dist/src/store/sqlite/game-scores.test.js +0 -106
- package/dist/src/store/sqlite/game-state.test.js +0 -76
- package/dist/src/store/sqlite/global-index.test.js +0 -136
- package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
- package/dist/src/store/sqlite/perf-samples.test.js +0 -146
- package/dist/src/store/sqlite/raptor.test.js +0 -106
- package/dist/src/store/sqlite/turns.test.js +0 -183
- package/dist/src/store/sqlite.cachehit.test.js +0 -55
- package/dist/src/store/sqlite.dbmaint.test.js +0 -158
- package/dist/src/store/sqlite.dbmirror.test.js +0 -184
- package/dist/src/store/turns/contract-compliance.test.js +0 -428
- package/dist/src/store/turns/memory-store.test.js +0 -9
- package/dist/src/store/turns/migrations.test.js +0 -138
- package/dist/src/store/turns/sqlite-store.test.js +0 -144
- package/dist/src/store/vectorIndex.test.js +0 -123
- package/dist/src/store.test.js +0 -161
- package/dist/src/supersede.test.js +0 -36
- package/dist/src/topics/cluster.test.js +0 -150
- package/dist/src/topics/store.test.js +0 -117
- package/dist/src/types.test.js +0 -9
- package/dist/src/vector-search-cache.test.js +0 -157
- package/dist/src/vectorStore.test.js +0 -479
- package/dist/src/wiki.test.js +0 -171
- package/extensions/conflict-scan.test.ts +0 -129
- package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
- package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
- package/extensions/dashboard-server/html.test.ts +0 -62
- package/extensions/dashboard-server/perf-server.test.ts +0 -101
- package/extensions/dashboard-server/routes-cache.test.ts +0 -302
- package/extensions/dashboard-server/server.test.ts +0 -131
- package/extensions/dashboard-server-s32.test.ts +0 -195
- package/extensions/dashboard-server.test.ts +0 -382
- package/extensions/mega-cache-replay.test.ts +0 -526
- package/extensions/mega-compact-s38.test.ts +0 -1433
- package/extensions/mega-compact.test.ts +0 -1509
- package/extensions/mega-events.test.ts +0 -55
- package/extensions/mega-game-cmds.test.ts +0 -197
- package/extensions/mega-runtime/snapshot.test.ts +0 -139
- package/extensions/mega-runtime/state.test.ts +0 -262
- package/extensions/mega-runtime/widget.test.ts +0 -468
- package/extensions/mega-shutdown-widget.test.ts +0 -141
- package/extensions/mega-teamrun.test.ts +0 -176
- package/extensions/mega-trim.test.ts +0 -64
- package/extensions/mega-turn-store.test.ts +0 -108
- package/src/boundary.test.ts +0 -187
- package/src/compact.test.ts +0 -99
- package/src/config/themes.test.ts +0 -116
- package/src/dedup/dedup.test.ts +0 -46
- package/src/dedup/l1.test.ts +0 -57
- package/src/dedup/raptor/buildHistory.test.ts +0 -353
- package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
- package/src/dedup/raptor/multilevel.test.ts +0 -325
- package/src/dedup/raptor/promote.test.ts +0 -82
- package/src/dedup/raptor/raptor.test.ts +0 -297
- package/src/dedup/raptor/retrieval.test.ts +0 -118
- package/src/dedup/raptor/serve-gate.test.ts +0 -348
- package/src/dedup/sprint12.test.ts +0 -242
- package/src/dedup-engine.test.ts +0 -670
- package/src/driftDetection.test.ts +0 -100
- package/src/e2e.test.ts +0 -843
- package/src/engine.test.ts +0 -123
- package/src/extractive.test.ts +0 -174
- package/src/fork.test.ts +0 -94
- package/src/game/scoring.test.ts +0 -103
- package/src/httpEmbedder.test.ts +0 -286
- package/src/importance.test.ts +0 -538
- package/src/intent.test.ts +0 -87
- package/src/log.test.ts +0 -47
- package/src/mechanical-fix.test.ts +0 -70
- package/src/memory.test.ts +0 -92
- package/src/memoryConsolidate.test.ts +0 -47
- package/src/memoryOps.test.ts +0 -148
- package/src/memoryRecall.test.ts +0 -194
- package/src/memoryRoundtrip.test.ts +0 -155
- package/src/metrics/turns.test.ts +0 -165
- package/src/mirror/mirror.test.ts +0 -240
- package/src/raptor-inject-summaries.test.ts +0 -228
- package/src/ratio.bench.test.ts +0 -1316
- package/src/recall.integration.test.ts +0 -96
- package/src/recall.test.ts +0 -467
- package/src/sprint14.test.ts +0 -245
- package/src/sprint4x-rag-verification.test.ts +0 -119
- package/src/store/compression.test.ts +0 -168
- package/src/store/memoryIndex.test.ts +0 -61
- package/src/store/migrate.test.ts +0 -158
- package/src/store/pgOpenGuard.test.ts +0 -89
- package/src/store/phase01.test.ts +0 -88
- package/src/store/phase04.test.ts +0 -58
- package/src/store/sprint10.test.ts +0 -214
- package/src/store/sqlite/game-achievements.test.ts +0 -80
- package/src/store/sqlite/game-scores.test.ts +0 -132
- package/src/store/sqlite/game-state.test.ts +0 -89
- package/src/store/sqlite/global-index.test.ts +0 -222
- package/src/store/sqlite/mechanical-fix.test.ts +0 -162
- package/src/store/sqlite/perf-samples.test.ts +0 -169
- package/src/store/sqlite/raptor.test.ts +0 -139
- package/src/store/sqlite/turns.test.ts +0 -218
- package/src/store/sqlite.cachehit.test.ts +0 -68
- package/src/store/sqlite.dbmaint.test.ts +0 -193
- package/src/store/sqlite.dbmirror.test.ts +0 -229
- package/src/store/turns/contract-compliance.test.ts +0 -562
- package/src/store/turns/memory-store.test.ts +0 -15
- package/src/store/turns/migrations.test.ts +0 -161
- package/src/store/turns/sqlite-store.test.ts +0 -161
- package/src/store/vectorIndex.test.ts +0 -140
- package/src/store.test.ts +0 -191
- package/src/supersede.test.ts +0 -42
- package/src/topics/cluster.test.ts +0 -176
- package/src/topics/store.test.ts +0 -132
- package/src/types.test.ts +0 -10
- package/src/vector-search-cache.test.ts +0 -190
- package/src/vectorStore.test.ts +0 -533
- package/src/wiki.test.ts +0 -217
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { VectorStore } from "./vectorStore.js";
|
|
7
|
-
import { compactSession } from "./engine.js";
|
|
8
|
-
import { recallAndInline } from "./recall.js";
|
|
9
|
-
import type { EngineMessage } from "./types.js";
|
|
10
|
-
|
|
11
|
-
const baseTmp = mkdtempSync(join(tmpdir(), "mc-resume-"));
|
|
12
|
-
let counter = 0;
|
|
13
|
-
/** Two instances, SAME disk dir — simulates a fresh process / resumed session. */
|
|
14
|
-
function storeForDir(dir: string) {
|
|
15
|
-
return new VectorStore({ dedupSim: 0.9, stateDir: dir });
|
|
16
|
-
}
|
|
17
|
-
function msg(role: EngineMessage["role"], text: string, toolName?: string): EngineMessage {
|
|
18
|
-
return toolName ? { role, text, toolName, input: text, output: text } : { role, text };
|
|
19
|
-
}
|
|
20
|
-
const SESS = "sess_resume";
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Simulate the extension's `recentUserQuery`: the resume query is built from the
|
|
24
|
-
* newest user message in the (re-loaded) session. We model "newest user msg"
|
|
25
|
-
* directly rather than going through pi's session manager.
|
|
26
|
-
*/
|
|
27
|
-
function latestUserQuery(messages: EngineMessage[]): string {
|
|
28
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
29
|
-
if (messages[i].role === "user") return messages[i].text;
|
|
30
|
-
}
|
|
31
|
-
return "";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
test("resume contract: compact in one process, recall in a fresh one from disk", () => {
|
|
35
|
-
const dir = join(baseTmp, `run-${counter++}`);
|
|
36
|
-
|
|
37
|
-
// --- Process 1: the original session compacts ---
|
|
38
|
-
const writer = storeForDir(dir);
|
|
39
|
-
const session: EngineMessage[] = [
|
|
40
|
-
msg("user", "investigated src/compact.ts and added a truncate helper"),
|
|
41
|
-
msg("assistant", "added truncate", "Edit"),
|
|
42
|
-
msg("user", "then wired it into the summary pipeline"),
|
|
43
|
-
msg("assistant", "wired it in", "Edit"),
|
|
44
|
-
];
|
|
45
|
-
const ran = compactSession(
|
|
46
|
-
{ sessionId: SESS, messages: session, keepFrom: session.length, timestamp: 1 },
|
|
47
|
-
writer,
|
|
48
|
-
);
|
|
49
|
-
assert.equal(ran.skipped, false);
|
|
50
|
-
assert.ok(ran.checkpointId, "a checkpoint was persisted");
|
|
51
|
-
|
|
52
|
-
// --- Process 2: pi restarts, session resumes from disk ---
|
|
53
|
-
const reader = storeForDir(dir); // brand new instance, same dir
|
|
54
|
-
const resumeQuery = latestUserQuery(session); // newest user msg
|
|
55
|
-
const r = recallAndInline(
|
|
56
|
-
{ sessionId: SESS, query: resumeQuery, limit: 3, source: "resume" },
|
|
57
|
-
reader,
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
assert.equal(r.empty, false, "resume must re-surface the compacted context");
|
|
61
|
-
assert.equal(r.toInject.length, 1);
|
|
62
|
-
assert.equal(r.toInject[0].checkpoint.checkpointId, ran.checkpointId);
|
|
63
|
-
assert.ok(r.block.includes("Recalled context"), "block is model-visible system-prompt text");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("resume contract: nothing to recall for a brand-new session", () => {
|
|
67
|
-
const dir = join(baseTmp, `run-${counter++}`);
|
|
68
|
-
const fresh = storeForDir(dir);
|
|
69
|
-
const r = recallAndInline(
|
|
70
|
-
{ sessionId: "sess_never_seen", query: "anything at all", limit: 3, source: "resume" },
|
|
71
|
-
fresh,
|
|
72
|
-
);
|
|
73
|
-
assert.equal(r.empty, true);
|
|
74
|
-
assert.equal(r.block, "");
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("resume contract: re-inject is deduped after the first recall", () => {
|
|
78
|
-
const dir = join(baseTmp, `run-${counter++}`);
|
|
79
|
-
const writer = storeForDir(dir);
|
|
80
|
-
const session: EngineMessage[] = [
|
|
81
|
-
msg("user", "built the trigram embedder for the vector store"),
|
|
82
|
-
msg("assistant", "built it", "Edit"),
|
|
83
|
-
];
|
|
84
|
-
compactSession({ sessionId: SESS, messages: session, keepFrom: 2, timestamp: 1 }, writer);
|
|
85
|
-
|
|
86
|
-
const reader = storeForDir(dir);
|
|
87
|
-
const q = latestUserQuery(session);
|
|
88
|
-
const first = recallAndInline({ sessionId: SESS, query: q, limit: 3, source: "resume" }, reader);
|
|
89
|
-
const second = recallAndInline({ sessionId: SESS, query: q, limit: 3, source: "resume" }, reader);
|
|
90
|
-
assert.equal(first.empty, false);
|
|
91
|
-
assert.equal(second.empty, true, "second resume does not re-inject (sentinel)");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("cleanup", () => {
|
|
95
|
-
rmSync(baseTmp, { recursive: true, force: true });
|
|
96
|
-
});
|
package/src/recall.test.ts
DELETED
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { VectorStore } from "./vectorStore.js";
|
|
7
|
-
import { compactSession } from "./engine.js";
|
|
8
|
-
import { recallAndInline, recallAndInlineAsync, formatRecallBlock } from "./recall.js";
|
|
9
|
-
import { vectorList, vectorWasInjected } from "./vectorStore.js";
|
|
10
|
-
import { markInjectedGlobal, wasInjectedGlobal, closeIndexStore } from "./store/sqlite.js";
|
|
11
|
-
import {
|
|
12
|
-
closeVectorIndex,
|
|
13
|
-
initVectorIndex,
|
|
14
|
-
rebuildFromSqlite,
|
|
15
|
-
} from "./store/vectorIndex.js";
|
|
16
|
-
import type { EngineMessage } from "./types.js";
|
|
17
|
-
|
|
18
|
-
const baseTmp = mkdtempSync(join(tmpdir(), "mc-recall-"));
|
|
19
|
-
let counter = 0;
|
|
20
|
-
function store() {
|
|
21
|
-
return new VectorStore({ dedupSim: 0.9, stateDir: join(baseTmp, `run-${counter++}`) });
|
|
22
|
-
}
|
|
23
|
-
function msg(role: EngineMessage["role"], text: string, toolName?: string): EngineMessage {
|
|
24
|
-
return toolName ? { role, text, toolName, input: text, output: text } : { role, text };
|
|
25
|
-
}
|
|
26
|
-
const SESS = "sess_recall";
|
|
27
|
-
|
|
28
|
-
test("recallAndInline injects new hits and marks them injected", () => {
|
|
29
|
-
const s = store();
|
|
30
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "investigated src/vectorStore.ts embedding"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 1 }, s);
|
|
31
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "fixed the dedupe race in store.ts"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 2 }, s);
|
|
32
|
-
|
|
33
|
-
const r1 = recallAndInline({ sessionId: SESS, query: "vectorStore embedding", limit: 1, source: "command" }, s as any);
|
|
34
|
-
assert.equal(r1.empty, false);
|
|
35
|
-
assert.equal(r1.toInject.length, 1);
|
|
36
|
-
assert.ok(r1.block.includes("Recalled context"));
|
|
37
|
-
|
|
38
|
-
// Second call with the same query must NOT re-inject (shared dedup).
|
|
39
|
-
const r2 = recallAndInline({ sessionId: SESS, query: "vectorStore embedding", limit: 1, source: "command" }, s as any);
|
|
40
|
-
assert.equal(r2.empty, true);
|
|
41
|
-
assert.equal(r2.toInject.length, 0);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("recallAndInline skipInjected=false re-returns hits", () => {
|
|
45
|
-
const s = store();
|
|
46
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "configured the fast gate threshold"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 1 }, s);
|
|
47
|
-
const r1 = recallAndInline({ sessionId: SESS, query: "fast gate threshold", limit: 5, source: "resume" }, s as any);
|
|
48
|
-
const r2 = recallAndInline({ sessionId: SESS, query: "fast gate threshold", limit: 5, source: "resume", skipInjected: false }, s as any);
|
|
49
|
-
assert.equal(r1.toInject.length, 1);
|
|
50
|
-
assert.equal(r2.toInject.length, 1);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test("formatRecallBlock is empty for no hits", () => {
|
|
54
|
-
assert.equal(formatRecallBlock([]), "");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("formatRecallBlock (S17): labels a cross-repo hit with its source repo", () => {
|
|
58
|
-
const hit = {
|
|
59
|
-
checkpoint: { checkpointId: "chkpt_x", summary: "did thing Y", filesModified: ["a.ts"] },
|
|
60
|
-
score: 0.91,
|
|
61
|
-
repoId: "/home/u/rad-gateway",
|
|
62
|
-
} as any;
|
|
63
|
-
const block = formatRecallBlock([hit]);
|
|
64
|
-
assert.ok(block.includes("from repo"), "labels cross-repo source");
|
|
65
|
-
assert.ok(block.includes("rad-gateway"), "includes the repo display name");
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("formatRecallBlock (S17): omits the label for same-repo hits (no repoId)", () => {
|
|
69
|
-
const hit = {
|
|
70
|
-
checkpoint: { checkpointId: "c1", summary: "s", filesModified: [] },
|
|
71
|
-
score: 0.9,
|
|
72
|
-
} as any;
|
|
73
|
-
const block = formatRecallBlock([hit]);
|
|
74
|
-
assert.ok(!block.includes("from repo"), "no source label for same-repo hits");
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("recallAndInline empty when store has nothing for query", () => {
|
|
78
|
-
const s = store();
|
|
79
|
-
const r = recallAndInline({ sessionId: SESS, query: "no such topic exists here", limit: 5, source: "command" }, s as any);
|
|
80
|
-
assert.equal(r.empty, true);
|
|
81
|
-
assert.equal(r.block, "");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("Fix C: recallMaxTokens caps the injected block", () => {
|
|
85
|
-
const s = store();
|
|
86
|
-
// Three distinct checkpoints so we can observe the cap bite mid-stream.
|
|
87
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "alpha module wiring and bootstrap sequence"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 1 }, s);
|
|
88
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "beta module config and env resolution"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 2 }, s);
|
|
89
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "gamma module shutdown and cleanup hooks"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 3 }, s);
|
|
90
|
-
|
|
91
|
-
// A ceiling of 50 tokens fits the first checkpoint (~33 body tokens) but
|
|
92
|
-
// stops before the second (~65 cumulative) — proving the cap bites mid-stream.
|
|
93
|
-
// (F3: the cap now counts body tokens only — one preamble at format time, not
|
|
94
|
-
// N — matching the async path. The old per-hit preamble counting needed ~100.)
|
|
95
|
-
const r = recallAndInline(
|
|
96
|
-
{ sessionId: SESS, query: "module wiring config shutdown", limit: 5, source: "command", recallMaxTokens: 50, skipInjected: false },
|
|
97
|
-
s as any,
|
|
98
|
-
);
|
|
99
|
-
assert.ok(r.toInject.length >= 1, "at least one injected under the cap");
|
|
100
|
-
assert.ok(r.toInject.length < 3, "cap prevented all three from injecting");
|
|
101
|
-
assert.ok(r.block.length > 0, "block non-empty");
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("Fix C: inline dedupe drops a hit already resident in the live window", () => {
|
|
105
|
-
const s = store();
|
|
106
|
-
const resident = "alpha module wiring and bootstrap sequence";
|
|
107
|
-
compactSession({ sessionId: SESS, messages: [msg("user", resident), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 1 }, s);
|
|
108
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "omega module telemetry and tracing spans"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 2 }, s);
|
|
109
|
-
|
|
110
|
-
// Baseline: with dedupe OFF, both checkpoints are candidates.
|
|
111
|
-
const rNoDedup = recallAndInline(
|
|
112
|
-
{ sessionId: SESS, query: "module wiring telemetry", limit: 5, source: "command", skipInjected: false },
|
|
113
|
-
s as any,
|
|
114
|
-
);
|
|
115
|
-
// The live window contains the exact summary of the first checkpoint — as it
|
|
116
|
-
// would be if a prior recall already injected it. Inline dedupe must drop it
|
|
117
|
-
// (strictly fewer injected than the no-dedupe baseline).
|
|
118
|
-
const residentSummary = rNoDedup.toInject[0].checkpoint.summary;
|
|
119
|
-
const rDedup = recallAndInline(
|
|
120
|
-
{ sessionId: SESS, query: "module wiring telemetry", limit: 5, source: "command", skipInjected: false, windowDedupe: true, liveWindow: [residentSummary], dedupSim: 0.9 },
|
|
121
|
-
s as any,
|
|
122
|
-
);
|
|
123
|
-
assert.ok(rDedup.toInject.length <= rNoDedup.toInject.length, "dedupe never adds hits");
|
|
124
|
-
assert.ok(
|
|
125
|
-
rDedup.toInject.length < rNoDedup.toInject.length,
|
|
126
|
-
"inline dedupe dropped a resident hit",
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// ---- S18 cross-repo global injected-set (real-data, no mocks) ----------------
|
|
131
|
-
//
|
|
132
|
-
// Earlier versions of these tests used `as any` mock stores with canned
|
|
133
|
-
// `searchAsync` returns. That was mock data: it asserted recall's orchestration
|
|
134
|
-
// against a fake search result, not the real embed → HNSW → hydrate → inject
|
|
135
|
-
// path. Per the no-mock-data principle, both tests now seed a REAL foreign
|
|
136
|
-
// VectorStore (real checkpoint + real TrigramEmbedder embedding persisted to
|
|
137
|
-
// SQLite), rebuild the real PGlite index from it via `rebuildFromSqlite`, and
|
|
138
|
-
// run the full `recallAndInlineAsync` cross-repo path against a separate self
|
|
139
|
-
// store. The foreign checkpoint hydrates from the foreign store via its real
|
|
140
|
-
// repoId (== stateDir, per VectorStore's repoId convention).
|
|
141
|
-
|
|
142
|
-
async function seedForeignRepo(foreignStateDir: string): Promise<{ sessionId: string; checkpointId: string; summary: string }> {
|
|
143
|
-
// A real VectorStore at the foreign repo's stateDir. repoId == stateDir.
|
|
144
|
-
const foreign = new VectorStore({ stateDir: foreignStateDir, dedupSim: 0.9 });
|
|
145
|
-
const sess = "sess_foreign";
|
|
146
|
-
// Seed a real checkpoint via the real compactSession pipeline. The summary
|
|
147
|
-
// text determines the embedding; the query below must land near it.
|
|
148
|
-
const summary = "foreign repo authentication jwt token validation";
|
|
149
|
-
const result = compactSession(
|
|
150
|
-
{
|
|
151
|
-
sessionId: sess,
|
|
152
|
-
messages: [msg("user", summary), msg("assistant", "ok", "Edit")],
|
|
153
|
-
keepFrom: 2,
|
|
154
|
-
timestamp: 1,
|
|
155
|
-
},
|
|
156
|
-
foreign,
|
|
157
|
-
);
|
|
158
|
-
return { sessionId: sess, checkpointId: result.checkpointId ?? "", summary };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
test("S18: global injected-set skips a foreign checkpoint already injected machine-wide", async () => {
|
|
162
|
-
if (process.env.MEGACOMPACT_PGLITE_DISABLED === "true") { return; } // skip when WASM index is off
|
|
163
|
-
const indexDir = mkdtempSync(join(tmpdir(), "mc-gi-"));
|
|
164
|
-
const foreignStateDir = mkdtempSync(join(tmpdir(), "mc-gi-foreign-"));
|
|
165
|
-
const selfStateDir = mkdtempSync(join(tmpdir(), "mc-gi-self-"));
|
|
166
|
-
process.env.MEGACOMPACT_VECTOR_INDEX_DIR = mkdtempSync(join(tmpdir(), "mc-gi-vidx-"));
|
|
167
|
-
try {
|
|
168
|
-
await closeVectorIndex(); // fresh singleton per this index dir
|
|
169
|
-
const seed = await seedForeignRepo(foreignStateDir);
|
|
170
|
-
// Populate the real PGlite index from the foreign store's real checkpoints.
|
|
171
|
-
await rebuildFromSqlite(
|
|
172
|
-
() => [{ repoId: foreignStateDir, stateDir: foreignStateDir }],
|
|
173
|
-
(sd) => {
|
|
174
|
-
// readCheckpoints: yield (sessionId, checkpointId, embedding) for every
|
|
175
|
-
// real checkpoint in this store. Mirrors the production enumerator.
|
|
176
|
-
const store = new VectorStore({ stateDir: sd, dedupSim: 0.9 });
|
|
177
|
-
return vectorList(store, seed.sessionId).map((cp) => ({
|
|
178
|
-
sessionId: seed.sessionId,
|
|
179
|
-
checkpointId: cp.checkpointId,
|
|
180
|
-
embedding: cp.embedding,
|
|
181
|
-
}));
|
|
182
|
-
},
|
|
183
|
-
);
|
|
184
|
-
const pg = await initVectorIndex();
|
|
185
|
-
assert.ok(pg, "PGlite index should initialize (WASM available)");
|
|
186
|
-
|
|
187
|
-
const sess = "sess_cross";
|
|
188
|
-
// Pre-mark the foreign checkpoint as already injected machine-wide.
|
|
189
|
-
markInjectedGlobal(seed.checkpointId, foreignStateDir, sess, indexDir);
|
|
190
|
-
assert.equal(wasInjectedGlobal(seed.checkpointId, sess, indexDir), true);
|
|
191
|
-
|
|
192
|
-
// Self store (different repo) — the cross-repo query runs against the index.
|
|
193
|
-
const selfStore = new VectorStore({ stateDir: selfStateDir, dedupSim: 0.9 });
|
|
194
|
-
const r = await recallAndInlineAsync(
|
|
195
|
-
{ sessionId: sess, query: "foreign repo authentication jwt", limit: 3, source: "command", crossRepo: true, globalIndexDir: indexDir },
|
|
196
|
-
selfStore,
|
|
197
|
-
);
|
|
198
|
-
assert.equal(r.toInject.length, 0, "globally-injected foreign checkpoint skipped");
|
|
199
|
-
} finally {
|
|
200
|
-
await closeVectorIndex();
|
|
201
|
-
closeIndexStore();
|
|
202
|
-
delete process.env.MEGACOMPACT_VECTOR_INDEX_DIR;
|
|
203
|
-
rmSync(indexDir, { recursive: true, force: true });
|
|
204
|
-
rmSync(foreignStateDir, { recursive: true, force: true });
|
|
205
|
-
rmSync(selfStateDir, { recursive: true, force: true });
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
test("S18: a fresh foreign checkpoint is injected AND recorded globally", async () => {
|
|
210
|
-
if (process.env.MEGACOMPACT_PGLITE_DISABLED === "true") { return; } // skip when WASM index is off
|
|
211
|
-
const indexDir = mkdtempSync(join(tmpdir(), "mc-gi2-"));
|
|
212
|
-
const foreignStateDir = mkdtempSync(join(tmpdir(), "mc-gi2-foreign-"));
|
|
213
|
-
const selfStateDir = mkdtempSync(join(tmpdir(), "mc-gi2-self-"));
|
|
214
|
-
process.env.MEGACOMPACT_VECTOR_INDEX_DIR = mkdtempSync(join(tmpdir(), "mc-gi2-vidx-"));
|
|
215
|
-
try {
|
|
216
|
-
await closeVectorIndex(); // fresh singleton per this index dir
|
|
217
|
-
const seed = await seedForeignRepo(foreignStateDir);
|
|
218
|
-
assert.equal(wasInjectedGlobal(seed.checkpointId, "sess_fresh", indexDir), false);
|
|
219
|
-
await rebuildFromSqlite(
|
|
220
|
-
() => [{ repoId: foreignStateDir, stateDir: foreignStateDir }],
|
|
221
|
-
(sd) => {
|
|
222
|
-
const store = new VectorStore({ stateDir: sd, dedupSim: 0.9 });
|
|
223
|
-
return vectorList(store, seed.sessionId).map((cp) => ({
|
|
224
|
-
sessionId: seed.sessionId,
|
|
225
|
-
checkpointId: cp.checkpointId,
|
|
226
|
-
embedding: cp.embedding,
|
|
227
|
-
}));
|
|
228
|
-
},
|
|
229
|
-
);
|
|
230
|
-
const pg = await initVectorIndex();
|
|
231
|
-
assert.ok(pg, "PGlite index should initialize (WASM available)");
|
|
232
|
-
|
|
233
|
-
const sess = "sess_fresh";
|
|
234
|
-
const selfStore = new VectorStore({ stateDir: selfStateDir, dedupSim: 0.9 });
|
|
235
|
-
const r = await recallAndInlineAsync(
|
|
236
|
-
{ sessionId: sess, query: "foreign repo authentication jwt", limit: 3, source: "command", crossRepo: true, globalIndexDir: indexDir },
|
|
237
|
-
selfStore,
|
|
238
|
-
);
|
|
239
|
-
assert.equal(r.toInject.length, 1, "fresh foreign checkpoint injected");
|
|
240
|
-
assert.equal(wasInjectedGlobal(seed.checkpointId, sess, indexDir), true, "recorded machine-wide");
|
|
241
|
-
} finally {
|
|
242
|
-
await closeVectorIndex();
|
|
243
|
-
closeIndexStore();
|
|
244
|
-
delete process.env.MEGACOMPACT_VECTOR_INDEX_DIR;
|
|
245
|
-
rmSync(indexDir, { recursive: true, force: true });
|
|
246
|
-
rmSync(foreignStateDir, { recursive: true, force: true });
|
|
247
|
-
rmSync(selfStateDir, { recursive: true, force: true });
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// ---- F3: format-once — one preamble, [1..n] numbering, cap respected ----
|
|
252
|
-
//
|
|
253
|
-
// The fix (landed async, extended to sync here) accumulates the hit list and
|
|
254
|
-
// calls formatRecallBlock ONCE at the end, so a multi-hit block carries exactly
|
|
255
|
-
// one preamble and contiguous [1..n] labels instead of one preamble per hit.
|
|
256
|
-
|
|
257
|
-
test("F3 (sync): multi-hit injection has exactly one preamble and [1..n] numbering", () => {
|
|
258
|
-
const s = store();
|
|
259
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "alpha module wiring and bootstrap sequence"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 1 }, s);
|
|
260
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "beta module config and env resolution"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 2 }, s);
|
|
261
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "gamma module shutdown and cleanup hooks"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 3 }, s);
|
|
262
|
-
|
|
263
|
-
const r = recallAndInline(
|
|
264
|
-
{ sessionId: SESS, query: "module wiring config shutdown", limit: 5, source: "command", skipInjected: false },
|
|
265
|
-
s as any,
|
|
266
|
-
);
|
|
267
|
-
assert.ok(r.toInject.length >= 2, "at least two hits injected (got " + r.toInject.length + ")");
|
|
268
|
-
// Exactly one preamble (the old per-hit format produced one per hit).
|
|
269
|
-
const preamble = "The following compacted context was recalled";
|
|
270
|
-
assert.equal(r.block.split(preamble).length - 1, 1, "exactly one preamble for a multi-hit block");
|
|
271
|
-
// Contiguous [1..n] numbering.
|
|
272
|
-
for (let i = 1; i <= r.toInject.length; i++) {
|
|
273
|
-
assert.ok(r.block.includes(`[${i}]`), `block includes [${i}]`);
|
|
274
|
-
}
|
|
275
|
-
// No out-of-range label (e.g. [n+1]) leaks in.
|
|
276
|
-
assert.ok(!r.block.includes(`[${r.toInject.length + 1}]`), "no extra-numbered label");
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
test("F3 (sync): recallMaxTokens caps mid-stream with exactly one preamble", () => {
|
|
280
|
-
const s = store();
|
|
281
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "alpha module wiring and bootstrap sequence"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 1 }, s);
|
|
282
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "beta module config and env resolution"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 2 }, s);
|
|
283
|
-
compactSession({ sessionId: SESS, messages: [msg("user", "gamma module shutdown and cleanup hooks"), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: 3 }, s);
|
|
284
|
-
|
|
285
|
-
// A tight ceiling that fits the first checkpoint (~33 body tokens) but stops
|
|
286
|
-
// before the second (~65 cumulative). F3: body-only counting (one preamble at
|
|
287
|
-
// format time, not per hit), matching the async path.
|
|
288
|
-
const r = recallAndInline(
|
|
289
|
-
{ sessionId: SESS, query: "module wiring config shutdown", limit: 5, source: "command", skipInjected: false, recallMaxTokens: 50 },
|
|
290
|
-
s as any,
|
|
291
|
-
);
|
|
292
|
-
assert.ok(r.toInject.length < 3, "cap stopped before all three injected");
|
|
293
|
-
assert.ok(r.toInject.length >= 1, "at least one injected under the cap");
|
|
294
|
-
assert.equal(
|
|
295
|
-
r.block.split("The following compacted context was recalled").length - 1,
|
|
296
|
-
1,
|
|
297
|
-
"still exactly one preamble under the cap",
|
|
298
|
-
);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
test("F3 (async): multi-hit cross-repo injection has exactly one preamble and [1..n] numbering", async () => {
|
|
302
|
-
if (process.env.MEGACOMPACT_PGLITE_DISABLED === "true") { return; } // skip when WASM index is off
|
|
303
|
-
const indexDir = mkdtempSync(join(tmpdir(), "mc-f3a-"));
|
|
304
|
-
const foreignStateDir = mkdtempSync(join(tmpdir(), "mc-f3a-foreign-"));
|
|
305
|
-
const selfStateDir = mkdtempSync(join(tmpdir(), "mc-f3a-self-"));
|
|
306
|
-
process.env.MEGACOMPACT_VECTOR_INDEX_DIR = mkdtempSync(join(tmpdir(), "mc-f3a-vidx-"));
|
|
307
|
-
try {
|
|
308
|
-
await closeVectorIndex();
|
|
309
|
-
// Seed multiple distinct foreign checkpoints so the cross-repo query yields
|
|
310
|
-
// more than one hit (needed to assert [1..n] numbering).
|
|
311
|
-
const foreign = new VectorStore({ stateDir: foreignStateDir, dedupSim: 0.9 });
|
|
312
|
-
const fsess = "sess_foreign_f3";
|
|
313
|
-
const summaries = [
|
|
314
|
-
"foreign repo authentication jwt token validation",
|
|
315
|
-
"foreign repo database connection pooling and retry",
|
|
316
|
-
"foreign repo logging telemetry and tracing spans",
|
|
317
|
-
];
|
|
318
|
-
const cids: string[] = [];
|
|
319
|
-
for (let i = 0; i < summaries.length; i++) {
|
|
320
|
-
const res = compactSession(
|
|
321
|
-
{ sessionId: fsess, messages: [msg("user", summaries[i]), msg("assistant", "ok", "Edit")], keepFrom: 2, timestamp: i + 1 },
|
|
322
|
-
foreign,
|
|
323
|
-
);
|
|
324
|
-
if (res.checkpointId) cids.push(res.checkpointId);
|
|
325
|
-
}
|
|
326
|
-
await rebuildFromSqlite(
|
|
327
|
-
() => [{ repoId: foreignStateDir, stateDir: foreignStateDir }],
|
|
328
|
-
(sd) => {
|
|
329
|
-
const st = new VectorStore({ stateDir: sd, dedupSim: 0.9 });
|
|
330
|
-
return vectorList(st, fsess).map((cp) => ({
|
|
331
|
-
sessionId: fsess, checkpointId: cp.checkpointId, embedding: cp.embedding,
|
|
332
|
-
}));
|
|
333
|
-
},
|
|
334
|
-
);
|
|
335
|
-
const pg = await initVectorIndex();
|
|
336
|
-
assert.ok(pg, "PGlite index should initialize");
|
|
337
|
-
|
|
338
|
-
const selfStore = new VectorStore({ stateDir: selfStateDir, dedupSim: 0.9 });
|
|
339
|
-
const r = await recallAndInlineAsync(
|
|
340
|
-
{ sessionId: "sess_f3", query: "foreign repo", limit: 5, source: "command", crossRepo: true, skipInjected: false, globalIndexDir: indexDir },
|
|
341
|
-
selfStore,
|
|
342
|
-
);
|
|
343
|
-
assert.ok(r.toInject.length >= 2, "at least two cross-repo hits (got " + r.toInject.length + ")");
|
|
344
|
-
assert.equal(
|
|
345
|
-
r.block.split("The following compacted context was recalled").length - 1,
|
|
346
|
-
1,
|
|
347
|
-
"exactly one preamble for a multi-hit async block",
|
|
348
|
-
);
|
|
349
|
-
for (let i = 1; i <= r.toInject.length; i++) {
|
|
350
|
-
assert.ok(r.block.includes(`[${i}]`), `async block includes [${i}]`);
|
|
351
|
-
}
|
|
352
|
-
assert.ok(!r.block.includes(`[${r.toInject.length + 1}]`), "no extra-numbered label (async)");
|
|
353
|
-
} finally {
|
|
354
|
-
await closeVectorIndex();
|
|
355
|
-
closeIndexStore();
|
|
356
|
-
delete process.env.MEGACOMPACT_VECTOR_INDEX_DIR;
|
|
357
|
-
rmSync(indexDir, { recursive: true, force: true });
|
|
358
|
-
rmSync(foreignStateDir, { recursive: true, force: true });
|
|
359
|
-
rmSync(selfStateDir, { recursive: true, force: true });
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
// ---- F2: cross-repo injected-set bypass ----------------------------------
|
|
364
|
-
//
|
|
365
|
-
// When the same session resumes in a DIFFERENT repo, the per-repo session_state
|
|
366
|
-
// has no injection marker for the foreign checkpoint (different stateDir), so
|
|
367
|
-
// only the machine-wide injected-set (shared globalIndexDir) can block a
|
|
368
|
-
// re-inject. The F2 fix ensures globalIndexDir is always resolved (via
|
|
369
|
-
// getIndexDir in the extension), so wasInjectedGlobal is consulted; without
|
|
370
|
-
// the fix, globalIndexDir was undefined and foreign checkpoints re-injected
|
|
371
|
-
// every resume. This test passes globalIndexDir explicitly (simulating the
|
|
372
|
-
// resolver default) and does NOT set MEGACOMPACT_INDEX_DIR.
|
|
373
|
-
|
|
374
|
-
test("F2: cross-repo hit is not re-injected when resuming the same session in a different repo (shared index dir)", async () => {
|
|
375
|
-
if (process.env.MEGACOMPACT_PGLITE_DISABLED === "true") { return; } // skip when WASM index is off
|
|
376
|
-
const indexDir = mkdtempSync(join(tmpdir(), "mc-f2-"));
|
|
377
|
-
const foreignStateDir = mkdtempSync(join(tmpdir(), "mc-f2-foreign-"));
|
|
378
|
-
const selfStateDir1 = mkdtempSync(join(tmpdir(), "mc-f2-self1-"));
|
|
379
|
-
const selfStateDir2 = mkdtempSync(join(tmpdir(), "mc-f2-self2-"));
|
|
380
|
-
process.env.MEGACOMPACT_VECTOR_INDEX_DIR = mkdtempSync(join(tmpdir(), "mc-f2-vidx-"));
|
|
381
|
-
try {
|
|
382
|
-
await closeVectorIndex();
|
|
383
|
-
const seed = await seedForeignRepo(foreignStateDir);
|
|
384
|
-
await rebuildFromSqlite(
|
|
385
|
-
() => [{ repoId: foreignStateDir, stateDir: foreignStateDir }],
|
|
386
|
-
(sd) => {
|
|
387
|
-
const st = new VectorStore({ stateDir: sd, dedupSim: 0.9 });
|
|
388
|
-
return vectorList(st, seed.sessionId).map((cp) => ({
|
|
389
|
-
sessionId: seed.sessionId, checkpointId: cp.checkpointId, embedding: cp.embedding,
|
|
390
|
-
}));
|
|
391
|
-
},
|
|
392
|
-
);
|
|
393
|
-
const pg = await initVectorIndex();
|
|
394
|
-
assert.ok(pg, "PGlite index should initialize");
|
|
395
|
-
|
|
396
|
-
const sess = "sess_resume";
|
|
397
|
-
// Repo B: first recall — fresh foreign checkpoint is injected AND recorded
|
|
398
|
-
// in the shared machine-wide index.
|
|
399
|
-
const storeB = new VectorStore({ stateDir: selfStateDir1, dedupSim: 0.9 });
|
|
400
|
-
const r1 = await recallAndInlineAsync(
|
|
401
|
-
{ sessionId: sess, query: "foreign repo authentication jwt", limit: 3, source: "command", crossRepo: true, globalIndexDir: indexDir },
|
|
402
|
-
storeB,
|
|
403
|
-
);
|
|
404
|
-
assert.equal(r1.toInject.length, 1, "first recall (repo B) injects the foreign checkpoint");
|
|
405
|
-
assert.equal(wasInjectedGlobal(seed.checkpointId, sess, indexDir), true, "recorded in the shared index");
|
|
406
|
-
|
|
407
|
-
// Repo C: SAME session resumed in a DIFFERENT repo. The per-session injected
|
|
408
|
-
// set in repo C's store is empty (different stateDir), so only the shared
|
|
409
|
-
// global injected-set can block re-injection.
|
|
410
|
-
const storeC = new VectorStore({ stateDir: selfStateDir2, dedupSim: 0.9 });
|
|
411
|
-
assert.equal(vectorWasInjected(storeC, sess, seed.checkpointId), false, "repo C per-session set is empty (different stateDir)");
|
|
412
|
-
const r2 = await recallAndInlineAsync(
|
|
413
|
-
{ sessionId: sess, query: "foreign repo authentication jwt", limit: 3, source: "command", crossRepo: true, globalIndexDir: indexDir },
|
|
414
|
-
storeC,
|
|
415
|
-
);
|
|
416
|
-
assert.equal(r2.toInject.length, 0, "second recall (repo C) does NOT re-inject (machine-wide global dedup)");
|
|
417
|
-
} finally {
|
|
418
|
-
await closeVectorIndex();
|
|
419
|
-
closeIndexStore();
|
|
420
|
-
delete process.env.MEGACOMPACT_VECTOR_INDEX_DIR;
|
|
421
|
-
rmSync(indexDir, { recursive: true, force: true });
|
|
422
|
-
rmSync(foreignStateDir, { recursive: true, force: true });
|
|
423
|
-
rmSync(selfStateDir1, { recursive: true, force: true });
|
|
424
|
-
rmSync(selfStateDir2, { recursive: true, force: true });
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
test("F2: without globalIndexDir, cross-repo hits are skipped (not injected undeduped)", async () => {
|
|
429
|
-
if (process.env.MEGACOMPACT_PGLITE_DISABLED === "true") { return; } // skip when WASM index is off
|
|
430
|
-
const foreignStateDir = mkdtempSync(join(tmpdir(), "mc-f2b-foreign-"));
|
|
431
|
-
const selfStateDir = mkdtempSync(join(tmpdir(), "mc-f2b-self-"));
|
|
432
|
-
process.env.MEGACOMPACT_VECTOR_INDEX_DIR = mkdtempSync(join(tmpdir(), "mc-f2b-vidx-"));
|
|
433
|
-
try {
|
|
434
|
-
await closeVectorIndex();
|
|
435
|
-
const seed = await seedForeignRepo(foreignStateDir);
|
|
436
|
-
await rebuildFromSqlite(
|
|
437
|
-
() => [{ repoId: foreignStateDir, stateDir: foreignStateDir }],
|
|
438
|
-
(sd) => {
|
|
439
|
-
const st = new VectorStore({ stateDir: sd, dedupSim: 0.9 });
|
|
440
|
-
return vectorList(st, seed.sessionId).map((cp) => ({
|
|
441
|
-
sessionId: seed.sessionId, checkpointId: cp.checkpointId, embedding: cp.embedding,
|
|
442
|
-
}));
|
|
443
|
-
},
|
|
444
|
-
);
|
|
445
|
-
const pg = await initVectorIndex();
|
|
446
|
-
assert.ok(pg, "PGlite index should initialize");
|
|
447
|
-
|
|
448
|
-
// No globalIndexDir → the F2 guard skips foreign hits rather than injecting
|
|
449
|
-
// them undeduped. Same-repo hits (none here) would still pass.
|
|
450
|
-
const selfStore = new VectorStore({ stateDir: selfStateDir, dedupSim: 0.9 });
|
|
451
|
-
const r = await recallAndInlineAsync(
|
|
452
|
-
{ sessionId: "sess_nodir", query: "foreign repo authentication jwt", limit: 3, source: "command", crossRepo: true },
|
|
453
|
-
selfStore,
|
|
454
|
-
);
|
|
455
|
-
assert.equal(r.toInject.length, 0, "foreign hit skipped when globalIndexDir is unset (no undeduped injection)");
|
|
456
|
-
} finally {
|
|
457
|
-
await closeVectorIndex();
|
|
458
|
-
closeIndexStore();
|
|
459
|
-
delete process.env.MEGACOMPACT_VECTOR_INDEX_DIR;
|
|
460
|
-
rmSync(foreignStateDir, { recursive: true, force: true });
|
|
461
|
-
rmSync(selfStateDir, { recursive: true, force: true });
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
test("cleanup", () => {
|
|
466
|
-
rmSync(baseTmp, { recursive: true, force: true });
|
|
467
|
-
});
|