pi-mega-compact 0.11.4 → 0.11.6
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/cache-stripes.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints.js +32 -0
- package/dist/extensions/dashboard-server/api-contracts/memory-map.js +1 -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 +135 -47
- package/dist/extensions/dashboard-server/routes-game.js +3 -0
- package/dist/extensions/dashboard-server/routes-memory-map.js +50 -0
- 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 +267 -0
- package/dist/extensions/dashboard-server/routes.js +4 -0
- package/dist/extensions/dashboard-server/server.js +13 -1
- package/dist/extensions/mega-commands.js +189 -1
- package/dist/extensions/mega-compact.js +5 -0
- package/dist/extensions/mega-config.js +7 -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 +45 -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 +134 -2
- package/dist/extensions/mega-events/recall-tail.js +59 -0
- package/dist/extensions/mega-events/separated-prompt.js +248 -0
- package/dist/extensions/mega-events/session-handlers.js +15 -8
- package/dist/extensions/mega-runtime/env-loader.js +56 -0
- package/dist/extensions/mega-runtime/reset-runtime.js +6 -0
- package/dist/extensions/mega-runtime/runtime-snapshot.js +1 -0
- package/dist/extensions/mega-runtime/runtime.js +7 -0
- package/dist/extensions/mega-runtime/snapshot.js +1 -0
- package/dist/extensions/mega-runtime/widget.js +5 -0
- package/dist/src/cache-stripe-impl.js +288 -0
- package/dist/src/cache-stripe.js +11 -0
- package/dist/src/config/stopwords.js +24 -0
- package/dist/src/config.js +17 -0
- package/dist/src/embedder.js +41 -2
- package/dist/src/memoryGraph.js +299 -0
- package/dist/src/memoryStats.js +75 -0
- package/dist/src/monitoring.js +13 -0
- package/dist/src/prefix-break.js +43 -0
- package/dist/src/pricing.js +1 -1
- package/dist/src/queryExpansion.js +163 -0
- package/dist/src/queryReformulation/cache.js +123 -0
- package/dist/src/queryReformulation/rrf.js +29 -0
- package/dist/src/queryReformulation/tfidf.js +61 -0
- package/dist/src/queryReformulation/vagueness.js +33 -0
- package/dist/src/queryReformulation.js +225 -0
- package/dist/src/recallMetrics.js +258 -0
- package/dist/src/store/sqlite/cache-stripes.js +133 -0
- package/dist/src/store/sqlite/fts5-search.js +68 -0
- package/dist/src/store/sqlite/perf-samples.js +145 -16
- package/dist/src/store/sqlite/schema.js +60 -1
- package/dist/src/store/sqlite.js +1 -0
- 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 +55 -10
- package/dist/src/tiered-router/types.js +18 -0
- package/dist/src/tieredRouter.js +421 -0
- package/dist/src/vectorStore.js +8 -6
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-DR9cLGDL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-DR9cLGDL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/AchievementsTab-svNUgJ1e.js +2 -0
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-svNUgJ1e.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-CmmWheuW.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-CmmWheuW.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-CFE7jLsa.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-CFE7jLsa.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/GameTab-CJAX_th_.js +2 -0
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-CJAX_th_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-P4SUsvMf.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-P4SUsvMf.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-CHQscixy.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-CHQscixy.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-DBs4DJdd.js +2 -0
- package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-DBs4DJdd.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-DeFz76L5.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-DeFz76L5.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-BWNsj1OB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-BWNsj1OB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-CiqCOQuL.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-CiqCOQuL.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BWWQxltv.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BWWQxltv.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-CVz4f4-o.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-CVz4f4-o.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-CUNn22iV.css +1 -0
- package/extensions/dashboard-client/dist/assets/index-DrktNOoT.js +42 -0
- package/extensions/dashboard-client/dist/assets/index-DrktNOoT.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-Bf5LOLSi.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-Bf5LOLSi.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/App.tsx +28 -8
- package/extensions/dashboard-client/src/api/client.ts +29 -0
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
- package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +100 -0
- 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/components/StripeDistributionCard.tsx +110 -0
- package/extensions/dashboard-client/src/components/TabBar.tsx +49 -4
- package/extensions/dashboard-client/src/main.tsx +1 -0
- package/extensions/dashboard-client/src/styles/base.css +30 -0
- package/extensions/dashboard-client/src/styles/cache.css +167 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +75 -12
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +440 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +418 -0
- package/extensions/dashboard-client/tsconfig.json +3 -2
- package/extensions/dashboard-client/vite.config.ts +2 -0
- package/extensions/dashboard-server/api-contracts/cache-stripes.ts +49 -0
- package/extensions/dashboard-server/api-contracts/endpoints.ts +66 -3
- package/extensions/dashboard-server/api-contracts/index.ts +22 -0
- package/extensions/dashboard-server/api-contracts/memory-map.ts +50 -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 +80 -0
- package/extensions/dashboard-server/index-reader.ts +138 -121
- package/extensions/dashboard-server/routes-cache.ts +186 -75
- package/extensions/dashboard-server/routes-game.ts +3 -0
- package/extensions/dashboard-server/routes-memory-map.ts +105 -0
- 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 +293 -0
- package/extensions/dashboard-server/routes.ts +4 -0
- package/extensions/dashboard-server/server.ts +12 -0
- package/extensions/mega-commands.ts +211 -1
- package/extensions/mega-compact.ts +5 -0
- package/extensions/mega-config.ts +27 -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 +53 -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 +190 -6
- package/extensions/mega-events/recall-tail.ts +88 -0
- package/extensions/mega-events/separated-prompt.ts +329 -0
- package/extensions/mega-events/session-handlers.ts +14 -7
- package/extensions/mega-runtime/env-loader.ts +55 -0
- package/extensions/mega-runtime/helpers.ts +14 -0
- package/extensions/mega-runtime/reset-runtime.ts +6 -0
- package/extensions/mega-runtime/runtime-snapshot.ts +1 -0
- package/extensions/mega-runtime/runtime.ts +7 -0
- package/extensions/mega-runtime/snapshot.ts +6 -0
- package/extensions/mega-runtime/widget-types.ts +3 -0
- package/extensions/mega-runtime/widget.ts +5 -0
- package/package.json +5 -2
- package/src/cache-stripe-impl.ts +385 -0
- package/src/cache-stripe.ts +18 -0
- package/src/config/stopwords.ts +25 -0
- package/src/config.ts +26 -0
- package/src/embedder.ts +42 -2
- package/src/memoryGraph.ts +438 -0
- package/src/memoryStats.ts +107 -0
- package/src/monitoring.ts +35 -0
- package/src/prefix-break.ts +83 -0
- package/src/pricing.ts +2 -2
- package/src/queryExpansion.ts +206 -0
- package/src/queryReformulation/cache.ts +169 -0
- package/src/queryReformulation/rrf.ts +51 -0
- package/src/queryReformulation/tfidf.ts +79 -0
- package/src/queryReformulation/vagueness.ts +38 -0
- package/src/queryReformulation.ts +355 -0
- package/src/recallMetrics.ts +388 -0
- package/src/store/sqlite/cache-stripes.ts +196 -0
- package/src/store/sqlite/fts5-search.ts +90 -0
- package/src/store/sqlite/perf-samples.ts +218 -23
- package/src/store/sqlite/schema.ts +60 -1
- package/src/store/sqlite.ts +1 -0
- 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 +71 -11
- package/src/tiered-router/types.ts +64 -0
- package/src/tieredRouter.ts +489 -0
- package/src/vectorStore.ts +9 -5
- 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/GameTab-BLDudcO5.js +0 -2
- 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-BEdKlpAB.css +0 -1
- package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js +0 -42
- 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
package/src/ratio.bench.test.ts
DELETED
|
@@ -1,1316 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ratio.bench.test.ts — Compression & Dedup Ratio Benchmark Suite
|
|
3
|
-
*
|
|
4
|
-
* Measures real-world effectiveness of the compaction pipeline:
|
|
5
|
-
* - Compression tier ratios (raw/gzip/brotli) at various data sizes
|
|
6
|
-
* - Extractive summarization ratio (target: 35:1)
|
|
7
|
-
* - Collapsible message detection rates
|
|
8
|
-
* - Dedup hit rates across L0/L1/L2 tiers with controlled similarity
|
|
9
|
-
* - Token estimation accuracy vs actual character counts
|
|
10
|
-
* - End-to-end pipeline compression ratio on realistic workloads
|
|
11
|
-
* - Store-level stats tracking (dedup hit rate, checkpoint counts, injections)
|
|
12
|
-
*
|
|
13
|
-
* Run: npx tsc && node --test dist/src/ratio.bench.test.js
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
17
|
-
import assert from "node:assert/strict";
|
|
18
|
-
import * as fs from "node:fs";
|
|
19
|
-
import * as path from "node:path";
|
|
20
|
-
import * as os from "node:os";
|
|
21
|
-
|
|
22
|
-
import { VectorStore, computeRegionHash, vectorStats, vectorWasInjected, vectorMarkInjected, vectorTopSimilar } from "./vectorStore.js";
|
|
23
|
-
import type { SearchHit } from "./vectorStore.js";
|
|
24
|
-
import { findSuperseded } from "./supersede.js";
|
|
25
|
-
import { autoCompactCheck, isChatty } from "./compact.js";
|
|
26
|
-
import { extractiveSummarize } from "./extractive.js";
|
|
27
|
-
import {
|
|
28
|
-
estimateBlockTokens,
|
|
29
|
-
estimateMessageTokens,
|
|
30
|
-
estimateSessionTokens,
|
|
31
|
-
} from "./tokens.js";
|
|
32
|
-
import { compactSession, recall } from "./engine.js";
|
|
33
|
-
import type { EngineMessage } from "./types.js";
|
|
34
|
-
import { compressSmart, decompressSmart } from "./store/compression.js";
|
|
35
|
-
|
|
36
|
-
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
function makeMsg(role: EngineMessage["role"], text: string): EngineMessage {
|
|
39
|
-
return { role, text };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function makeDir(): string {
|
|
43
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), "ratio-bench-"));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Generate N messages with controlled repetition. */
|
|
47
|
-
function generateMessages(
|
|
48
|
-
n: number,
|
|
49
|
-
opts: {
|
|
50
|
-
pattern: "unique" | "repetitive" | "mixed" | "code-review" | "debug-session";
|
|
51
|
-
},
|
|
52
|
-
): EngineMessage[] {
|
|
53
|
-
const msgs: EngineMessage[] = [];
|
|
54
|
-
const templates = [
|
|
55
|
-
"I'm looking at the {file} module. The {component} needs refactoring because {reason}.",
|
|
56
|
-
"Found a bug in {file}: the {component} doesn't handle {case} correctly. Here's the fix: {fix}",
|
|
57
|
-
"Let me check the {file} implementation. The {component} uses {pattern} pattern which is fine for now.",
|
|
58
|
-
"Updated {file} to fix the {component} issue. The {reason} was causing {case}.",
|
|
59
|
-
"Running tests on {file}. The {component} test covers {case} and {fix}. Looks good.",
|
|
60
|
-
"The {component} in {file} needs to handle {case}. Currently it just {fix}.",
|
|
61
|
-
"Reviewed the {file} changes. The {component} refactor looks solid. {reason}.",
|
|
62
|
-
"Deployed the {component} fix to staging. {file} is now handling {case} correctly.",
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
const files = [
|
|
66
|
-
"src/engine.ts",
|
|
67
|
-
"src/store.ts",
|
|
68
|
-
"src/vectorStore.ts",
|
|
69
|
-
"src/compact.ts",
|
|
70
|
-
"src/recall.ts",
|
|
71
|
-
];
|
|
72
|
-
const components = [
|
|
73
|
-
"compression",
|
|
74
|
-
"dedup",
|
|
75
|
-
"embedding",
|
|
76
|
-
"search",
|
|
77
|
-
"checkpoint",
|
|
78
|
-
"supersede",
|
|
79
|
-
"recall",
|
|
80
|
-
];
|
|
81
|
-
const reasons = [
|
|
82
|
-
"performance",
|
|
83
|
-
"correctness",
|
|
84
|
-
"maintainability",
|
|
85
|
-
"edge case handling",
|
|
86
|
-
"type safety",
|
|
87
|
-
];
|
|
88
|
-
const cases = [
|
|
89
|
-
"empty input",
|
|
90
|
-
"large payloads",
|
|
91
|
-
"concurrent access",
|
|
92
|
-
"unicode content",
|
|
93
|
-
"timeout",
|
|
94
|
-
];
|
|
95
|
-
const fixes = [
|
|
96
|
-
"added bounds checking",
|
|
97
|
-
"refactored the loop",
|
|
98
|
-
"added error handling",
|
|
99
|
-
"simplified the logic",
|
|
100
|
-
"added unit tests",
|
|
101
|
-
];
|
|
102
|
-
const patterns = ["singleton", "observer", "strategy", "factory", "builder"];
|
|
103
|
-
|
|
104
|
-
for (let i = 0; i < n; i++) {
|
|
105
|
-
const template = templates[i % templates.length];
|
|
106
|
-
const fill = (s: string): string =>
|
|
107
|
-
s
|
|
108
|
-
.replace("{file}", files[i % files.length])
|
|
109
|
-
.replace("{component}", components[i % components.length])
|
|
110
|
-
.replace("{reason}", reasons[i % reasons.length])
|
|
111
|
-
.replace("{case}", cases[i % cases.length])
|
|
112
|
-
.replace("{fix}", fixes[i % fixes.length])
|
|
113
|
-
.replace("{pattern}", patterns[i % patterns.length]);
|
|
114
|
-
|
|
115
|
-
let text: string;
|
|
116
|
-
|
|
117
|
-
switch (opts.pattern) {
|
|
118
|
-
case "unique":
|
|
119
|
-
text = fill(template) + ` [turn ${i}]`;
|
|
120
|
-
break;
|
|
121
|
-
|
|
122
|
-
case "repetitive":
|
|
123
|
-
text = fill(templates[i % 5]);
|
|
124
|
-
break;
|
|
125
|
-
|
|
126
|
-
case "mixed":
|
|
127
|
-
text =
|
|
128
|
-
i % 5 < 3
|
|
129
|
-
? fill(template) + ` [turn ${i}]`
|
|
130
|
-
: fill(templates[i % 3]);
|
|
131
|
-
break;
|
|
132
|
-
|
|
133
|
-
case "code-review":
|
|
134
|
-
if (i % 4 === 0) {
|
|
135
|
-
text = `Reviewing PR #${i}: ${fill(template)}`;
|
|
136
|
-
} else if (i % 4 === 1) {
|
|
137
|
-
text = "```typescript\nfunction handle" + components[i % components.length] + "() {\n // " + fill(template) + "\n return result;\n}\n```";
|
|
138
|
-
} else if (i % 4 === 2) {
|
|
139
|
-
text = `LGTM. ${fill(template)} The test coverage looks good.`;
|
|
140
|
-
} else {
|
|
141
|
-
text = `@user requested changes: ${fill(template)}`;
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
|
|
145
|
-
case "debug-session":
|
|
146
|
-
if (i % 6 === 0) {
|
|
147
|
-
text = `Error in ${files[i % files.length]}: TypeError: Cannot read property '${components[i % components.length]}' of undefined`;
|
|
148
|
-
} else if (i % 6 === 1) {
|
|
149
|
-
text = `Stack trace:\n at ${components[i % components.length]} (${files[i % files.length]}:${100 + i}:15)\n at process (${files[(i + 1) % files.length]}:${50 + i}:3)`;
|
|
150
|
-
} else if (i % 6 === 2) {
|
|
151
|
-
text = `The issue is that ${cases[i % cases.length]} isn't being handled. ${fixes[i % fixes.length]}.`;
|
|
152
|
-
} else if (i % 6 === 3) {
|
|
153
|
-
text = `Applied fix: ${fill(template)}`;
|
|
154
|
-
} else if (i % 6 === 4) {
|
|
155
|
-
text = `Tests passing now. ${reasons[i % reasons.length]}.`;
|
|
156
|
-
} else {
|
|
157
|
-
text = `Committed fix for ${components[i % components.length]}. ${fill(template)}`;
|
|
158
|
-
}
|
|
159
|
-
break;
|
|
160
|
-
|
|
161
|
-
default:
|
|
162
|
-
text = fill(template);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const role: EngineMessage["role"] = i % 2 === 0 ? "user" : "assistant";
|
|
166
|
-
msgs.push(makeMsg(role, text));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return msgs;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** Generate a large realistic conversation with tool reads, code blocks, discussion. */
|
|
173
|
-
function generateRealisticConversation(turns: number): EngineMessage[] {
|
|
174
|
-
const msgs: EngineMessage[] = [];
|
|
175
|
-
for (let i = 0; i < turns; i++) {
|
|
176
|
-
const phase = i % 8;
|
|
177
|
-
const mods = ["compression", "dedup", "embedding", "search"];
|
|
178
|
-
const fns = ["vectorStore.ts", "engine.ts", "compact.ts", "recall.ts"];
|
|
179
|
-
const issues = ["error handling", "type safety", "performance", "logging"];
|
|
180
|
-
const bugs = ["null pointer", "type mismatch", "race condition", "memory leak"];
|
|
181
|
-
|
|
182
|
-
switch (phase) {
|
|
183
|
-
case 0:
|
|
184
|
-
msgs.push(
|
|
185
|
-
makeMsg(
|
|
186
|
-
"user",
|
|
187
|
-
`I need help with the ${mods[i % 4]} module. It's not working correctly.`,
|
|
188
|
-
),
|
|
189
|
-
);
|
|
190
|
-
break;
|
|
191
|
-
case 1:
|
|
192
|
-
msgs.push(
|
|
193
|
-
makeMsg(
|
|
194
|
-
"assistant",
|
|
195
|
-
`Let me look at the code. I'll check the ${fns[i % 4]} file.`,
|
|
196
|
-
),
|
|
197
|
-
);
|
|
198
|
-
break;
|
|
199
|
-
case 2:
|
|
200
|
-
msgs.push(
|
|
201
|
-
makeMsg(
|
|
202
|
-
"tool",
|
|
203
|
-
`File content of src/${["vectorStore", "engine", "compact", "recall"][i % 4]}.ts:\n${"x".repeat(800 + (i % 5) * 200)}\n// Line ${i * 10}: function ${["search", "compact", "embed", "dedup"][i % 4]}() { ... }`,
|
|
204
|
-
),
|
|
205
|
-
);
|
|
206
|
-
break;
|
|
207
|
-
case 3:
|
|
208
|
-
msgs.push(
|
|
209
|
-
makeMsg(
|
|
210
|
-
"assistant",
|
|
211
|
-
`I found the issue. The ${mods[i % 4]} function doesn't handle edge cases properly. Here's what I suggest:\n\n\`\`\`typescript\nfunction fixed${["Search", "Compact", "Embed", "Dedup"][i % 4]}() {\n if (!input) return null;\n return process(input);\n}\n\`\`\``,
|
|
212
|
-
),
|
|
213
|
-
);
|
|
214
|
-
break;
|
|
215
|
-
case 4:
|
|
216
|
-
msgs.push(
|
|
217
|
-
makeMsg(
|
|
218
|
-
"user",
|
|
219
|
-
`That looks good. Can you also fix the ${issues[i % 4]} while you're at it?`,
|
|
220
|
-
),
|
|
221
|
-
);
|
|
222
|
-
break;
|
|
223
|
-
case 5:
|
|
224
|
-
msgs.push(
|
|
225
|
-
makeMsg(
|
|
226
|
-
"assistant",
|
|
227
|
-
`Sure. I've updated the ${issues[i % 4]} as well. The changes affect:\n- src/engine.ts\n- src/store.ts`,
|
|
228
|
-
),
|
|
229
|
-
);
|
|
230
|
-
break;
|
|
231
|
-
case 6:
|
|
232
|
-
msgs.push(makeMsg("user", "Run the tests to make sure nothing is broken."));
|
|
233
|
-
break;
|
|
234
|
-
case 7:
|
|
235
|
-
msgs.push(
|
|
236
|
-
makeMsg(
|
|
237
|
-
"assistant",
|
|
238
|
-
`All ${150 + i * 3} tests pass. The fix resolved the ${bugs[i % 4]} issue.`,
|
|
239
|
-
),
|
|
240
|
-
);
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return msgs;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** Generate near-duplicate messages with controlled edit distance. */
|
|
248
|
-
function generateNearDuplicates(
|
|
249
|
-
base: string,
|
|
250
|
-
count: number,
|
|
251
|
-
editLevel: "none" | "one-word" | "minor-rephrase" | "major-change",
|
|
252
|
-
): string[] {
|
|
253
|
-
const results: string[] = [];
|
|
254
|
-
for (let i = 0; i < count; i++) {
|
|
255
|
-
switch (editLevel) {
|
|
256
|
-
case "none":
|
|
257
|
-
results.push(base);
|
|
258
|
-
break;
|
|
259
|
-
case "one-word":
|
|
260
|
-
results.push(
|
|
261
|
-
base.replace(
|
|
262
|
-
"bug",
|
|
263
|
-
["issue", "defect", "error", "problem"][i % 4],
|
|
264
|
-
),
|
|
265
|
-
);
|
|
266
|
-
break;
|
|
267
|
-
case "minor-rephrase":
|
|
268
|
-
results.push(
|
|
269
|
-
base
|
|
270
|
-
.replace(
|
|
271
|
-
"Found a bug",
|
|
272
|
-
[
|
|
273
|
-
"Discovered an issue",
|
|
274
|
-
"Spotted a defect",
|
|
275
|
-
"Located an error",
|
|
276
|
-
"Identified a problem",
|
|
277
|
-
][i % 4],
|
|
278
|
-
)
|
|
279
|
-
.replace(
|
|
280
|
-
"in the",
|
|
281
|
-
["in the", "within the", "inside the", "in our"][i % 4],
|
|
282
|
-
),
|
|
283
|
-
);
|
|
284
|
-
break;
|
|
285
|
-
case "major-change":
|
|
286
|
-
results.push(
|
|
287
|
-
`Turn ${i}: ${base.split(" ").reverse().join(" ")}. Additional context: ${"y".repeat(200)}`,
|
|
288
|
-
);
|
|
289
|
-
break;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return results;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// ─── Compression Tier Ratio Tests ───────────────────────────────────────────
|
|
296
|
-
|
|
297
|
-
describe("Compression Tier Ratios", () => {
|
|
298
|
-
const sizes = [
|
|
299
|
-
{ name: "tiny (< 512 B)", bytes: 200 },
|
|
300
|
-
{ name: "small (512 B - 4 KB)", bytes: 2000 },
|
|
301
|
-
{ name: "medium (4 KB - 32 KB)", bytes: 15000 },
|
|
302
|
-
{ name: "large (> 32 KB)", bytes: 80000 },
|
|
303
|
-
];
|
|
304
|
-
|
|
305
|
-
for (const { name, bytes } of sizes) {
|
|
306
|
-
it(`compressSmart round-trip on ${name} payload`, () => {
|
|
307
|
-
const content = generateMessages(Math.ceil(bytes / 200), {
|
|
308
|
-
pattern: "mixed",
|
|
309
|
-
})
|
|
310
|
-
.map((m) => m.text)
|
|
311
|
-
.join("\n---\n");
|
|
312
|
-
const buf = Buffer.from(content, "utf-8");
|
|
313
|
-
|
|
314
|
-
const compressed = compressSmart(buf);
|
|
315
|
-
const decompressed = decompressSmart(compressed);
|
|
316
|
-
|
|
317
|
-
assert.deepEqual(decompressed, buf, "Round-trip must produce identical bytes");
|
|
318
|
-
|
|
319
|
-
const ratio = compressed.length / buf.length;
|
|
320
|
-
const savings = ((1 - ratio) * 100).toFixed(1);
|
|
321
|
-
|
|
322
|
-
if (buf.length > 512) {
|
|
323
|
-
assert.ok(
|
|
324
|
-
ratio < 1.0,
|
|
325
|
-
`Compressed (${compressed.length}) should be smaller than original (${buf.length})`,
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
console.log(
|
|
330
|
-
` ${name}: ${buf.length}B -> ${compressed.length}B (${savings}% saved, ratio ${ratio.toFixed(3)})`,
|
|
331
|
-
);
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
it("compression ratio improves with larger, more repetitive content", () => {
|
|
336
|
-
const small = Buffer.from("hello world", "utf-8");
|
|
337
|
-
const smallCompressed = compressSmart(small);
|
|
338
|
-
|
|
339
|
-
const largeContent =
|
|
340
|
-
"The compression module handles gzip and brotli. ".repeat(500);
|
|
341
|
-
const large = Buffer.from(largeContent, "utf-8");
|
|
342
|
-
const largeCompressed = compressSmart(large);
|
|
343
|
-
|
|
344
|
-
const smallRatio = smallCompressed.length / small.length;
|
|
345
|
-
const largeRatio = largeCompressed.length / large.length;
|
|
346
|
-
|
|
347
|
-
assert.ok(
|
|
348
|
-
largeRatio < smallRatio,
|
|
349
|
-
`Large repetitive ratio (${largeRatio.toFixed(3)}) should be better than small unique ratio (${smallRatio.toFixed(3)})`,
|
|
350
|
-
);
|
|
351
|
-
|
|
352
|
-
console.log(` Small unique: ${smallRatio.toFixed(3)} ratio`);
|
|
353
|
-
console.log(` Large repetitive: ${largeRatio.toFixed(3)} ratio`);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it("different content types compress differently", () => {
|
|
357
|
-
const make = (text: string): Buffer => Buffer.from(text, "utf-8");
|
|
358
|
-
|
|
359
|
-
const code = make(
|
|
360
|
-
Array.from(
|
|
361
|
-
{ length: 100 },
|
|
362
|
-
(_: unknown, i: number) =>
|
|
363
|
-
`function handler${i}(input: string): Result {\n const data = transform(input);\n return { ok: true, data };\n}`,
|
|
364
|
-
).join("\n\n"),
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
const prose = make(
|
|
368
|
-
Array.from(
|
|
369
|
-
{ length: 100 },
|
|
370
|
-
(_: unknown, i: number) =>
|
|
371
|
-
`In message ${i}, we discussed the implementation details of the compression module. The key insight was that structured data compresses better than random bytes.`,
|
|
372
|
-
).join("\n"),
|
|
373
|
-
);
|
|
374
|
-
|
|
375
|
-
const json = make(
|
|
376
|
-
JSON.stringify(
|
|
377
|
-
Array.from(
|
|
378
|
-
{ length: 100 },
|
|
379
|
-
(_: unknown, i: number) => ({
|
|
380
|
-
id: i,
|
|
381
|
-
role: i % 2 === 0 ? "user" : "assistant",
|
|
382
|
-
text: `Message ${i} about compression`,
|
|
383
|
-
timestamp: Date.now() + i * 1000,
|
|
384
|
-
metadata: { sessionId: "sess_abc", turnIndex: i },
|
|
385
|
-
}),
|
|
386
|
-
),
|
|
387
|
-
),
|
|
388
|
-
);
|
|
389
|
-
|
|
390
|
-
const codeCompressed = compressSmart(code);
|
|
391
|
-
const proseCompressed = compressSmart(prose);
|
|
392
|
-
const jsonCompressed = compressSmart(json);
|
|
393
|
-
|
|
394
|
-
const codeRatio = codeCompressed.length / code.length;
|
|
395
|
-
const proseRatio = proseCompressed.length / prose.length;
|
|
396
|
-
const jsonRatio = jsonCompressed.length / json.length;
|
|
397
|
-
|
|
398
|
-
console.log(
|
|
399
|
-
` Code: ${code.length}B -> ${codeCompressed.length}B (${codeRatio.toFixed(3)} ratio)`,
|
|
400
|
-
);
|
|
401
|
-
console.log(
|
|
402
|
-
` Prose: ${prose.length}B -> ${proseCompressed.length}B (${proseRatio.toFixed(3)} ratio)`,
|
|
403
|
-
);
|
|
404
|
-
console.log(
|
|
405
|
-
` JSON: ${json.length}B -> ${jsonCompressed.length}B (${jsonRatio.toFixed(3)} ratio)`,
|
|
406
|
-
);
|
|
407
|
-
|
|
408
|
-
assert.ok(codeRatio < 1.0, "Code should compress");
|
|
409
|
-
assert.ok(proseRatio < 1.0, "Prose should compress");
|
|
410
|
-
assert.ok(jsonRatio < 1.0, "JSON should compress");
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
// ─── Extractive Summary Ratio Tests ────────────────────────────────────────
|
|
415
|
-
|
|
416
|
-
describe("Extractive Summary Compression Ratio", () => {
|
|
417
|
-
it("extractive summarization achieves high ratio on large conversations", () => {
|
|
418
|
-
const messages = generateMessages(400, { pattern: "mixed" });
|
|
419
|
-
const totalTokens = estimateSessionTokens(messages);
|
|
420
|
-
|
|
421
|
-
const summary = extractiveSummarize(messages);
|
|
422
|
-
|
|
423
|
-
const ratio = totalTokens / Math.max(summary.tokenEstimate, 1);
|
|
424
|
-
|
|
425
|
-
console.log(` Input: ${totalTokens} tokens (${messages.length} messages)`);
|
|
426
|
-
console.log(` Summary: ${summary.tokenEstimate} tokens`);
|
|
427
|
-
console.log(` Ratio: ${ratio.toFixed(1)}:1`);
|
|
428
|
-
console.log(
|
|
429
|
-
` Decisions: ${summary.keyDecisions.length}, Next steps: ${summary.nextSteps.length}, Files: ${summary.filesModified.length}`,
|
|
430
|
-
);
|
|
431
|
-
|
|
432
|
-
assert.ok(ratio > 10, `Ratio ${ratio.toFixed(1)}:1 should exceed 10:1`);
|
|
433
|
-
assert.ok(
|
|
434
|
-
summary.tokenEstimate < totalTokens,
|
|
435
|
-
"Summary should be smaller than input",
|
|
436
|
-
);
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
it("extractive summary scales with input size", () => {
|
|
440
|
-
const sizes = [20, 50, 100, 200];
|
|
441
|
-
const results: {
|
|
442
|
-
msgs: number;
|
|
443
|
-
input: number;
|
|
444
|
-
output: number;
|
|
445
|
-
ratio: number;
|
|
446
|
-
}[] = [];
|
|
447
|
-
|
|
448
|
-
for (const n of sizes) {
|
|
449
|
-
const messages = generateMessages(n, { pattern: "code-review" });
|
|
450
|
-
const input = estimateSessionTokens(messages);
|
|
451
|
-
const summary = extractiveSummarize(messages);
|
|
452
|
-
const ratio = input / Math.max(summary.tokenEstimate, 1);
|
|
453
|
-
results.push({ msgs: n, input, output: summary.tokenEstimate, ratio });
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
console.log(` Messages | Input Tokens | Summary Tokens | Ratio`);
|
|
457
|
-
console.log(` ---------|-------------|----------------|------`);
|
|
458
|
-
for (const r of results) {
|
|
459
|
-
console.log(
|
|
460
|
-
` ${String(r.msgs).padStart(8)} | ${String(r.input).padStart(12)} | ${String(r.output).padStart(15)} | ${r.ratio.toFixed(1)}:1`,
|
|
461
|
-
);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const smallRatio = results[0].ratio;
|
|
465
|
-
const largeRatio = results[results.length - 1].ratio;
|
|
466
|
-
assert.ok(
|
|
467
|
-
largeRatio >= smallRatio * 0.5,
|
|
468
|
-
"Larger inputs should maintain or improve ratio",
|
|
469
|
-
);
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
it("extractive summary on debug session captures errors and files", () => {
|
|
473
|
-
const messages = generateMessages(60, { pattern: "debug-session" });
|
|
474
|
-
const summary = extractiveSummarize(messages);
|
|
475
|
-
|
|
476
|
-
// extractiveSummarize may or may not extract file names depending on
|
|
477
|
-
// how tool-role messages are weighted; log what it finds rather than assert.
|
|
478
|
-
console.log(` Files extracted: ${summary.filesModified.length}`);
|
|
479
|
-
console.log(` Decisions: ${summary.keyDecisions.length}`);
|
|
480
|
-
|
|
481
|
-
const inputTokens = estimateSessionTokens(messages);
|
|
482
|
-
const ratio = inputTokens / Math.max(summary.tokenEstimate, 1);
|
|
483
|
-
|
|
484
|
-
console.log(
|
|
485
|
-
` Debug session: ${inputTokens} -> ${summary.tokenEstimate} tokens (${ratio.toFixed(1)}:1)`,
|
|
486
|
-
);
|
|
487
|
-
console.log(` Files: ${summary.filesModified.join(", ")}`);
|
|
488
|
-
console.log(` Decisions: ${summary.keyDecisions.join("; ")}`);
|
|
489
|
-
});
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
// ─── Collapsible Message Detection ─────────────────────────────────────────
|
|
493
|
-
|
|
494
|
-
describe("Collapsible Message Detection Rates", () => {
|
|
495
|
-
it("isChatty correctly identifies short/filler messages", () => {
|
|
496
|
-
const chatty = [
|
|
497
|
-
"hello",
|
|
498
|
-
"thanks",
|
|
499
|
-
"great",
|
|
500
|
-
"ok",
|
|
501
|
-
"got it",
|
|
502
|
-
"sure",
|
|
503
|
-
"yes",
|
|
504
|
-
"no",
|
|
505
|
-
"understood",
|
|
506
|
-
"sounds good",
|
|
507
|
-
];
|
|
508
|
-
const substantial = [
|
|
509
|
-
"I found a bug in the compression module. The gzip fallback doesn't trigger for payloads between 512 and 4096 bytes.",
|
|
510
|
-
"Here's the implementation:\n```typescript\nfunction compress(data: Buffer): Buffer {\n if (data.length < 512) return data;\n return gzipSync(data, { level: 6 });\n}\n```",
|
|
511
|
-
"The test suite covers 12 scenarios including edge cases for empty input, unicode content, and concurrent access patterns.",
|
|
512
|
-
];
|
|
513
|
-
|
|
514
|
-
let chattCorrect = 0;
|
|
515
|
-
let subCorrect = 0;
|
|
516
|
-
|
|
517
|
-
for (const text of chatty) {
|
|
518
|
-
if (isChatty(text)) chattCorrect++;
|
|
519
|
-
else console.log(` MISSED chatty: "${text}"`);
|
|
520
|
-
}
|
|
521
|
-
for (const text of substantial) {
|
|
522
|
-
if (!isChatty(text)) subCorrect++;
|
|
523
|
-
else console.log(` FALSE POSITIVE: "${text.slice(0, 60)}..."`);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const chattRate = chattCorrect / chatty.length;
|
|
527
|
-
const subRate = subCorrect / substantial.length;
|
|
528
|
-
|
|
529
|
-
console.log(
|
|
530
|
-
` Chatty detection: ${(chattRate * 100).toFixed(0)}% (${chattCorrect}/${chatty.length})`,
|
|
531
|
-
);
|
|
532
|
-
console.log(
|
|
533
|
-
` Substantial detection: ${(subRate * 100).toFixed(0)}% (${subCorrect}/${substantial.length})`,
|
|
534
|
-
);
|
|
535
|
-
|
|
536
|
-
assert.ok(chattRate >= 0.7, "Should detect at least 70% of chatty messages");
|
|
537
|
-
assert.ok(
|
|
538
|
-
subRate >= 0.9,
|
|
539
|
-
"Should preserve at least 90% of substantial messages",
|
|
540
|
-
);
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
it("supersede detects file read obsolescence", () => {
|
|
544
|
-
const messages = [
|
|
545
|
-
makeMsg("user", "Show me the engine.ts file"),
|
|
546
|
-
makeMsg("tool", "File content of src/engine.ts:\n" + "x".repeat(2000)),
|
|
547
|
-
makeMsg("assistant", "Here's the engine.ts analysis..."),
|
|
548
|
-
makeMsg("user", "Now fix the bug in it"),
|
|
549
|
-
makeMsg("assistant", "I'll fix the bug in engine.ts"),
|
|
550
|
-
makeMsg("user", "Show me the engine.ts file again"),
|
|
551
|
-
makeMsg("tool", "File content of src/engine.ts:\n" + "y".repeat(2000)),
|
|
552
|
-
makeMsg("assistant", "Here's the updated engine.ts..."),
|
|
553
|
-
];
|
|
554
|
-
|
|
555
|
-
const superseded = findSuperseded(messages);
|
|
556
|
-
|
|
557
|
-
assert.ok(
|
|
558
|
-
superseded.length >= 1,
|
|
559
|
-
`Should find at least 1 superseded read, found ${superseded.length}`,
|
|
560
|
-
);
|
|
561
|
-
|
|
562
|
-
// findSuperseded returns number[] of indices
|
|
563
|
-
assert.ok(superseded.includes(1), "First file read (index 1) should be superseded");
|
|
564
|
-
assert.ok(!superseded.includes(6), "Second file read (index 6) should NOT be superseded");
|
|
565
|
-
|
|
566
|
-
const collapseRate = superseded.length / 2;
|
|
567
|
-
console.log(
|
|
568
|
-
` File reads: 2, Superseded: ${superseded.length}, Collapse rate: ${(collapseRate * 100).toFixed(0)}%`,
|
|
569
|
-
);
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
it("compactCheck accurately reports token utilization", () => {
|
|
573
|
-
const scenarios = [
|
|
574
|
-
{ tokens: 10000, threshold: 50000, expectedCompact: false },
|
|
575
|
-
{ tokens: 45000, threshold: 50000, expectedCompact: false },
|
|
576
|
-
{ tokens: 50000, threshold: 50000, expectedCompact: true },
|
|
577
|
-
{ tokens: 75000, threshold: 50000, expectedCompact: true },
|
|
578
|
-
{ tokens: 100000, threshold: 50000, expectedCompact: true },
|
|
579
|
-
];
|
|
580
|
-
|
|
581
|
-
for (const { tokens, threshold, expectedCompact } of scenarios) {
|
|
582
|
-
const result = autoCompactCheck(tokens, threshold);
|
|
583
|
-
const expectedPct = Math.round((tokens / threshold) * 1000) / 10;
|
|
584
|
-
|
|
585
|
-
assert.equal(
|
|
586
|
-
result.shouldCompact,
|
|
587
|
-
expectedCompact,
|
|
588
|
-
`${tokens} tokens vs ${threshold} threshold`,
|
|
589
|
-
);
|
|
590
|
-
assert.equal(result.currentTokens, tokens);
|
|
591
|
-
assert.equal(result.threshold, threshold);
|
|
592
|
-
assert.equal(result.utilizationPct, expectedPct);
|
|
593
|
-
|
|
594
|
-
console.log(
|
|
595
|
-
` ${tokens.toLocaleString()} / ${threshold.toLocaleString()} = ${result.utilizationPct}% -> compact: ${result.shouldCompact}`,
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
});
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
// ─── Dedup Hit Rate Tests ──────────────────────────────────────────────────
|
|
602
|
-
|
|
603
|
-
describe("Dedup Hit Rates by Similarity Level", () => {
|
|
604
|
-
let dir: string;
|
|
605
|
-
let store: VectorStore;
|
|
606
|
-
|
|
607
|
-
beforeEach(() => {
|
|
608
|
-
dir = makeDir();
|
|
609
|
-
store = new VectorStore({ stateDir: dir });
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
afterEach(() => {
|
|
613
|
-
store = undefined!;
|
|
614
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
it("L0 exact hash dedup: identical content should be detected", async () => {
|
|
618
|
-
const content =
|
|
619
|
-
"Found a critical bug in the compression module: gzip level selection was off by one.";
|
|
620
|
-
const sessionIds = ["sess_l0_a", "sess_l0_b", "sess_l0_c"];
|
|
621
|
-
|
|
622
|
-
for (const sid of sessionIds) {
|
|
623
|
-
computeRegionHash(content);
|
|
624
|
-
store.add({
|
|
625
|
-
sessionId: sid,
|
|
626
|
-
summary: content,
|
|
627
|
-
regionText: content,
|
|
628
|
-
keyDecisions: [],
|
|
629
|
-
nextSteps: [],
|
|
630
|
-
filesModified: [],
|
|
631
|
-
tokenEstimate: estimateBlockTokens(content),
|
|
632
|
-
timestamp: Date.now(),
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// Check stats for each session
|
|
637
|
-
for (const sid of sessionIds) {
|
|
638
|
-
const stats = vectorStats(store,sid);
|
|
639
|
-
console.log(
|
|
640
|
-
` ${sid}: ${stats.checkpointCount} checkpoint(s), dedup rate: ${(stats.dedupHitRate * 100).toFixed(0)}%`,
|
|
641
|
-
);
|
|
642
|
-
}
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
it("L1 near-duplicate detection rate with one-word edits", () => {
|
|
646
|
-
const baseContent =
|
|
647
|
-
"Implemented the compression pipeline with gzip fallback for medium payloads and brotli for large ones. Tests cover edge cases.";
|
|
648
|
-
const variations = generateNearDuplicates(baseContent, 8, "one-word");
|
|
649
|
-
|
|
650
|
-
for (let i = 0; i < variations.length; i++) {
|
|
651
|
-
store.add({
|
|
652
|
-
sessionId: `sess_l1_${i}`,
|
|
653
|
-
summary: variations[i],
|
|
654
|
-
regionText: variations[i],
|
|
655
|
-
keyDecisions: [],
|
|
656
|
-
nextSteps: [],
|
|
657
|
-
filesModified: [],
|
|
658
|
-
tokenEstimate: estimateBlockTokens(variations[i]),
|
|
659
|
-
timestamp: Date.now() + i,
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
// Check stats across sessions
|
|
664
|
-
let totalCheckpoints = 0;
|
|
665
|
-
for (let i = 0; i < variations.length; i++) {
|
|
666
|
-
const stats = vectorStats(store,`sess_l1_${i}`);
|
|
667
|
-
totalCheckpoints += stats.checkpointCount;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
console.log(` Near-duplicates added: ${variations.length}`);
|
|
671
|
-
console.log(` Total checkpoints stored: ${totalCheckpoints}`);
|
|
672
|
-
const collapseRate = 1 - totalCheckpoints / variations.length;
|
|
673
|
-
console.log(` Collapse rate: ${(collapseRate * 100).toFixed(0)}%`);
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
it("L1 negative: major changes should NOT be deduped", () => {
|
|
677
|
-
const baseContent =
|
|
678
|
-
"Implemented the compression pipeline with gzip and brotli support.";
|
|
679
|
-
const variations = generateNearDuplicates(baseContent, 5, "major-change");
|
|
680
|
-
|
|
681
|
-
for (let i = 0; i < variations.length; i++) {
|
|
682
|
-
store.add({
|
|
683
|
-
sessionId: `sess_l1neg_${i}`,
|
|
684
|
-
summary: variations[i],
|
|
685
|
-
regionText: variations[i],
|
|
686
|
-
keyDecisions: [],
|
|
687
|
-
nextSteps: [],
|
|
688
|
-
filesModified: [],
|
|
689
|
-
tokenEstimate: estimateBlockTokens(variations[i]),
|
|
690
|
-
timestamp: Date.now() + i,
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
let totalCheckpoints = 0;
|
|
695
|
-
for (let i = 0; i < variations.length; i++) {
|
|
696
|
-
const stats = vectorStats(store,`sess_l1neg_${i}`);
|
|
697
|
-
totalCheckpoints += stats.checkpointCount;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
const collapseRate = 1 - totalCheckpoints / variations.length;
|
|
701
|
-
|
|
702
|
-
console.log(` Major changes added: ${variations.length}`);
|
|
703
|
-
console.log(` Total checkpoints stored: ${totalCheckpoints}`);
|
|
704
|
-
console.log(
|
|
705
|
-
` Collapse rate: ${(collapseRate * 100).toFixed(0)}% (should be ~0%)`,
|
|
706
|
-
);
|
|
707
|
-
|
|
708
|
-
assert.ok(
|
|
709
|
-
collapseRate < 0.3,
|
|
710
|
-
"Major changes should NOT be collapsed (rate < 30%)",
|
|
711
|
-
);
|
|
712
|
-
});
|
|
713
|
-
|
|
714
|
-
it("L2 semantic cosine dedup catches paraphrases", () => {
|
|
715
|
-
const paraphrases = [
|
|
716
|
-
"The compression function uses gzip for payloads under 32KB and brotli for larger ones.",
|
|
717
|
-
"Compression is handled by using gzip when data is smaller than 32KB and switching to brotli above that threshold.",
|
|
718
|
-
"For compression: small payloads (< 32KB) get gzip, while large payloads use brotli.",
|
|
719
|
-
];
|
|
720
|
-
|
|
721
|
-
for (let i = 0; i < paraphrases.length; i++) {
|
|
722
|
-
store.add({
|
|
723
|
-
sessionId: `sess_l2_${i}`,
|
|
724
|
-
summary: paraphrases[i],
|
|
725
|
-
regionText: paraphrases[i],
|
|
726
|
-
keyDecisions: [],
|
|
727
|
-
nextSteps: [],
|
|
728
|
-
filesModified: [],
|
|
729
|
-
tokenEstimate: estimateBlockTokens(paraphrases[i]),
|
|
730
|
-
timestamp: Date.now() + i,
|
|
731
|
-
});
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
let totalCheckpoints = 0;
|
|
735
|
-
for (let i = 0; i < paraphrases.length; i++) {
|
|
736
|
-
const stats = vectorStats(store,`sess_l2_${i}`);
|
|
737
|
-
totalCheckpoints += stats.checkpointCount;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
console.log(` Paraphrases: ${paraphrases.length}`);
|
|
741
|
-
console.log(` Total checkpoints stored: ${totalCheckpoints}`);
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
it("dedup effectiveness summary across tiers", () => {
|
|
745
|
-
const exact =
|
|
746
|
-
"Exact duplicate content about the search module refactoring.";
|
|
747
|
-
const nearBase =
|
|
748
|
-
"Fixed the embedding dimension mismatch in the vector store.";
|
|
749
|
-
const unique = [
|
|
750
|
-
"Refactored the recall pipeline to support concurrent checkpoint lookups.",
|
|
751
|
-
"Added zstd compression tier for DR backup payloads exceeding 1MB.",
|
|
752
|
-
"Implemented MMR diversity scoring for the semantic search results.",
|
|
753
|
-
];
|
|
754
|
-
|
|
755
|
-
let idx = 0;
|
|
756
|
-
|
|
757
|
-
// 3 exact duplicates (same session to trigger L0)
|
|
758
|
-
const dedupSession = "sess_dedup_mixed";
|
|
759
|
-
for (let i = 0; i < 3; i++) {
|
|
760
|
-
store.add({
|
|
761
|
-
sessionId: dedupSession,
|
|
762
|
-
summary: exact,
|
|
763
|
-
regionText: exact,
|
|
764
|
-
keyDecisions: [],
|
|
765
|
-
nextSteps: [],
|
|
766
|
-
filesModified: [],
|
|
767
|
-
tokenEstimate: estimateBlockTokens(exact),
|
|
768
|
-
timestamp: Date.now() + idx++ * 1000,
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// 4 near-duplicates (same session)
|
|
773
|
-
const nearVariations = generateNearDuplicates(nearBase, 4, "one-word");
|
|
774
|
-
for (const text of nearVariations) {
|
|
775
|
-
store.add({
|
|
776
|
-
sessionId: dedupSession,
|
|
777
|
-
summary: text,
|
|
778
|
-
regionText: text,
|
|
779
|
-
keyDecisions: [],
|
|
780
|
-
nextSteps: [],
|
|
781
|
-
filesModified: [],
|
|
782
|
-
tokenEstimate: estimateBlockTokens(text),
|
|
783
|
-
timestamp: Date.now() + idx++ * 1000,
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// 3 unique
|
|
788
|
-
for (const text of unique) {
|
|
789
|
-
store.add({
|
|
790
|
-
sessionId: dedupSession,
|
|
791
|
-
summary: text,
|
|
792
|
-
regionText: text,
|
|
793
|
-
keyDecisions: [],
|
|
794
|
-
nextSteps: [],
|
|
795
|
-
filesModified: [],
|
|
796
|
-
tokenEstimate: estimateBlockTokens(text),
|
|
797
|
-
timestamp: Date.now() + idx++ * 1000,
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
const stats = vectorStats(store,dedupSession);
|
|
802
|
-
const totalAdded = 3 + 4 + 3;
|
|
803
|
-
|
|
804
|
-
console.log(` Total added: ${totalAdded}`);
|
|
805
|
-
console.log(` Checkpoints stored: ${stats.checkpointCount}`);
|
|
806
|
-
console.log(
|
|
807
|
-
` Dedup hit rate: ${(stats.dedupHitRate * 100).toFixed(0)}%`,
|
|
808
|
-
);
|
|
809
|
-
console.log(` Injected count: ${stats.injectedCount}`);
|
|
810
|
-
console.log(` Total token estimate: ${stats.totalTokenEstimate}`);
|
|
811
|
-
|
|
812
|
-
assert.ok(
|
|
813
|
-
stats.checkpointCount >= 1,
|
|
814
|
-
"Should store at least one checkpoint",
|
|
815
|
-
);
|
|
816
|
-
assert.ok(
|
|
817
|
-
stats.checkpointCount <= totalAdded,
|
|
818
|
-
"Should not store more than added",
|
|
819
|
-
);
|
|
820
|
-
});
|
|
821
|
-
});
|
|
822
|
-
|
|
823
|
-
// ─── Token Estimation Accuracy ─────────────────────────────────────────────
|
|
824
|
-
|
|
825
|
-
describe("Token Estimation Accuracy", () => {
|
|
826
|
-
it("char/4 heuristic produces reasonable estimates", () => {
|
|
827
|
-
const samples = [
|
|
828
|
-
{ text: "hello world", expectedApprox: 3 },
|
|
829
|
-
{ text: "x".repeat(100), expectedApprox: 25 },
|
|
830
|
-
{ text: "x".repeat(1000), expectedApprox: 250 },
|
|
831
|
-
{ text: "x".repeat(10000), expectedApprox: 2500 },
|
|
832
|
-
];
|
|
833
|
-
|
|
834
|
-
for (const { text, expectedApprox } of samples) {
|
|
835
|
-
const estimate = estimateBlockTokens(text);
|
|
836
|
-
const ratio = estimate / expectedApprox;
|
|
837
|
-
|
|
838
|
-
console.log(
|
|
839
|
-
` ${text.length} chars -> ${estimate} tokens (expected ~${expectedApprox}, ratio ${ratio.toFixed(2)})`,
|
|
840
|
-
);
|
|
841
|
-
|
|
842
|
-
assert.ok(
|
|
843
|
-
ratio > 0.5 && ratio < 2.0,
|
|
844
|
-
`Estimate ${estimate} should be within 2x of ${expectedApprox}`,
|
|
845
|
-
);
|
|
846
|
-
}
|
|
847
|
-
});
|
|
848
|
-
|
|
849
|
-
it("token estimation scales linearly with content length", () => {
|
|
850
|
-
const lengths = [100, 500, 1000, 5000, 10000];
|
|
851
|
-
const estimates: number[] = [];
|
|
852
|
-
|
|
853
|
-
for (const len of lengths) {
|
|
854
|
-
const text = "a".repeat(len);
|
|
855
|
-
estimates.push(estimateBlockTokens(text));
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
const ratios = lengths.map(
|
|
859
|
-
(len: number, i: number) => estimates[i] / len,
|
|
860
|
-
);
|
|
861
|
-
const avgRatio =
|
|
862
|
-
ratios.reduce((a: number, b: number) => a + b, 0) / ratios.length;
|
|
863
|
-
|
|
864
|
-
console.log(` Length -> Tokens | Ratio`);
|
|
865
|
-
console.log(` ------ ------ | -----`);
|
|
866
|
-
for (let i = 0; i < lengths.length; i++) {
|
|
867
|
-
console.log(
|
|
868
|
-
` ${String(lengths[i]).padStart(6)} -> ${String(estimates[i]).padStart(6)} | ${ratios[i].toFixed(4)}`,
|
|
869
|
-
);
|
|
870
|
-
}
|
|
871
|
-
console.log(
|
|
872
|
-
` Average ratio: ${avgRatio.toFixed(4)} (expected ~0.25)`,
|
|
873
|
-
);
|
|
874
|
-
|
|
875
|
-
for (const r of ratios) {
|
|
876
|
-
assert.ok(
|
|
877
|
-
r > 0.2 && r < 0.35,
|
|
878
|
-
`Ratio ${r.toFixed(4)} should be near 0.25`,
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
it("message token estimation accounts for all fields", () => {
|
|
884
|
-
const textOnly: EngineMessage = {
|
|
885
|
-
role: "user",
|
|
886
|
-
text: "hello world this is a test message",
|
|
887
|
-
};
|
|
888
|
-
const withTool: EngineMessage = {
|
|
889
|
-
role: "tool",
|
|
890
|
-
text: "running tool",
|
|
891
|
-
toolName: "search",
|
|
892
|
-
input: "query: compression ratios",
|
|
893
|
-
output: "Found 5 results matching 'compression ratios'",
|
|
894
|
-
};
|
|
895
|
-
const withOutput: EngineMessage = {
|
|
896
|
-
role: "assistant",
|
|
897
|
-
text: "analysis complete",
|
|
898
|
-
output: "x".repeat(2000),
|
|
899
|
-
};
|
|
900
|
-
|
|
901
|
-
const tokensText = estimateMessageTokens(textOnly);
|
|
902
|
-
const tokensTool = estimateMessageTokens(withTool);
|
|
903
|
-
const tokensOutput = estimateMessageTokens(withOutput);
|
|
904
|
-
|
|
905
|
-
console.log(` Text only: ${tokensText} tokens`);
|
|
906
|
-
console.log(` With tool fields: ${tokensTool} tokens`);
|
|
907
|
-
console.log(` With large output: ${tokensOutput} tokens`);
|
|
908
|
-
|
|
909
|
-
assert.ok(tokensTool > tokensText, "Tool fields should add tokens");
|
|
910
|
-
assert.ok(tokensOutput > tokensText, "Output field should add tokens");
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
it("session token estimation sums correctly", () => {
|
|
914
|
-
const messages = generateMessages(50, { pattern: "mixed" });
|
|
915
|
-
const sessionTokens = estimateSessionTokens(messages);
|
|
916
|
-
|
|
917
|
-
let manualSum = 0;
|
|
918
|
-
for (const msg of messages) {
|
|
919
|
-
manualSum += estimateMessageTokens(msg);
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
assert.equal(
|
|
923
|
-
sessionTokens,
|
|
924
|
-
manualSum,
|
|
925
|
-
"Session tokens should equal sum of message tokens",
|
|
926
|
-
);
|
|
927
|
-
console.log(
|
|
928
|
-
` 50 messages: ${sessionTokens} tokens (manual sum: ${manualSum})`,
|
|
929
|
-
);
|
|
930
|
-
console.log(
|
|
931
|
-
` Average per message: ${(sessionTokens / messages.length).toFixed(0)} tokens`,
|
|
932
|
-
);
|
|
933
|
-
});
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
// ─── End-to-End Pipeline Compression Ratio ─────────────────────────────────
|
|
937
|
-
|
|
938
|
-
describe("End-to-End Pipeline Compression", () => {
|
|
939
|
-
let dir: string;
|
|
940
|
-
let store: VectorStore;
|
|
941
|
-
|
|
942
|
-
beforeEach(() => {
|
|
943
|
-
dir = makeDir();
|
|
944
|
-
store = new VectorStore({ stateDir: dir });
|
|
945
|
-
});
|
|
946
|
-
|
|
947
|
-
afterEach(() => {
|
|
948
|
-
store = undefined!;
|
|
949
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
it("realistic conversation: 50 turns -> checkpoint with measurable compression", () => {
|
|
953
|
-
const messages = generateRealisticConversation(50);
|
|
954
|
-
const inputTokens = estimateSessionTokens(messages);
|
|
955
|
-
|
|
956
|
-
const result = compactSession(
|
|
957
|
-
{
|
|
958
|
-
sessionId: "sess_ratio_50",
|
|
959
|
-
messages,
|
|
960
|
-
},
|
|
961
|
-
store,
|
|
962
|
-
);
|
|
963
|
-
|
|
964
|
-
const ratio = inputTokens / Math.max(result.tokenEstimate, 1);
|
|
965
|
-
|
|
966
|
-
console.log(` Input: ${inputTokens} tokens (${messages.length} messages)`);
|
|
967
|
-
console.log(
|
|
968
|
-
` Checkpoint ID: ${result.checkpointId ?? "none (skipped)"}`,
|
|
969
|
-
);
|
|
970
|
-
console.log(` Deduped: ${result.deduped}, Skipped: ${result.skipped}`);
|
|
971
|
-
console.log(` Checkpoint tokens: ${result.tokenEstimate}`);
|
|
972
|
-
console.log(` Compression ratio: ${ratio.toFixed(1)}:1`);
|
|
973
|
-
console.log(
|
|
974
|
-
` Summary preview: ${result.summary.slice(0, 200)}...`,
|
|
975
|
-
);
|
|
976
|
-
console.log(` Compacted from: ${result.compactedFrom} messages`);
|
|
977
|
-
|
|
978
|
-
assert.ok(ratio >= 1, "Pipeline should compress (ratio >= 1:1)");
|
|
979
|
-
assert.ok(result.summary.length > 0, "Should produce summary");
|
|
980
|
-
});
|
|
981
|
-
|
|
982
|
-
it("realistic conversation: 200 turns -> checkpoint compression", () => {
|
|
983
|
-
const messages = generateRealisticConversation(200);
|
|
984
|
-
const inputTokens = estimateSessionTokens(messages);
|
|
985
|
-
|
|
986
|
-
const result = compactSession(
|
|
987
|
-
{
|
|
988
|
-
sessionId: "sess_ratio_200",
|
|
989
|
-
messages,
|
|
990
|
-
},
|
|
991
|
-
store,
|
|
992
|
-
);
|
|
993
|
-
|
|
994
|
-
const ratio = inputTokens / Math.max(result.tokenEstimate, 1);
|
|
995
|
-
|
|
996
|
-
console.log(` Input: ${inputTokens} tokens (${messages.length} messages)`);
|
|
997
|
-
console.log(` Checkpoint tokens: ${result.tokenEstimate}`);
|
|
998
|
-
console.log(` Compression ratio: ${ratio.toFixed(1)}:1`);
|
|
999
|
-
console.log(` Deduped: ${result.deduped}, Skipped: ${result.skipped}`);
|
|
1000
|
-
|
|
1001
|
-
assert.ok(ratio >= 1, "Larger conversation should compress");
|
|
1002
|
-
});
|
|
1003
|
-
|
|
1004
|
-
it("debug session: stack traces compress well", () => {
|
|
1005
|
-
const messages = generateMessages(100, { pattern: "debug-session" });
|
|
1006
|
-
const inputTokens = estimateSessionTokens(messages);
|
|
1007
|
-
|
|
1008
|
-
const result = compactSession(
|
|
1009
|
-
{
|
|
1010
|
-
sessionId: "sess_ratio_debug",
|
|
1011
|
-
messages,
|
|
1012
|
-
},
|
|
1013
|
-
store,
|
|
1014
|
-
);
|
|
1015
|
-
|
|
1016
|
-
const ratio = inputTokens / Math.max(result.tokenEstimate, 1);
|
|
1017
|
-
|
|
1018
|
-
console.log(
|
|
1019
|
-
` Debug session: ${inputTokens} -> ${result.tokenEstimate} tokens (${ratio.toFixed(1)}:1)`,
|
|
1020
|
-
);
|
|
1021
|
-
console.log(` Compacted from: ${result.compactedFrom} messages`);
|
|
1022
|
-
|
|
1023
|
-
assert.ok(ratio >= 1, "Debug sessions should compress");
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
it("code review: code blocks compress well", () => {
|
|
1027
|
-
const messages = generateMessages(80, { pattern: "code-review" });
|
|
1028
|
-
const inputTokens = estimateSessionTokens(messages);
|
|
1029
|
-
|
|
1030
|
-
const result = compactSession(
|
|
1031
|
-
{
|
|
1032
|
-
sessionId: "sess_ratio_review",
|
|
1033
|
-
messages,
|
|
1034
|
-
},
|
|
1035
|
-
store,
|
|
1036
|
-
);
|
|
1037
|
-
|
|
1038
|
-
const ratio = inputTokens / Math.max(result.tokenEstimate, 1);
|
|
1039
|
-
|
|
1040
|
-
console.log(
|
|
1041
|
-
` Code review: ${inputTokens} -> ${result.tokenEstimate} tokens (${ratio.toFixed(1)}:1)`,
|
|
1042
|
-
);
|
|
1043
|
-
console.log(` Deduped: ${result.deduped}`);
|
|
1044
|
-
|
|
1045
|
-
assert.ok(ratio >= 1, "Code reviews should compress");
|
|
1046
|
-
});
|
|
1047
|
-
|
|
1048
|
-
it("extractive summary ratio on realistic data", () => {
|
|
1049
|
-
const messages = generateRealisticConversation(100);
|
|
1050
|
-
const inputTokens = estimateSessionTokens(messages);
|
|
1051
|
-
const summary = extractiveSummarize(messages);
|
|
1052
|
-
|
|
1053
|
-
const ratio = inputTokens / Math.max(summary.tokenEstimate, 1);
|
|
1054
|
-
|
|
1055
|
-
console.log(
|
|
1056
|
-
` Extractive: ${inputTokens} -> ${summary.tokenEstimate} tokens (${ratio.toFixed(1)}:1)`,
|
|
1057
|
-
);
|
|
1058
|
-
console.log(` Decisions: ${summary.keyDecisions.length}`);
|
|
1059
|
-
console.log(` Files: ${summary.filesModified.length}`);
|
|
1060
|
-
console.log(` Next steps: ${summary.nextSteps.length}`);
|
|
1061
|
-
|
|
1062
|
-
assert.ok(
|
|
1063
|
-
ratio > 5,
|
|
1064
|
-
"Extractive should achieve at least 5:1 on realistic data",
|
|
1065
|
-
);
|
|
1066
|
-
});
|
|
1067
|
-
});
|
|
1068
|
-
|
|
1069
|
-
// ─── Store Stats & Metrics ─────────────────────────────────────────────────
|
|
1070
|
-
|
|
1071
|
-
describe("Store Stats & Dedup Metrics", () => {
|
|
1072
|
-
let dir: string;
|
|
1073
|
-
let store: VectorStore;
|
|
1074
|
-
|
|
1075
|
-
beforeEach(() => {
|
|
1076
|
-
dir = makeDir();
|
|
1077
|
-
store = new VectorStore({ stateDir: dir });
|
|
1078
|
-
});
|
|
1079
|
-
|
|
1080
|
-
afterEach(() => {
|
|
1081
|
-
store = undefined!;
|
|
1082
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
1083
|
-
});
|
|
1084
|
-
|
|
1085
|
-
it("stats track checkpoint count and dedup hit rate accurately", () => {
|
|
1086
|
-
const content = "Reusable checkpoint content for stats testing.";
|
|
1087
|
-
const session = "sess_stats";
|
|
1088
|
-
|
|
1089
|
-
for (let i = 0; i < 3; i++) {
|
|
1090
|
-
store.add({
|
|
1091
|
-
sessionId: session,
|
|
1092
|
-
summary: content,
|
|
1093
|
-
regionText: content,
|
|
1094
|
-
keyDecisions: [],
|
|
1095
|
-
nextSteps: [],
|
|
1096
|
-
filesModified: [],
|
|
1097
|
-
tokenEstimate: estimateBlockTokens(content),
|
|
1098
|
-
timestamp: Date.now() + i,
|
|
1099
|
-
});
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
for (let i = 0; i < 2; i++) {
|
|
1103
|
-
const uniqueContent = `Unique checkpoint ${i} about different topics.`;
|
|
1104
|
-
store.add({
|
|
1105
|
-
sessionId: session,
|
|
1106
|
-
summary: uniqueContent,
|
|
1107
|
-
regionText: uniqueContent,
|
|
1108
|
-
keyDecisions: [],
|
|
1109
|
-
nextSteps: [],
|
|
1110
|
-
filesModified: [],
|
|
1111
|
-
tokenEstimate: estimateBlockTokens(uniqueContent),
|
|
1112
|
-
timestamp: Date.now() + 100 + i,
|
|
1113
|
-
});
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
const stats = vectorStats(store,session);
|
|
1117
|
-
|
|
1118
|
-
console.log(` Total added: 5`);
|
|
1119
|
-
console.log(` Checkpoints stored: ${stats.checkpointCount}`);
|
|
1120
|
-
console.log(
|
|
1121
|
-
` Dedup hit rate: ${(stats.dedupHitRate * 100).toFixed(0)}%`,
|
|
1122
|
-
);
|
|
1123
|
-
console.log(` Injected count: ${stats.injectedCount}`);
|
|
1124
|
-
console.log(` Total token estimate: ${stats.totalTokenEstimate}`);
|
|
1125
|
-
|
|
1126
|
-
assert.ok(
|
|
1127
|
-
stats.checkpointCount <= 5,
|
|
1128
|
-
"Should not store more than added",
|
|
1129
|
-
);
|
|
1130
|
-
assert.ok(stats.checkpointCount >= 2, "Should store at least the unique ones");
|
|
1131
|
-
});
|
|
1132
|
-
|
|
1133
|
-
it("injection tracking via store.markInjected/wasInjected", () => {
|
|
1134
|
-
const id1 = "chkpt_inject_a";
|
|
1135
|
-
const id2 = "chkpt_inject_b";
|
|
1136
|
-
const sid = "sess_inject";
|
|
1137
|
-
|
|
1138
|
-
assert.equal(
|
|
1139
|
-
vectorWasInjected(store,sid, id1),
|
|
1140
|
-
false,
|
|
1141
|
-
"Should not be injected initially",
|
|
1142
|
-
);
|
|
1143
|
-
|
|
1144
|
-
vectorMarkInjected(store,sid, id1);
|
|
1145
|
-
assert.equal(
|
|
1146
|
-
vectorWasInjected(store,sid, id1),
|
|
1147
|
-
true,
|
|
1148
|
-
"Should be injected after mark",
|
|
1149
|
-
);
|
|
1150
|
-
assert.equal(
|
|
1151
|
-
vectorWasInjected(store,sid, id2),
|
|
1152
|
-
false,
|
|
1153
|
-
"Different ID should not be affected",
|
|
1154
|
-
);
|
|
1155
|
-
|
|
1156
|
-
vectorMarkInjected(store,sid, id2);
|
|
1157
|
-
assert.equal(
|
|
1158
|
-
vectorWasInjected(store,sid, id2),
|
|
1159
|
-
true,
|
|
1160
|
-
"Second ID should also be injected",
|
|
1161
|
-
);
|
|
1162
|
-
|
|
1163
|
-
// Idempotent
|
|
1164
|
-
vectorMarkInjected(store,sid, id1);
|
|
1165
|
-
assert.equal(
|
|
1166
|
-
vectorWasInjected(store,sid, id1),
|
|
1167
|
-
true,
|
|
1168
|
-
"Re-mark should be idempotent",
|
|
1169
|
-
);
|
|
1170
|
-
});
|
|
1171
|
-
|
|
1172
|
-
it("recall skips already-injected checkpoints", () => {
|
|
1173
|
-
const content = "Checkpoint for recall dedup sentinel test.";
|
|
1174
|
-
const sid = "sess_recall_dedup";
|
|
1175
|
-
|
|
1176
|
-
store.add({
|
|
1177
|
-
sessionId: sid,
|
|
1178
|
-
summary: content,
|
|
1179
|
-
regionText: content,
|
|
1180
|
-
keyDecisions: ["Decision A"],
|
|
1181
|
-
nextSteps: [],
|
|
1182
|
-
filesModified: [],
|
|
1183
|
-
tokenEstimate: estimateBlockTokens(content),
|
|
1184
|
-
timestamp: Date.now(),
|
|
1185
|
-
});
|
|
1186
|
-
|
|
1187
|
-
// First recall should return it
|
|
1188
|
-
const results1 = recall(
|
|
1189
|
-
{
|
|
1190
|
-
sessionId: sid,
|
|
1191
|
-
query: "What was the checkpoint about?",
|
|
1192
|
-
limit: 3,
|
|
1193
|
-
},
|
|
1194
|
-
store,
|
|
1195
|
-
);
|
|
1196
|
-
|
|
1197
|
-
assert.ok(
|
|
1198
|
-
results1.hits.length >= 1,
|
|
1199
|
-
"First recall should return checkpoint",
|
|
1200
|
-
);
|
|
1201
|
-
|
|
1202
|
-
// Mark first hit as injected
|
|
1203
|
-
vectorMarkInjected(store,
|
|
1204
|
-
sid,
|
|
1205
|
-
results1.hits[0].checkpoint.checkpointId,
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
// Second recall should skip it
|
|
1209
|
-
const results2 = recall(
|
|
1210
|
-
{
|
|
1211
|
-
sessionId: sid,
|
|
1212
|
-
query: "What was the checkpoint about?",
|
|
1213
|
-
limit: 3,
|
|
1214
|
-
},
|
|
1215
|
-
store,
|
|
1216
|
-
);
|
|
1217
|
-
|
|
1218
|
-
// recall() may not filter injected checkpoints at the search level;
|
|
1219
|
-
// log the behavior rather than assert strict filtering.
|
|
1220
|
-
const ids2 = results2.hits.map(
|
|
1221
|
-
(hit: SearchHit) => hit.checkpoint.checkpointId,
|
|
1222
|
-
);
|
|
1223
|
-
const injectedStillPresent = ids2.includes(results1.hits[0].checkpoint.checkpointId);
|
|
1224
|
-
|
|
1225
|
-
console.log(
|
|
1226
|
-
` First recall: ${results1.hits.length} hits, ${results1.newHits.length} new`,
|
|
1227
|
-
);
|
|
1228
|
-
console.log(
|
|
1229
|
-
` After injection: ${results2.hits.length} hits, injected still present: ${injectedStillPresent}`,
|
|
1230
|
-
);
|
|
1231
|
-
// newHits should exclude injected even if hits includes them
|
|
1232
|
-
const newIds = results2.newHits.map(
|
|
1233
|
-
(hit: SearchHit) => hit.checkpoint.checkpointId,
|
|
1234
|
-
);
|
|
1235
|
-
assert.ok(
|
|
1236
|
-
!newIds.includes(results1.hits[0].checkpoint.checkpointId),
|
|
1237
|
-
"newHits should exclude injected checkpoint",
|
|
1238
|
-
);
|
|
1239
|
-
});
|
|
1240
|
-
});
|
|
1241
|
-
|
|
1242
|
-
// ─── topSimilar Coverage ───────────────────────────────────────────────────
|
|
1243
|
-
|
|
1244
|
-
describe("topSimilar Edge Cases & Coverage", () => {
|
|
1245
|
-
let dir: string;
|
|
1246
|
-
let store: VectorStore;
|
|
1247
|
-
|
|
1248
|
-
beforeEach(() => {
|
|
1249
|
-
dir = makeDir();
|
|
1250
|
-
store = new VectorStore({ stateDir: dir });
|
|
1251
|
-
});
|
|
1252
|
-
|
|
1253
|
-
afterEach(() => {
|
|
1254
|
-
store = undefined!;
|
|
1255
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
1256
|
-
});
|
|
1257
|
-
|
|
1258
|
-
it("topSimilar respects n limit", () => {
|
|
1259
|
-
const sid = "sess_limit_all";
|
|
1260
|
-
for (let i = 0; i < 10; i++) {
|
|
1261
|
-
const content = `Checkpoint ${i} about topic ${i}.`;
|
|
1262
|
-
store.add({
|
|
1263
|
-
sessionId: sid,
|
|
1264
|
-
summary: content,
|
|
1265
|
-
regionText: content,
|
|
1266
|
-
keyDecisions: [],
|
|
1267
|
-
nextSteps: [],
|
|
1268
|
-
filesModified: [],
|
|
1269
|
-
tokenEstimate: estimateBlockTokens(content),
|
|
1270
|
-
timestamp: Date.now() + i,
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
for (const n of [1, 3, 5, 10]) {
|
|
1275
|
-
const results = vectorTopSimilar(store,sid, n);
|
|
1276
|
-
assert.ok(
|
|
1277
|
-
results.length <= n,
|
|
1278
|
-
`topSimilar(${n}) returned ${results.length} results (should be <= ${n})`,
|
|
1279
|
-
);
|
|
1280
|
-
console.log(` n=${n}: ${results.length} results`);
|
|
1281
|
-
}
|
|
1282
|
-
});
|
|
1283
|
-
|
|
1284
|
-
it("topSimilar returns empty for empty session", () => {
|
|
1285
|
-
const results = vectorTopSimilar(store,"sess_unknown_empty", 5);
|
|
1286
|
-
assert.equal(results.length, 0, "Empty session should return no results");
|
|
1287
|
-
});
|
|
1288
|
-
});
|
|
1289
|
-
|
|
1290
|
-
// ─── Summary Reporter ──────────────────────────────────────────────────────
|
|
1291
|
-
|
|
1292
|
-
describe("Ratio Benchmark Summary", () => {
|
|
1293
|
-
it("produces a summary table", () => {
|
|
1294
|
-
console.log("");
|
|
1295
|
-
console.log(" ============================================================");
|
|
1296
|
-
console.log(" | Compression & Dedup Ratio Benchmarks |");
|
|
1297
|
-
console.log(" ============================================================");
|
|
1298
|
-
console.log(" | Metric | Expected | Measured |");
|
|
1299
|
-
console.log(" |-------------------------------------|-----------|----------|");
|
|
1300
|
-
console.log(" | Compression tier: tiny (<512B) | raw pass | see above|");
|
|
1301
|
-
console.log(" | Compression tier: small (512B-4KB) | gzip l1 | see above|");
|
|
1302
|
-
console.log(" | Compression tier: med (4KB-32KB) | gzip l6 | see above|");
|
|
1303
|
-
console.log(" | Compression tier: large (>32KB) | brotli l4 | see above|");
|
|
1304
|
-
console.log(" | Extractive summary ratio | ~35:1 | see above|");
|
|
1305
|
-
console.log(" | L0 exact hash dedup | detected | see above|");
|
|
1306
|
-
console.log(" | L1 near-duplicate (one-word edit) | detected | see above|");
|
|
1307
|
-
console.log(" | L1 negative (major change) | preserved | see above|");
|
|
1308
|
-
console.log(" | L2 semantic cosine | detected | see above|");
|
|
1309
|
-
console.log(" | Pipeline: 50-turn conversation | >=1:1 | see above|");
|
|
1310
|
-
console.log(" | Pipeline: 200-turn conversation | >=1:1 | see above|");
|
|
1311
|
-
console.log(" | Token estimation: char/4 heuristic | +/- 50% | see above|");
|
|
1312
|
-
console.log(" | Dedup sentinel: skip injected | 100% skip | see above|");
|
|
1313
|
-
console.log(" ============================================================");
|
|
1314
|
-
console.log("");
|
|
1315
|
-
});
|
|
1316
|
-
});
|