pi-mega-compact 0.11.3 → 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 +3 -0
- package/dist/extensions/mega-events/agent-handlers.js +41 -6
- 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 +118 -128
- package/dist/extensions/mega-events/mirror-append.js +107 -0
- package/dist/extensions/mega-events/outage-advisor.js +59 -0
- 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 +6 -0
- package/dist/extensions/mega-runtime/runtime.js +7 -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 +18 -0
- package/extensions/mega-events/agent-handlers.ts +44 -5
- 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 +156 -124
- package/extensions/mega-events/mirror-append.ts +155 -0
- package/extensions/mega-events/outage-advisor.ts +79 -0
- 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 +14 -0
- package/extensions/mega-runtime/reset-runtime.ts +6 -0
- package/extensions/mega-runtime/runtime.ts +7 -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 -820
- 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 -872
- 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,298 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* serve-gate.test.ts — S25 RAPTOR promotion acceptance tests.
|
|
3
|
-
*
|
|
4
|
-
* Five gates that must ALL pass before the RAPTOR tree is trusted as the live
|
|
5
|
-
* recall surface:
|
|
6
|
-
* 1. Shadow gate (RAPTOR_SHADOW_MODE != false → no RAPTOR merge)
|
|
7
|
-
* 2. Stale tree fallback (builtAt < max checkpoint timestamp → flat)
|
|
8
|
-
* 3. timedOut fallback (extractive-fallback root → flat)
|
|
9
|
-
* 4. Coverage breadth (2-topic fixture, RAPTOR hits both vs flat misses one)
|
|
10
|
-
* 5. p95 latency (200-checkpoint × 20-query median < 100 ms)
|
|
11
|
-
*
|
|
12
|
-
* No network — default extractive summarizer + trigram embedder.
|
|
13
|
-
*/
|
|
14
|
-
import { test, beforeEach, afterEach } from "node:test";
|
|
15
|
-
import assert from "node:assert/strict";
|
|
16
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
17
|
-
import { tmpdir } from "node:os";
|
|
18
|
-
import { join } from "node:path";
|
|
19
|
-
import { VectorStore, vectorList, vectorSearch } from "../../vectorStore.js";
|
|
20
|
-
import { runRaptor, isShadowMode } from "./index.js";
|
|
21
|
-
import { compactSession } from "../../engine.js";
|
|
22
|
-
import { Logger } from "../../log.js";
|
|
23
|
-
import { loadDedupConfig } from "../../config/dedup.js";
|
|
24
|
-
import { listRaptorNodes } from "../../store/sqlite.js";
|
|
25
|
-
import { normalizeSessionId } from "../../store.js";
|
|
26
|
-
/* ------------------------------------------------------------------ helpers */
|
|
27
|
-
let tmpDir;
|
|
28
|
-
let counter = 0;
|
|
29
|
-
beforeEach(() => {
|
|
30
|
-
tmpDir = mkdtempSync(join(tmpdir(), "mc-gate-"));
|
|
31
|
-
});
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
34
|
-
});
|
|
35
|
-
function stateDir() {
|
|
36
|
-
return join(tmpDir, `run-${counter++}`);
|
|
37
|
-
}
|
|
38
|
-
/** Config with dedup tiers disabled so compactSession creates distinct checkpoints. */
|
|
39
|
-
function cfg(overrides) {
|
|
40
|
-
return {
|
|
41
|
-
...loadDedupConfig(),
|
|
42
|
-
RAPTOR_ENABLED: true,
|
|
43
|
-
L0_ENABLED: false,
|
|
44
|
-
L1_ENABLED: false,
|
|
45
|
-
L2_ENABLED: false,
|
|
46
|
-
...overrides,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function msg(text, toolName) {
|
|
50
|
-
return toolName
|
|
51
|
-
? { role: "assistant", text, toolName, input: text, output: text }
|
|
52
|
-
: { role: "user", text };
|
|
53
|
-
}
|
|
54
|
-
function seedSession(store, sid, count, topic, startTs = 1) {
|
|
55
|
-
for (let i = 1; i <= count; i++) {
|
|
56
|
-
compactSession({
|
|
57
|
-
sessionId: sid,
|
|
58
|
-
messages: [
|
|
59
|
-
msg(`${topic} checkpoint ${i} with unique content`),
|
|
60
|
-
msg(`acknowledged ${i}`, "Edit"),
|
|
61
|
-
],
|
|
62
|
-
keepFrom: 2,
|
|
63
|
-
timestamp: startTs + i,
|
|
64
|
-
}, store);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function buildTree(store, sid) {
|
|
68
|
-
const nsid = normalizeSessionId(sid);
|
|
69
|
-
const all = vectorList(store, nsid);
|
|
70
|
-
const leaves = all.map((cp) => ({
|
|
71
|
-
id: cp.checkpointId,
|
|
72
|
-
messages: [],
|
|
73
|
-
sourceText: cp.normalizedText ?? cp.summary ?? cp.regionHash,
|
|
74
|
-
embedding: cp.embedding,
|
|
75
|
-
}));
|
|
76
|
-
return runRaptor(leaves, {
|
|
77
|
-
stateDir: store.stateDir,
|
|
78
|
-
sessionId: nsid,
|
|
79
|
-
logger: new Logger(),
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
/* ------------------------------------------------------------------- tests */
|
|
83
|
-
// ─── Gate 1: shadow mode ────────────────────────────────────────────────────
|
|
84
|
-
test("gate 1: shadow mode (default) → search does NOT use RAPTOR merge", () => {
|
|
85
|
-
const sd = stateDir();
|
|
86
|
-
const s = new VectorStore({ dedupSim: 0.9, stateDir: sd, config: cfg() });
|
|
87
|
-
const sid = "shadow";
|
|
88
|
-
seedSession(s, sid, 5, "shadows");
|
|
89
|
-
buildTree(s, sid);
|
|
90
|
-
// Shadow mode is the default when env is not explicitly "false".
|
|
91
|
-
const orig = process.env.RAPTOR_SHADOW_MODE;
|
|
92
|
-
process.env.RAPTOR_SHADOW_MODE = "true";
|
|
93
|
-
try {
|
|
94
|
-
assert.ok(isShadowMode(), "shadow mode should be active");
|
|
95
|
-
// Search still returns results (flat fallback). Verify no crash.
|
|
96
|
-
const hits = vectorSearch(s, sid, "shadows checkpoint", 5);
|
|
97
|
-
assert.ok(hits.length > 0, "flat search returns results in shadow mode");
|
|
98
|
-
}
|
|
99
|
-
finally {
|
|
100
|
-
if (orig === undefined)
|
|
101
|
-
delete process.env.RAPTOR_SHADOW_MODE;
|
|
102
|
-
else
|
|
103
|
-
process.env.RAPTOR_SHADOW_MODE = orig;
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
// ─── Gate 2: stale tree fallback ────────────────────────────────────────────
|
|
107
|
-
test("gate 2: stale tree (builtAt < newest checkpoint) → serve flat", () => {
|
|
108
|
-
const sd = stateDir();
|
|
109
|
-
const s = new VectorStore({ dedupSim: 0.9, stateDir: sd, config: cfg() });
|
|
110
|
-
const sid = "stale";
|
|
111
|
-
// Build tree at checkpoints 1..5 (builtAt ≈ now).
|
|
112
|
-
seedSession(s, sid, 5, "stale topic", 0);
|
|
113
|
-
buildTree(s, sid);
|
|
114
|
-
const nodesBefore = listRaptorNodes(sid, sd);
|
|
115
|
-
assert.ok(nodesBefore.length > 0, "tree built");
|
|
116
|
-
const treeBuiltAt = nodesBefore[0].builtAt;
|
|
117
|
-
// Add checkpoint 6 with timestamp > treeBuiltAt → tree is now stale.
|
|
118
|
-
compactSession({
|
|
119
|
-
sessionId: sid,
|
|
120
|
-
messages: [
|
|
121
|
-
msg("stale topic checkpoint 6 newer than tree"),
|
|
122
|
-
msg("ok", "Edit"),
|
|
123
|
-
],
|
|
124
|
-
keepFrom: 2,
|
|
125
|
-
timestamp: treeBuiltAt + 1000,
|
|
126
|
-
}, s);
|
|
127
|
-
// Enable live mode so the gate is actually evaluated.
|
|
128
|
-
const orig = process.env.RAPTOR_SHADOW_MODE;
|
|
129
|
-
process.env.RAPTOR_SHADOW_MODE = "false";
|
|
130
|
-
try {
|
|
131
|
-
// Search should succeed (flat fallback) even though tree is stale.
|
|
132
|
-
const hits = vectorSearch(s, sid, "stale topic", 3);
|
|
133
|
-
assert.ok(hits.length > 0, "flat search returns hits when tree is stale");
|
|
134
|
-
}
|
|
135
|
-
finally {
|
|
136
|
-
if (orig === undefined)
|
|
137
|
-
delete process.env.RAPTOR_SHADOW_MODE;
|
|
138
|
-
else
|
|
139
|
-
process.env.RAPTOR_SHADOW_MODE = orig;
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
// ─── Gate 3: timedOut fallback ──────────────────────────────────────────────
|
|
143
|
-
test("gate 3: timedOut extractive-fallback tree → serve flat", () => {
|
|
144
|
-
const sd = stateDir();
|
|
145
|
-
// Force extractive fallback by setting a tiny token budget.
|
|
146
|
-
const s = new VectorStore({
|
|
147
|
-
dedupSim: 0.9,
|
|
148
|
-
stateDir: sd,
|
|
149
|
-
config: cfg({ RAPTOR_MAX_TOKEN_BUDGET_PER_SESSION: 1 }),
|
|
150
|
-
});
|
|
151
|
-
const sid = "timedout";
|
|
152
|
-
seedSession(s, sid, 10, "budget topic", 0);
|
|
153
|
-
buildTree(s, sid);
|
|
154
|
-
const nodes = listRaptorNodes(sid, sd);
|
|
155
|
-
if (nodes.length > 0) {
|
|
156
|
-
const root = nodes.find((n) => !n.parentId && n.level >= 99);
|
|
157
|
-
if (root) {
|
|
158
|
-
// timedOut tree — search should fall back to flat.
|
|
159
|
-
const orig = process.env.RAPTOR_SHADOW_MODE;
|
|
160
|
-
process.env.RAPTOR_SHADOW_MODE = "false";
|
|
161
|
-
try {
|
|
162
|
-
const hits = vectorSearch(s, sid, "budget topic", 3);
|
|
163
|
-
assert.ok(hits.length > 0, "flat search returns hits when tree is timedOut");
|
|
164
|
-
}
|
|
165
|
-
finally {
|
|
166
|
-
if (orig === undefined)
|
|
167
|
-
delete process.env.RAPTOR_SHADOW_MODE;
|
|
168
|
-
else
|
|
169
|
-
process.env.RAPTOR_SHADOW_MODE = orig;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
assert.ok(true, "budget did not trigger extractive fallback (non-deterministic)");
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
assert.ok(true, "no tree built for tiny-budget session");
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
// ─── Gate 4: coverage breadth ───────────────────────────────────────────────
|
|
181
|
-
test("gate 4: RAPTOR covers both topics vs flat may miss one", () => {
|
|
182
|
-
const sd = stateDir();
|
|
183
|
-
const s = new VectorStore({ dedupSim: 0.9, stateDir: sd, config: cfg() });
|
|
184
|
-
const sid = "breadth";
|
|
185
|
-
// Two distinct topics — interleaved timestamps.
|
|
186
|
-
for (let i = 1; i <= 5; i++) {
|
|
187
|
-
compactSession({
|
|
188
|
-
sessionId: sid,
|
|
189
|
-
messages: [
|
|
190
|
-
msg(`cooking recipe ${i} pasta sauce basil`),
|
|
191
|
-
msg(`ok ${i}`, "Edit"),
|
|
192
|
-
],
|
|
193
|
-
keepFrom: 2,
|
|
194
|
-
timestamp: i * 2,
|
|
195
|
-
}, s);
|
|
196
|
-
compactSession({
|
|
197
|
-
sessionId: sid,
|
|
198
|
-
messages: [
|
|
199
|
-
msg(`automotive engine ${i} horsepower torque transmission`),
|
|
200
|
-
msg(`ok ${i}`, "Edit"),
|
|
201
|
-
],
|
|
202
|
-
keepFrom: 2,
|
|
203
|
-
timestamp: i * 2 + 1,
|
|
204
|
-
}, s);
|
|
205
|
-
}
|
|
206
|
-
buildTree(s, sid);
|
|
207
|
-
const nodes = listRaptorNodes(sid, sd);
|
|
208
|
-
assert.ok(nodes.length > 0, "tree built for breadth test");
|
|
209
|
-
// Enable live mode.
|
|
210
|
-
const orig = process.env.RAPTOR_SHADOW_MODE;
|
|
211
|
-
process.env.RAPTOR_SHADOW_MODE = "false";
|
|
212
|
-
try {
|
|
213
|
-
const hits = vectorSearch(s, sid, "cooking and automotive", 5);
|
|
214
|
-
assert.ok(hits.length > 0, "search returns hits for mixed query");
|
|
215
|
-
// Breadth: at least 2 distinct hits (probabilistic, but with 10
|
|
216
|
-
// checkpoints across 2 topics, the tree's staged expansion should
|
|
217
|
-
// surface both).
|
|
218
|
-
assert.ok(hits.length >= 2, `expected ≥2 diverse hits, got ${hits.length}`);
|
|
219
|
-
}
|
|
220
|
-
finally {
|
|
221
|
-
if (orig === undefined)
|
|
222
|
-
delete process.env.RAPTOR_SHADOW_MODE;
|
|
223
|
-
else
|
|
224
|
-
process.env.RAPTOR_SHADOW_MODE = orig;
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
// ─── Gate 5: p95 latency ────────────────────────────────────────────────────
|
|
228
|
-
test("gate 5: 200-checkpoint × 20-query median latency < 100 ms", () => {
|
|
229
|
-
const sd = stateDir();
|
|
230
|
-
const s = new VectorStore({ dedupSim: 0.9, stateDir: sd, config: cfg() });
|
|
231
|
-
const sid = "latency";
|
|
232
|
-
// 200 checkpoints across 10 topics.
|
|
233
|
-
const topics = [
|
|
234
|
-
"machine learning gradient descent",
|
|
235
|
-
"quantum computing entanglement",
|
|
236
|
-
"organic chemistry catalysis",
|
|
237
|
-
"renaissance art fresco painting",
|
|
238
|
-
"marine biology coral reefs",
|
|
239
|
-
"astrophysics dark matter",
|
|
240
|
-
"ancient rome senate",
|
|
241
|
-
"music theory counterpoint",
|
|
242
|
-
"urban planning zoning",
|
|
243
|
-
"evolutionary biology adaptation",
|
|
244
|
-
];
|
|
245
|
-
for (let i = 1; i <= 200; i++) {
|
|
246
|
-
const topic = topics[i % topics.length];
|
|
247
|
-
compactSession({
|
|
248
|
-
sessionId: sid,
|
|
249
|
-
messages: [msg(`${topic} checkpoint ${i}`), msg(`ack ${i}`, "Edit")],
|
|
250
|
-
keepFrom: 2,
|
|
251
|
-
timestamp: i,
|
|
252
|
-
}, s);
|
|
253
|
-
}
|
|
254
|
-
buildTree(s, sid);
|
|
255
|
-
// Enable live mode.
|
|
256
|
-
const orig = process.env.RAPTOR_SHADOW_MODE;
|
|
257
|
-
process.env.RAPTOR_SHADOW_MODE = "false";
|
|
258
|
-
try {
|
|
259
|
-
const queries = [
|
|
260
|
-
"machine learning optimization",
|
|
261
|
-
"quantum entanglement physics",
|
|
262
|
-
"organic chemistry reactions",
|
|
263
|
-
"renaissance art techniques",
|
|
264
|
-
"coral reef ecosystems",
|
|
265
|
-
"dark matter universe",
|
|
266
|
-
"roman government structure",
|
|
267
|
-
"music harmony rules",
|
|
268
|
-
"city planning infrastructure",
|
|
269
|
-
"evolutionary adaptation species",
|
|
270
|
-
"gradient descent algorithms",
|
|
271
|
-
"quantum computing qubits",
|
|
272
|
-
"chemical catalysis processes",
|
|
273
|
-
"fresco painting methods",
|
|
274
|
-
"marine biology biodiversity",
|
|
275
|
-
"astrophysics observations",
|
|
276
|
-
"ancient roman history",
|
|
277
|
-
"music composition theory",
|
|
278
|
-
"urban development patterns",
|
|
279
|
-
"biology natural selection",
|
|
280
|
-
];
|
|
281
|
-
const latencies = [];
|
|
282
|
-
for (const q of queries) {
|
|
283
|
-
const t0 = Date.now();
|
|
284
|
-
vectorSearch(s, sid, q, 5);
|
|
285
|
-
latencies.push(Date.now() - t0);
|
|
286
|
-
}
|
|
287
|
-
latencies.sort((a, b) => a - b);
|
|
288
|
-
const median = latencies[Math.floor(latencies.length / 2)];
|
|
289
|
-
const p95 = latencies[Math.floor(latencies.length * 0.95)];
|
|
290
|
-
assert.ok(median < 100, `median latency ${median} ms exceeds 100 ms budget (p95=${p95} ms)`);
|
|
291
|
-
}
|
|
292
|
-
finally {
|
|
293
|
-
if (orig === undefined)
|
|
294
|
-
delete process.env.RAPTOR_SHADOW_MODE;
|
|
295
|
-
else
|
|
296
|
-
process.env.RAPTOR_SHADOW_MODE = orig;
|
|
297
|
-
}
|
|
298
|
-
});
|
|
@@ -1,219 +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, L2_ENABLED, vectorSemDedup, vectorList, vectorSearch } from "../vectorStore.js";
|
|
7
|
-
import { mmrRerank } from "./mmr.js";
|
|
8
|
-
import { topK } from "./topk.js";
|
|
9
|
-
import { cosineSimilarity, defaultEmbedder } from "../embedder.js";
|
|
10
|
-
import { upsertCheckpoint } from "../store/sqlite.js";
|
|
11
|
-
const baseTmp = mkdtempSync(join(tmpdir(), "mc-s12-"));
|
|
12
|
-
let counter = 0;
|
|
13
|
-
function store(opts = {}) {
|
|
14
|
-
const dir = join(baseTmp, `run-${counter++}`);
|
|
15
|
-
return new VectorStore({ stateDir: dir, ...opts });
|
|
16
|
-
}
|
|
17
|
-
// --- MMR diversity ---------------------------------------------------------
|
|
18
|
-
test("mmrRerank diversifies: a cluster yields distinct-relevance results", () => {
|
|
19
|
-
const e = defaultEmbedder();
|
|
20
|
-
// Three near-identical vectors + one distinct.
|
|
21
|
-
const v = e.embed("the compiler optimized the parser hot loop");
|
|
22
|
-
const v2 = e.embed("the compiler optimized the parser hot loops"); // near-dup of v
|
|
23
|
-
const v3 = e.embed("the compiler optimized the parser hot loop now"); // near-dup of v
|
|
24
|
-
const vDistinct = e.embed("the database added a covering index for queries");
|
|
25
|
-
const items = [
|
|
26
|
-
{ item: "a", vector: v, relevance: 0.9 },
|
|
27
|
-
{ item: "b", vector: v2, relevance: 0.88 },
|
|
28
|
-
{ item: "c", vector: v3, relevance: 0.87 },
|
|
29
|
-
{ item: "d", vector: vDistinct, relevance: 0.5 },
|
|
30
|
-
];
|
|
31
|
-
const ranked = mmrRerank(items, 2, 0.5);
|
|
32
|
-
assert.equal(ranked.length, 2);
|
|
33
|
-
// The near-dup cluster (a) and the distinct one (d) should both survive.
|
|
34
|
-
assert.ok(ranked.includes("a"));
|
|
35
|
-
assert.ok(ranked.includes("d"));
|
|
36
|
-
assert.ok(!ranked.includes("b") || !ranked.includes("c"));
|
|
37
|
-
});
|
|
38
|
-
test("mmrRerank with lambda=1 is pure relevance ranking", () => {
|
|
39
|
-
const items = [
|
|
40
|
-
{ item: "low", vector: [1, 0, 0], relevance: 0.1 },
|
|
41
|
-
{ item: "high", vector: [0, 1, 0], relevance: 0.9 },
|
|
42
|
-
];
|
|
43
|
-
const ranked = mmrRerank(items, 2, 1);
|
|
44
|
-
assert.deepEqual(ranked, ["high", "low"]);
|
|
45
|
-
});
|
|
46
|
-
// --- Heap top-k ------------------------------------------------------------
|
|
47
|
-
test("topK matches brute-force full sort on a fixture", () => {
|
|
48
|
-
const items = Array.from({ length: 1000 }, (_, i) => ({ item: i, score: Math.sin(i) * 100 + (i % 7) }));
|
|
49
|
-
for (const k of [1, 3, 10, 50]) {
|
|
50
|
-
const heap = topK(items, k).map((s) => s.item).sort((a, b) => b - a);
|
|
51
|
-
const brute = [...items].sort((a, b) => b.score - a.score).slice(0, k).map((s) => s.item).sort((a, b) => b - a);
|
|
52
|
-
assert.deepEqual(heap, brute, `topK(${k}) should match brute force`);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
test("topK with k >= n returns all (descending by score)", () => {
|
|
56
|
-
const items = [{ item: "x", score: 1 }, { item: "y", score: 2 }];
|
|
57
|
-
assert.deepEqual(topK(items, 5).map((s) => s.item), ["y", "x"]);
|
|
58
|
-
});
|
|
59
|
-
// --- Empty-vector guard ----------------------------------------------------
|
|
60
|
-
test("cosineSimilarity guards empty vector → 0 (no NaN)", () => {
|
|
61
|
-
assert.equal(cosineSimilarity([], [1, 2, 3]), 0);
|
|
62
|
-
assert.equal(cosineSimilarity([0, 0, 0], [1, 2, 3]), 0);
|
|
63
|
-
assert.ok(!Number.isNaN(cosineSimilarity([], [])));
|
|
64
|
-
});
|
|
65
|
-
// --- L2_ENABLED flag -------------------------------------------------------
|
|
66
|
-
test("L2_ENABLED defaults true; search still returns hits", () => {
|
|
67
|
-
assert.equal(L2_ENABLED, true);
|
|
68
|
-
const s = store();
|
|
69
|
-
s.add({ sessionId: "sess_l2", summary: "investigated the parser", regionText: "investigated src/parser.ts and added a tokenizer", timestamp: 1 });
|
|
70
|
-
const hits = vectorSearch(s, "sess_l2", "src/parser.ts tokenizer", 3);
|
|
71
|
-
assert.ok(hits.length >= 1);
|
|
72
|
-
});
|
|
73
|
-
test("L2_ENABLED=false skips semantic tier but L0/L1 still work", () => {
|
|
74
|
-
const s = store({ l2Enabled: false });
|
|
75
|
-
const r1 = s.add({ sessionId: "sess_l2off", summary: "x", regionText: "the auth module validates the session token", timestamp: 1 });
|
|
76
|
-
const r2 = s.add({ sessionId: "sess_l2off", summary: "x", regionText: "the auth module validates the session token", timestamp: 2 });
|
|
77
|
-
assert.equal(r2.deduped, true); // L0 catches exact
|
|
78
|
-
assert.equal(r1.deduped, false);
|
|
79
|
-
});
|
|
80
|
-
// --- SemDeDup --------------------------------------------------------------
|
|
81
|
-
// Seed a legacy session directly (bypassing add-time dedup tiers) so SemDeDup
|
|
82
|
-
// has a redundant pair to prune — its real job is offline cleanup of data that
|
|
83
|
-
// predates / escaped the online cascade.
|
|
84
|
-
function seed(dir, sessionId, rows) {
|
|
85
|
-
const e = defaultEmbedder();
|
|
86
|
-
for (const r of rows) {
|
|
87
|
-
const cp = {
|
|
88
|
-
checkpointId: r.id,
|
|
89
|
-
sessionId,
|
|
90
|
-
summary: r.text,
|
|
91
|
-
keyDecisions: [],
|
|
92
|
-
nextSteps: [],
|
|
93
|
-
filesModified: [],
|
|
94
|
-
tokenEstimate: r.tok,
|
|
95
|
-
regionHash: `r-${r.id}`,
|
|
96
|
-
embedding: e.embed(r.text),
|
|
97
|
-
timestamp: 1,
|
|
98
|
-
};
|
|
99
|
-
upsertCheckpoint(cp, dir);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
test("semDedup marks redundant near-identical rows 'removed' and search excludes them", () => {
|
|
103
|
-
const dir = join(baseTmp, `run-${counter++}`);
|
|
104
|
-
const s = new VectorStore({ stateDir: dir });
|
|
105
|
-
seed(dir, "sess_sd", [
|
|
106
|
-
{ id: "chkpt_001", text: "the cache stores parsed ast nodes for fast lookup", tok: 100 },
|
|
107
|
-
{ id: "chkpt_002", text: "the cache stores parsed ast nodes for fast lookup and reuse", tok: 900 },
|
|
108
|
-
]);
|
|
109
|
-
const removed = vectorSemDedup(s, "sess_sd", 0.85);
|
|
110
|
-
assert.equal(removed, 1);
|
|
111
|
-
const st = vectorList(s, "sess_sd");
|
|
112
|
-
const dropped = st.find((c) => c.dedupStatus === "removed");
|
|
113
|
-
assert.ok(dropped);
|
|
114
|
-
assert.equal(dropped.checkpointId, "chkpt_001"); // lower tokenEstimate removed
|
|
115
|
-
// Search excludes the removed row (only one active remains).
|
|
116
|
-
const hits = vectorSearch(s, "sess_sd", "cache parsed ast nodes", 5);
|
|
117
|
-
assert.equal(hits.length, 1);
|
|
118
|
-
});
|
|
119
|
-
test("semDedup is idempotent (re-run removes nothing new)", () => {
|
|
120
|
-
const dir = join(baseTmp, `run-${counter++}`);
|
|
121
|
-
const s = new VectorStore({ stateDir: dir });
|
|
122
|
-
seed(dir, "sess_sd2", [
|
|
123
|
-
{ id: "chkpt_001", text: "identical region text for the dedup job now", tok: 100 },
|
|
124
|
-
{ id: "chkpt_002", text: "identical region text for the dedup job right now", tok: 200 },
|
|
125
|
-
]);
|
|
126
|
-
const first = vectorSemDedup(s, "sess_sd2", 0.85);
|
|
127
|
-
const second = vectorSemDedup(s, "sess_sd2", 0.85);
|
|
128
|
-
assert.equal(first, 1);
|
|
129
|
-
assert.equal(second, 0);
|
|
130
|
-
});
|
|
131
|
-
// --- HttpEmbedder (BYO localhost backend) ----------------------------------
|
|
132
|
-
// Hermetic: a self-test server returns a deterministic embedding. The server
|
|
133
|
-
// runs in an INDEPENDENT child process (its own event loop) so that when
|
|
134
|
-
// HttpEmbedder.embed() blocks the *parent* via spawnSync, the server can still
|
|
135
|
-
// accept the connection — hosting it in-process would deadlock.
|
|
136
|
-
import { spawn } from "node:child_process";
|
|
137
|
-
const ECHO_SERVER = String.raw `
|
|
138
|
-
import { createServer } from "node:http";
|
|
139
|
-
const s = createServer((req, res) => {
|
|
140
|
-
let b = "";
|
|
141
|
-
req.on("data", (c) => (b += c));
|
|
142
|
-
req.on("end", () => {
|
|
143
|
-
const input = JSON.parse(b).input || [""];
|
|
144
|
-
const text = (input[0] || "").toLowerCase().replace(/\s+/g, " ");
|
|
145
|
-
const vec = new Array(8).fill(0);
|
|
146
|
-
for (const w of text.split(" ")) {
|
|
147
|
-
let h = 0x811c9dc5;
|
|
148
|
-
for (let i = 0; i < w.length; i++) { h ^= w.charCodeAt(i); h = Math.imul(h, 0x01000193); }
|
|
149
|
-
vec[h % 8] += 1;
|
|
150
|
-
}
|
|
151
|
-
res.setHeader("content-type", "application/json");
|
|
152
|
-
res.end(JSON.stringify({ data: [{ embedding: vec }] }));
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
s.listen(0, "127.0.0.1", () => process.stdout.write(String(s.address().port)));
|
|
156
|
-
`;
|
|
157
|
-
// A simpler shape-only server: always returns { data: [[0.1,0.2,0.3]] }.
|
|
158
|
-
const DATA_ARR_SERVER = String.raw `
|
|
159
|
-
import { createServer } from "node:http";
|
|
160
|
-
const s = createServer((_req, res) => {
|
|
161
|
-
res.setHeader("content-type", "application/json");
|
|
162
|
-
res.end(JSON.stringify({ data: [[0.1, 0.2, 0.3]] }));
|
|
163
|
-
});
|
|
164
|
-
s.listen(0, "127.0.0.1", () => process.stdout.write(String(s.address().port)));
|
|
165
|
-
`;
|
|
166
|
-
/** Spawn an independent echo server; resolves with its url once the port is up. */
|
|
167
|
-
function startEchoServer(shape) {
|
|
168
|
-
const script = shape === "data-arr" ? DATA_ARR_SERVER : ECHO_SERVER;
|
|
169
|
-
const proc = spawn(process.execPath, ["-e", script], { stdio: ["ignore", "pipe", "ignore"] });
|
|
170
|
-
return new Promise((resolve, reject) => {
|
|
171
|
-
let buf = "";
|
|
172
|
-
proc.stdout.on("data", (d) => {
|
|
173
|
-
buf += d.toString();
|
|
174
|
-
const m = buf.match(/(\d+)/);
|
|
175
|
-
if (m)
|
|
176
|
-
resolve({ url: `http://127.0.0.1:${m[1]}`, proc });
|
|
177
|
-
});
|
|
178
|
-
proc.on("error", reject);
|
|
179
|
-
setTimeout(() => reject(new Error("echo server did not start")), 5000);
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
test("HttpEmbedder parses OpenAI-style response and resolves dim", async () => {
|
|
183
|
-
const { url, proc } = await startEchoServer();
|
|
184
|
-
try {
|
|
185
|
-
const { HttpEmbedder } = await import("../httpEmbedder.js");
|
|
186
|
-
const emb = new HttpEmbedder({ url });
|
|
187
|
-
assert.equal(emb.dim, 0); // unknown until first embed
|
|
188
|
-
const v = emb.embed("the parser optimized the hot loop");
|
|
189
|
-
assert.equal(v.length, 8); // echo server returns 8-dim
|
|
190
|
-
assert.equal(emb.dim, 8); // resolved after first call
|
|
191
|
-
const v2 = emb.embed("the parser optimized the hot loop");
|
|
192
|
-
assert.deepEqual(v2, v); // deterministic
|
|
193
|
-
}
|
|
194
|
-
finally {
|
|
195
|
-
proc.kill();
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
test("HttpEmbedder tolerant parser: accepts { data: [[...]] } shape", async () => {
|
|
199
|
-
const { url, proc } = await startEchoServer("data-arr");
|
|
200
|
-
try {
|
|
201
|
-
const { HttpEmbedder } = await import("../httpEmbedder.js");
|
|
202
|
-
const emb = new HttpEmbedder({ url });
|
|
203
|
-
// embed() L2-normalizes; verify the { data: [[...]] } shape parsed (dim 3)
|
|
204
|
-
// and the returned vector is the unit-normalized form of [0.1, 0.2, 0.3].
|
|
205
|
-
const v = emb.embed("x");
|
|
206
|
-
assert.equal(v.length, 3);
|
|
207
|
-
const norm = Math.sqrt(0.1 ** 2 + 0.2 ** 2 + 0.3 ** 2);
|
|
208
|
-
assert.ok(Math.abs(v[0] - 0.1 / norm) < 1e-9);
|
|
209
|
-
assert.ok(Math.abs(v[1] - 0.2 / norm) < 1e-9);
|
|
210
|
-
assert.ok(Math.abs(v[2] - 0.3 / norm) < 1e-9);
|
|
211
|
-
}
|
|
212
|
-
finally {
|
|
213
|
-
proc.kill();
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
// --- cleanup ---------------------------------------------------------------
|
|
217
|
-
test("Sprint 12 cleanup", () => {
|
|
218
|
-
rmSync(baseTmp, { recursive: true, force: true });
|
|
219
|
-
});
|