onbuzz 4.9.13 → 4.10.0
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/node_modules/glob/README.md +31 -5
- package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/glob.js +2 -1
- package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
- package/node_modules/glob/dist/commonjs/index.min.js +3 -3
- package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
- package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/pattern.js +4 -0
- package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
- package/node_modules/glob/dist/esm/glob.d.ts +8 -0
- package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/glob.js +2 -1
- package/node_modules/glob/dist/esm/glob.js.map +1 -1
- package/node_modules/glob/dist/esm/index.min.js +3 -3
- package/node_modules/glob/dist/esm/index.min.js.map +4 -4
- package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
- package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/pattern.js +4 -0
- package/node_modules/glob/dist/esm/pattern.js.map +1 -1
- package/node_modules/{@isaacs → glob/node_modules}/balanced-match/README.md +7 -10
- package/node_modules/{@isaacs → glob/node_modules}/balanced-match/package.json +7 -18
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/README.md +3 -6
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.js +6 -4
- package/node_modules/glob/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -0
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.js +6 -4
- package/node_modules/glob/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
- package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/package.json +11 -7
- package/node_modules/glob/node_modules/minimatch/README.md +76 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +4 -2
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +309 -55
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +4 -4
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +81 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +232 -134
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +8 -8
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +4 -2
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +309 -55
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +4 -4
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +81 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +232 -134
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -1
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +8 -8
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
- package/node_modules/glob/node_modules/minimatch/package.json +17 -11
- package/node_modules/glob/package.json +10 -13
- package/node_modules/minipass/LICENSE.md +55 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
- package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/minipass/dist/commonjs/index.js +13 -3
- package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
- package/node_modules/minipass/dist/esm/index.d.ts +12 -16
- package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
- package/node_modules/minipass/dist/esm/index.js +3 -1
- package/node_modules/minipass/dist/esm/index.js.map +1 -1
- package/node_modules/minipass/package.json +9 -14
- package/node_modules/path-scurry/node_modules/lru-cache/README.md +96 -10
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.cjs.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +109 -32
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +334 -197
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +4 -4
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.mjs.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +109 -32
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +333 -196
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +1 -1
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +4 -4
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts +1400 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts +12 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/package.json +71 -18
- package/node_modules/path-scurry/package.json +8 -24
- package/package.json +1 -1
- package/scripts/debug-balance-probe.mjs +35 -35
- package/scripts/push-image.sh +43 -43
- package/scripts/setup-acr.sh +65 -65
- package/scripts/verify-optional-deps.js +96 -1
- package/src/__tests__/composioCliFlags.test.js +239 -239
- package/src/analyzers/CSSAnalyzer.js +298 -297
- package/src/analyzers/ConfigValidator.js +691 -690
- package/src/analyzers/ESLintAnalyzer.js +320 -320
- package/src/analyzers/JavaScriptAnalyzer.js +260 -261
- package/src/analyzers/PrettierFormatter.js +246 -247
- package/src/analyzers/PythonAnalyzer.js +283 -283
- package/src/analyzers/SecurityAnalyzer.js +729 -729
- package/src/analyzers/SparrowAnalyzer.js +341 -341
- package/src/analyzers/TypeScriptAnalyzer.js +247 -247
- package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -41
- package/src/analyzers/__tests__/ConfigValidator.test.js +362 -362
- package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -40
- package/src/analyzers/__tests__/PythonAnalyzer.test.js +205 -208
- package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -303
- package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -187
- package/src/analyzers/codeCloneDetector/analyzer.js +344 -344
- package/src/analyzers/codeCloneDetector/detector.js +250 -250
- package/src/analyzers/codeCloneDetector/index.js +194 -192
- package/src/analyzers/codeCloneDetector/parser.js +199 -199
- package/src/core/__tests__/agentPool.test.js +866 -866
- package/src/core/__tests__/agentPoolAutoResume.test.js +209 -209
- package/src/core/__tests__/agentPoolWakeOnMessage.test.js +315 -315
- package/src/core/__tests__/agentScheduler.emptyResponseChatStall.test.js +213 -213
- package/src/core/__tests__/agentScheduler.errorCategorisation.test.js +246 -246
- package/src/core/__tests__/agentScheduler.firstChunkTimeout.test.js +138 -138
- package/src/core/__tests__/agentScheduler.modeTransitions.test.js +233 -233
- package/src/core/__tests__/agentScheduler.nativePromptPick.test.js +319 -319
- package/src/core/__tests__/agentScheduler.taskLifecycleInstruction.test.js +78 -78
- package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -258
- package/src/core/__tests__/flowCheckpointStore.test.js +140 -140
- package/src/core/__tests__/flowEndToEnd.test.js +565 -565
- package/src/core/__tests__/flowFieldMapping.test.js +188 -189
- package/src/core/__tests__/flowLintClientMirror.test.js +96 -98
- package/src/core/__tests__/flowSavePayload.test.js +170 -169
- package/src/core/__tests__/flowTemplates.test.js +311 -311
- package/src/core/__tests__/flowVersionStore.test.js +123 -123
- package/src/core/__tests__/messageProcessor.test.js +669 -669
- package/src/core/__tests__/stateManager.test.js +0 -1
- package/src/core/agentPool.js +2474 -2475
- package/src/core/agentScheduler.js +1 -4
- package/src/core/contextManager.js +708 -708
- package/src/core/flowExecutor.js +1510 -1510
- package/src/core/flowFieldMapping.js +136 -138
- package/src/core/messageProcessor.js +953 -954
- package/src/core/orchestrator.js +593 -595
- package/src/core/stateManager.js +1765 -1752
- package/src/index.js +1221 -1221
- package/src/interfaces/__tests__/archivedAgentDelete.test.js +207 -207
- package/src/interfaces/__tests__/bulkAgentRoute.test.js +361 -361
- package/src/interfaces/__tests__/imageServing.test.js +228 -228
- package/src/interfaces/__tests__/remoteSessionAuth.test.js +308 -308
- package/src/interfaces/__tests__/videoJobsRoutes.test.js +178 -179
- package/src/interfaces/__tests__/webServer.marketplace.test.js +629 -629
- package/src/interfaces/schedulerRoutes.js +50 -50
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +341 -350
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -156
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +325 -330
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +385 -388
- package/src/interfaces/terminal/api/session.js +265 -266
- package/src/interfaces/terminal/api/websocket.js +496 -497
- package/src/interfaces/terminal/components/AgentCreator.js +691 -705
- package/src/interfaces/terminal/components/AgentEditor.js +676 -678
- package/src/interfaces/terminal/components/AgentSwitcher.js +331 -330
- package/src/interfaces/terminal/components/ErrorPanel.js +263 -264
- package/src/interfaces/terminal/components/Header.js +28 -28
- package/src/interfaces/terminal/components/Layout.js +598 -603
- package/src/interfaces/terminal/components/MessageList.js +280 -281
- package/src/interfaces/terminal/components/SettingsPanel.js +410 -415
- package/src/interfaces/terminal/components/StatusBar.js +2 -0
- package/src/interfaces/terminal/index.js +168 -168
- package/src/interfaces/terminal/state/useAgentControl.js +496 -496
- package/src/interfaces/terminal/state/useAgents.js +537 -537
- package/src/interfaces/terminal/state/useMessages.js +629 -630
- package/src/interfaces/terminal/state/useTools.js +554 -554
- package/src/interfaces/terminal/utils/debugLogger.js +44 -44
- package/src/interfaces/terminal/utils/settingsStorage.js +232 -232
- package/src/interfaces/webServer.js +7578 -7579
- package/src/interfaces/webServer.js.bak +7046 -7046
- package/src/modules/fileExplorer/__tests__/zipDownload.test.js +237 -237
- package/src/modules/fileExplorer/controller.js +470 -469
- package/src/modules/fileExplorer/routes.js +285 -286
- package/src/modules/widget/__tests__/isDisabled.test.js +41 -41
- package/src/modules/widget/__tests__/routes.test.js +677 -678
- package/src/modules/widget/__tests__/runtime.test.js +401 -401
- package/src/modules/widget/__tests__/versioning.test.js +309 -309
- package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -565
- package/src/modules/widget/__tests__/widgetTool.test.js +316 -316
- package/src/modules/widget/routes.js +435 -435
- package/src/modules/widget/runtime/bundle.js +640 -640
- package/src/modules/widget/runtime/webComponentBundle.js +470 -470
- package/src/modules/widget/schema.js +182 -181
- package/src/modules/widget/widgetTool.js +1389 -1389
- package/src/services/__tests__/agentActivityService.test.js +401 -402
- package/src/services/__tests__/benchmarkService.test.js +184 -184
- package/src/services/__tests__/contextInjectionService.test.js +246 -246
- package/src/services/__tests__/conversationQuery.test.js +721 -723
- package/src/services/__tests__/credentialVault.test.js +469 -469
- package/src/services/__tests__/discordService.integration.test.js +638 -639
- package/src/services/__tests__/flowContextService.test.js +590 -590
- package/src/services/__tests__/memoryService.test.js +1 -1
- package/src/services/__tests__/messageSource.test.js +380 -380
- package/src/services/__tests__/modelRouterNaming.test.js +111 -111
- package/src/services/__tests__/projectDetector.test.js +34 -34
- package/src/services/__tests__/promptService.test.js +242 -242
- package/src/services/__tests__/telegramService.test.js +941 -941
- package/src/services/__tests__/tokenCountingService.test.js +48 -48
- package/src/services/agentActivityService.js +419 -420
- package/src/services/aiService.js +2997 -3001
- package/src/services/apiKeyManager.js +359 -359
- package/src/services/benchmarkService.js +196 -196
- package/src/services/codebaseKnowledgeService.js +2 -2
- package/src/services/composioService.js +738 -738
- package/src/services/conversationCompactionService.js +1258 -1257
- package/src/services/credentialVault.js +685 -685
- package/src/services/discordService.js +792 -793
- package/src/services/embeddings/__tests__/azureCustomProvider.test.js +232 -232
- package/src/services/embeddings/__tests__/embeddingService.test.js +417 -417
- package/src/services/embeddings/__tests__/localProvider.test.js +263 -263
- package/src/services/embeddings/autoRecall.js +218 -219
- package/src/services/embeddings/indexers/__tests__/agentIndexer.test.js +232 -232
- package/src/services/embeddings/indexers/__tests__/memoryIndexer.test.js +418 -418
- package/src/services/embeddings/indexers/__tests__/reminisceIndexer.test.js +356 -357
- package/src/services/embeddings/indexers/__tests__/skillsIndexer.test.js +145 -145
- package/src/services/embeddings/indexers/__tests__/taskIndexer.test.js +146 -146
- package/src/services/embeddings/indexers/composioIndexer.js +279 -279
- package/src/services/embeddings/providerInterface.js +206 -206
- package/src/services/embeddings/providers/localProvider.js +11 -7
- package/src/services/embeddings/providers/openaiProvider.js +101 -101
- package/src/services/embeddings/vectorStore/inMemoryJsonStore.js +356 -356
- package/src/services/errorHandler.js +809 -809
- package/src/services/flowContextService.js +586 -586
- package/src/services/grounding/MockAdapter.js +125 -125
- package/src/services/modelRouterService.js +26 -31
- package/src/services/modelsService.js +322 -322
- package/src/services/ollamaService.js +452 -452
- package/src/services/projectDetector.js +403 -404
- package/src/services/promptService.js +418 -418
- package/src/services/qualityInspector.js +795 -795
- package/src/services/scheduleService.js +726 -726
- package/src/services/serviceRegistry.js +386 -386
- package/src/services/telegrafBot.js +174 -174
- package/src/services/telegramService.js +1972 -1972
- package/src/services/visualEditorBridge.js +1033 -1033
- package/src/services/visualEditorServer.js +1769 -1774
- package/src/services/whatsappService.js +667 -668
- package/src/tools/__tests__/agentCommunicationTool.findAgent.test.js +226 -226
- package/src/tools/__tests__/agentCommunicationTool.test.js +3 -3
- package/src/tools/__tests__/agentDelayTool.test.js +342 -342
- package/src/tools/__tests__/baseTool.test.js +3 -3
- package/src/tools/__tests__/codeMapTool.test.js +915 -915
- package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -309
- package/src/tools/__tests__/fileTreeTool.test.js +274 -274
- package/src/tools/__tests__/filesystemTool.test.js +815 -815
- package/src/tools/__tests__/foundryWebSearchTool.test.js +252 -252
- package/src/tools/__tests__/imageTool.validator.test.js +194 -194
- package/src/tools/__tests__/jobDoneTool.test.js +580 -581
- package/src/tools/__tests__/memoryTool.forgetStale.test.js +272 -272
- package/src/tools/__tests__/memoryTool.reminisce.test.js +2 -2
- package/src/tools/__tests__/memoryTool.reminisceSemanticSearch.test.js +301 -301
- package/src/tools/__tests__/memoryTool.semanticSearch.test.js +405 -405
- package/src/tools/__tests__/memoryTool.teamPool.test.js +293 -293
- package/src/tools/__tests__/memoryTool.test.js +1 -1
- package/src/tools/__tests__/seekTool.test.js +282 -282
- package/src/tools/__tests__/skillsTool.search.test.js +164 -164
- package/src/tools/__tests__/skillsTool.test.js +226 -226
- package/src/tools/__tests__/staticAnalysisTool.test.js +509 -509
- package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -137
- package/src/tools/__tests__/taskManagerTool.search.test.js +143 -143
- package/src/tools/__tests__/taskManagerTool.test.js +866 -866
- package/src/tools/__tests__/terminalTool.test.js +448 -448
- package/src/tools/__tests__/toolShapeForgiveness.test.js +259 -260
- package/src/tools/__tests__/userPromptTool.test.js +297 -297
- package/src/tools/__tests__/videoTool.jobs.test.js +147 -147
- package/src/tools/__tests__/webTool.e2e.test.js +609 -603
- package/src/tools/__tests__/webTool.unit.test.js +195 -195
- package/src/tools/__tests__/webTool.visionModel.test.js +75 -75
- package/src/tools/agentCommunicationTool.js +8 -10
- package/src/tools/agentDelayTool.js +496 -497
- package/src/tools/asyncToolManager.js +602 -603
- package/src/tools/baseTool.js +12 -11
- package/src/tools/cloneDetectionTool.js +576 -581
- package/src/tools/codeMapTool.js +0 -6
- package/src/tools/composioTool.js +617 -617
- package/src/tools/dependencyResolverTool.js +1211 -1212
- package/src/tools/desktop/DesktopTool.js +629 -638
- package/src/tools/desktop/__tests__/DesktopTool.e2e.test.js +306 -306
- package/src/tools/desktop/__tests__/DesktopTool.test.js +507 -507
- package/src/tools/desktop/__tests__/osController.test.js +364 -364
- package/src/tools/desktop/osController.js +491 -491
- package/src/tools/docxTool.js +623 -623
- package/src/tools/excelTool.js +636 -636
- package/src/tools/fileContentReplaceTool.js +5 -7
- package/src/tools/fileSystemTool.js +12 -19
- package/src/tools/fileTreeTool.js +840 -840
- package/src/tools/foundryWebSearchTool.js +273 -273
- package/src/tools/helpTool.js +198 -198
- package/src/tools/imageTool.js +1397 -1397
- package/src/tools/importAnalyzerTool.js +1056 -1056
- package/src/tools/jobDoneTool.js +495 -495
- package/src/tools/memoryTool.js +1 -1
- package/src/tools/office/pres/__tests__/presSystem.test.js +365 -365
- package/src/tools/office/pres/archetypes/agenda.js +61 -61
- package/src/tools/office/pres/archetypes/bentoGrid.js +218 -219
- package/src/tools/office/pres/archetypes/bigStat.js +140 -142
- package/src/tools/office/pres/archetypes/closing.js +70 -70
- package/src/tools/office/pres/archetypes/hero.js +70 -70
- package/src/tools/office/pres/archetypes/productHero.js +93 -94
- package/src/tools/office/pres/archetypes/table.js +73 -74
- package/src/tools/office/pres/backgrounds/orb.js +66 -66
- package/src/tools/office/pres/components.js +422 -423
- package/src/tools/officeTool.js +441 -441
- package/src/tools/pdfTool.js +625 -627
- package/src/tools/platformControlTool.js +1081 -1081
- package/src/tools/seekTool.js +917 -918
- package/src/tools/skillsTool.js +1 -1
- package/src/tools/staticAnalysisTool.js +2143 -2146
- package/src/tools/taskManagerTool.js +3324 -3324
- package/src/tools/terminalTool.js +2615 -2618
- package/src/tools/videoTool.js +1303 -1303
- package/src/tools/visionTool.js +508 -508
- package/src/tools/visualEditorTool.js +1289 -1290
- package/src/tools/webTool.js +3368 -3368
- package/src/tools/whatsappTool.js +464 -464
- package/src/types/__tests__/agent.test.js +499 -499
- package/src/types/__tests__/contextReference.test.js +606 -606
- package/src/types/__tests__/conversation.test.js +555 -555
- package/src/types/__tests__/toolCommand.test.js +584 -584
- package/src/types/contextReference.js +974 -971
- package/src/types/conversation.js +729 -729
- package/src/types/toolCommand.js +746 -746
- package/src/utilities/__tests__/attachmentValidator.test.js +80 -80
- package/src/utilities/__tests__/auditReport.test.js +328 -328
- package/src/utilities/__tests__/directoryAccessManager.test.js +388 -388
- package/src/utilities/__tests__/jsonRepair.test.js +103 -104
- package/src/utilities/__tests__/modeTransitionReasons.test.js +105 -105
- package/src/utilities/__tests__/platformUtils.test.js +80 -87
- package/src/utilities/__tests__/structuredFileValidator.test.js +261 -263
- package/src/utilities/__tests__/toolConstants.test.js +92 -94
- package/src/utilities/__tests__/useIsTouchDevice.detect.test.js +114 -114
- package/src/utilities/__tests__/webUiUtilSync.test.js +117 -117
- package/src/utilities/attachmentValidator.js +284 -288
- package/src/utilities/authCache.js.backup-1779570472481 +121 -121
- package/src/utilities/browserStealth.js +631 -630
- package/src/utilities/configManager.js +616 -617
- package/src/utilities/directoryAccessManager.js +564 -565
- package/src/utilities/fileProcessor.js +308 -307
- package/src/utilities/humanBehavior.js +454 -453
- package/src/utilities/logger.js +479 -479
- package/src/utilities/structuredFileValidator.js +696 -699
- package/src/utilities/tagParser.js +5 -10
- package/src/utilities/userDataDir.js +308 -308
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +0 -1
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +0 -1
- package/node_modules/minipass/LICENSE +0 -15
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/LICENSE.md +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/LICENSE +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/package.json +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts.map +0 -0
- /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/package.json +0 -0
|
@@ -1,356 +1,356 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* InMemoryJsonStore — concrete VectorStore backed by a single JSON file.
|
|
3
|
-
*
|
|
4
|
-
* Design choices:
|
|
5
|
-
* - Vectors held in memory as Float32Array (~3 KB each at 768 dims).
|
|
6
|
-
* At our scale (~10K vectors per agent) that's <30 MB resident.
|
|
7
|
-
* - Cosine similarity reduces to a dot product because the base-class
|
|
8
|
-
* normalizes every stored + queried vector. Tight loop in V8.
|
|
9
|
-
* - Single-file persistence with atomic write (write to `.tmp`, then
|
|
10
|
-
* fs.rename — atomic on the same filesystem). No partial reads.
|
|
11
|
-
* - File format is human-inspectable JSON (verbose but debuggable).
|
|
12
|
-
* The 4× size penalty vs binary is fine until we hit 100K+ vectors,
|
|
13
|
-
* at which point sqlite-vec is the planned drop-in.
|
|
14
|
-
* - Substring search is plain `String.includes()` on `metadata.text`
|
|
15
|
-
* after lowercasing both sides. No regex, matches the codebase's
|
|
16
|
-
* "native string ops" preference.
|
|
17
|
-
* - Fingerprint/dimension drift on load: silently empties the store
|
|
18
|
-
* (we treat the on-disk file as garbage). The orchestrator's
|
|
19
|
-
* responsibility is to backfill from source.
|
|
20
|
-
*
|
|
21
|
-
* Concurrency: not safe for multiple writers on the same file from
|
|
22
|
-
* different processes. Loxia is single-process per agent state, so
|
|
23
|
-
* this is fine. If we ever multiprocess, switch to sqlite-vec.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
import fsp from 'fs/promises';
|
|
27
|
-
import path from 'path';
|
|
28
|
-
import { reciprocalRankFusion } from './storeInterface.js';
|
|
29
|
-
|
|
30
|
-
const FILE_VERSION = 1;
|
|
31
|
-
|
|
32
|
-
export class InMemoryJsonStore {
|
|
33
|
-
/**
|
|
34
|
-
* @param {object} opts
|
|
35
|
-
* @param {string} opts.filePath - Absolute path to the .vec.json file.
|
|
36
|
-
* @param {number} opts.dimensions - Expected vector dimensionality.
|
|
37
|
-
* @param {string} opts.modelFingerprint - From EmbeddingProvider.getModelFingerprint().
|
|
38
|
-
* @param {object} [opts.logger]
|
|
39
|
-
*/
|
|
40
|
-
constructor({ filePath, dimensions, modelFingerprint, logger = null }) {
|
|
41
|
-
if (!filePath) throw new Error('InMemoryJsonStore requires filePath');
|
|
42
|
-
if (!Number.isInteger(dimensions) || dimensions <= 0) {
|
|
43
|
-
throw new Error('InMemoryJsonStore requires positive integer dimensions');
|
|
44
|
-
}
|
|
45
|
-
if (!modelFingerprint) throw new Error('InMemoryJsonStore requires modelFingerprint');
|
|
46
|
-
|
|
47
|
-
this._filePath = filePath;
|
|
48
|
-
this._dimensions = dimensions;
|
|
49
|
-
this._modelFingerprint = modelFingerprint;
|
|
50
|
-
this._logger = logger;
|
|
51
|
-
|
|
52
|
-
/** @type {Array<{id: string, vector: Float32Array, metadata: object}>} */
|
|
53
|
-
this._rows = [];
|
|
54
|
-
/** @type {Map<string, number>} id → index into _rows */
|
|
55
|
-
this._idIndex = new Map();
|
|
56
|
-
this._loaded = false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Load from disk. Idempotent; safe to call repeatedly. If the file
|
|
61
|
-
* doesn't exist, or its fingerprint / dimensions don't match the
|
|
62
|
-
* constructor args, the store starts empty (caller re-embeds).
|
|
63
|
-
*/
|
|
64
|
-
async load() {
|
|
65
|
-
if (this._loaded) return;
|
|
66
|
-
this._loaded = true;
|
|
67
|
-
|
|
68
|
-
let raw;
|
|
69
|
-
try {
|
|
70
|
-
raw = await fsp.readFile(this._filePath, 'utf8');
|
|
71
|
-
} catch (err) {
|
|
72
|
-
if (err?.code === 'ENOENT') return; // first run, file doesn't exist
|
|
73
|
-
this._logger?.warn?.('[vectorStore] failed to read store; starting empty', { path: this._filePath, err: err.message });
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
let parsed;
|
|
78
|
-
try {
|
|
79
|
-
parsed = JSON.parse(raw);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
this._logger?.warn?.('[vectorStore] corrupt JSON; starting empty', { path: this._filePath, err: err.message });
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (parsed?.version !== FILE_VERSION) {
|
|
86
|
-
this._logger?.info?.('[vectorStore] file version mismatch; starting empty', {
|
|
87
|
-
path: this._filePath, found: parsed?.version, expected: FILE_VERSION,
|
|
88
|
-
});
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (parsed.dimensions !== this._dimensions) {
|
|
92
|
-
this._logger?.info?.('[vectorStore] dimension mismatch; starting empty (re-embed required)', {
|
|
93
|
-
path: this._filePath, fileDims: parsed.dimensions, expectedDims: this._dimensions,
|
|
94
|
-
});
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (parsed.modelFingerprint !== this._modelFingerprint) {
|
|
98
|
-
this._logger?.info?.('[vectorStore] fingerprint mismatch; starting empty (re-embed required)', {
|
|
99
|
-
path: this._filePath, fileFp: parsed.modelFingerprint, expectedFp: this._modelFingerprint,
|
|
100
|
-
});
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (!Array.isArray(parsed.rows)) return;
|
|
104
|
-
|
|
105
|
-
for (const r of parsed.rows) {
|
|
106
|
-
if (!r || typeof r.id !== 'string' || !Array.isArray(r.vector)) continue;
|
|
107
|
-
if (r.vector.length !== this._dimensions) continue;
|
|
108
|
-
this._rows.push({
|
|
109
|
-
id: r.id,
|
|
110
|
-
vector: Float32Array.from(r.vector),
|
|
111
|
-
metadata: r.metadata || {},
|
|
112
|
-
});
|
|
113
|
-
this._idIndex.set(r.id, this._rows.length - 1);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async stats() {
|
|
118
|
-
let newestTs = null;
|
|
119
|
-
for (const r of this._rows) {
|
|
120
|
-
const ts = r.metadata?.createdAt;
|
|
121
|
-
if (typeof ts === 'string' && (!newestTs || ts > newestTs)) {
|
|
122
|
-
newestTs = ts;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
count: this._rows.length,
|
|
127
|
-
dimensions: this._dimensions,
|
|
128
|
-
modelFingerprint: this._modelFingerprint,
|
|
129
|
-
lastIndexedAt: newestTs,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async upsert(id, vector, metadata = {}) {
|
|
134
|
-
this._assertLoaded();
|
|
135
|
-
this._validateVector(vector);
|
|
136
|
-
if (typeof id !== 'string' || !id) throw new Error('upsert: id must be a non-empty string');
|
|
137
|
-
|
|
138
|
-
const existing = this._idIndex.get(id);
|
|
139
|
-
if (existing !== undefined) {
|
|
140
|
-
this._rows[existing] = { id, vector, metadata };
|
|
141
|
-
} else {
|
|
142
|
-
this._rows.push({ id, vector, metadata });
|
|
143
|
-
this._idIndex.set(id, this._rows.length - 1);
|
|
144
|
-
}
|
|
145
|
-
await this._flush();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async upsertBatch(rows) {
|
|
149
|
-
this._assertLoaded();
|
|
150
|
-
if (!Array.isArray(rows)) throw new Error('upsertBatch: rows must be an array');
|
|
151
|
-
for (const r of rows) {
|
|
152
|
-
this._validateVector(r?.vector);
|
|
153
|
-
if (typeof r?.id !== 'string' || !r.id) throw new Error('upsertBatch: each row needs an id');
|
|
154
|
-
const existing = this._idIndex.get(r.id);
|
|
155
|
-
if (existing !== undefined) {
|
|
156
|
-
this._rows[existing] = { id: r.id, vector: r.vector, metadata: r.metadata || {} };
|
|
157
|
-
} else {
|
|
158
|
-
this._rows.push({ id: r.id, vector: r.vector, metadata: r.metadata || {} });
|
|
159
|
-
this._idIndex.set(r.id, this._rows.length - 1);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
await this._flush();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async delete(id) {
|
|
166
|
-
this._assertLoaded();
|
|
167
|
-
const idx = this._idIndex.get(id);
|
|
168
|
-
if (idx === undefined) return;
|
|
169
|
-
// Swap-remove for O(1). Update the moved row's index.
|
|
170
|
-
const last = this._rows.length - 1;
|
|
171
|
-
if (idx !== last) {
|
|
172
|
-
this._rows[idx] = this._rows[last];
|
|
173
|
-
this._idIndex.set(this._rows[idx].id, idx);
|
|
174
|
-
}
|
|
175
|
-
this._rows.pop();
|
|
176
|
-
this._idIndex.delete(id);
|
|
177
|
-
await this._flush();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Delete every row whose metadata satisfies `predicate`. Used when a
|
|
182
|
-
* single source object (e.g. a conversation message) produced multiple
|
|
183
|
-
* chunks under the convention `${sourceId}#${chunkIndex}` — calling
|
|
184
|
-
* `delete()` per chunk would require N round-trips and N flushes.
|
|
185
|
-
*
|
|
186
|
-
* Returns the number of rows removed. One atomic flush at the end.
|
|
187
|
-
*
|
|
188
|
-
* @param {(metadata: object) => boolean} predicate
|
|
189
|
-
* @returns {Promise<number>}
|
|
190
|
-
*/
|
|
191
|
-
async deleteWhere(predicate) {
|
|
192
|
-
this._assertLoaded();
|
|
193
|
-
if (typeof predicate !== 'function') {
|
|
194
|
-
throw new Error('deleteWhere: predicate must be a function');
|
|
195
|
-
}
|
|
196
|
-
let removed = 0;
|
|
197
|
-
// Walk from the tail so swap-remove indices stay valid as we splice.
|
|
198
|
-
for (let i = this._rows.length - 1; i >= 0; i--) {
|
|
199
|
-
const row = this._rows[i];
|
|
200
|
-
let match
|
|
201
|
-
try { match = !!predicate(row.metadata); } catch { match = false; }
|
|
202
|
-
if (!match) continue;
|
|
203
|
-
const last = this._rows.length - 1;
|
|
204
|
-
if (i !== last) {
|
|
205
|
-
this._rows[i] = this._rows[last];
|
|
206
|
-
this._idIndex.set(this._rows[i].id, i);
|
|
207
|
-
}
|
|
208
|
-
this._rows.pop();
|
|
209
|
-
this._idIndex.delete(row.id);
|
|
210
|
-
removed++;
|
|
211
|
-
}
|
|
212
|
-
if (removed > 0) await this._flush();
|
|
213
|
-
return removed;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Cosine query. Vectors are normalized, so cosine = dot product.
|
|
218
|
-
* Linear scan — fine up to ~100K rows. For larger corpora we swap
|
|
219
|
-
* to sqlite-vec (HNSW) without changing this interface.
|
|
220
|
-
*
|
|
221
|
-
* @param {Float32Array} queryVector
|
|
222
|
-
* @param {object} [opts]
|
|
223
|
-
* @param {number} [opts.topK=10]
|
|
224
|
-
* @param {(metadata: object) => boolean} [opts.filter]
|
|
225
|
-
* @param {(baseScore: number, metadata: object) => number} [opts.scoring]
|
|
226
|
-
* Optional per-row score adjuster — used by the multi-signal
|
|
227
|
-
* ranking layer (recency + access boosts). See
|
|
228
|
-
* `vectorStore/scoring.js`. Identity when omitted.
|
|
229
|
-
*/
|
|
230
|
-
async query(queryVector, { topK = 10, filter = null, scoring = null } = {}) {
|
|
231
|
-
this._assertLoaded();
|
|
232
|
-
this._validateVector(queryVector);
|
|
233
|
-
const adjust = typeof scoring === 'function' ? scoring : null;
|
|
234
|
-
|
|
235
|
-
const scored = [];
|
|
236
|
-
for (const row of this._rows) {
|
|
237
|
-
if (filter && !filter(row.metadata)) continue;
|
|
238
|
-
const base = dot(queryVector, row.vector);
|
|
239
|
-
const score = adjust ? adjust(base, row.metadata) : base;
|
|
240
|
-
scored.push({ id: row.id, score, metadata: row.metadata });
|
|
241
|
-
}
|
|
242
|
-
scored.sort((a, b) => b.score - a.score);
|
|
243
|
-
return scored.slice(0, topK);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Hybrid query: rank-fuse semantic results with substring matches
|
|
248
|
-
* over `metadata.text`. RRF is used because raw scores live on
|
|
249
|
-
* different scales (cosine vs boolean) and RRF only needs ranks.
|
|
250
|
-
*
|
|
251
|
-
* @param {Float32Array} queryVector
|
|
252
|
-
* @param {string} queryText - For substring matching.
|
|
253
|
-
* @param {object} [opts]
|
|
254
|
-
* @param {number} [opts.topK=10]
|
|
255
|
-
* @param {Function} [opts.filter] - Same shape as query().
|
|
256
|
-
* @returns {Promise<Array<{id, score, metadata}>>}
|
|
257
|
-
*/
|
|
258
|
-
async hybridQuery(queryVector, queryText, { topK = 10, filter = null, scoring = null } = {}) {
|
|
259
|
-
this._assertLoaded();
|
|
260
|
-
// The semantic candidate set is the one that benefits from scoring
|
|
261
|
-
// adjustments. The substring path is rank-only, so reweighting
|
|
262
|
-
// wouldn't affect RRF anyway.
|
|
263
|
-
const semantic = await this.query(queryVector, { topK: topK * 4, filter, scoring });
|
|
264
|
-
const substring = await this._substringMatches(queryText, { topK: topK * 4, filter });
|
|
265
|
-
const fused = reciprocalRankFusion([semantic, substring], { topK });
|
|
266
|
-
// Hydrate ids back to full rows.
|
|
267
|
-
return fused.map(({ id, score }) => {
|
|
268
|
-
const idx = this._idIndex.get(id);
|
|
269
|
-
const row = idx !== undefined ? this._rows[idx] : null;
|
|
270
|
-
return { id, score, metadata: row?.metadata || {} };
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/** @private */
|
|
275
|
-
async _substringMatches(queryText, { topK, filter }) {
|
|
276
|
-
if (typeof queryText !== 'string' || !queryText) return [];
|
|
277
|
-
const needle = queryText.toLowerCase();
|
|
278
|
-
const matches = [];
|
|
279
|
-
for (const row of this._rows) {
|
|
280
|
-
if (filter && !filter(row.metadata)) continue;
|
|
281
|
-
const haystack = String(row.metadata?.text || '').toLowerCase();
|
|
282
|
-
if (haystack.length === 0) continue;
|
|
283
|
-
const idx = haystack.indexOf(needle);
|
|
284
|
-
if (idx === -1) continue;
|
|
285
|
-
// Score = inverse position (earlier matches rank higher). Used only
|
|
286
|
-
// for ordering inside this list — final fusion ignores raw scores.
|
|
287
|
-
matches.push({ id: row.id, score: 1 / (1 + idx) });
|
|
288
|
-
}
|
|
289
|
-
matches.sort((a, b) => b.score - a.score);
|
|
290
|
-
return matches.slice(0, topK);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async drop() {
|
|
294
|
-
this._assertLoaded();
|
|
295
|
-
this._rows = [];
|
|
296
|
-
this._idIndex.clear();
|
|
297
|
-
try {
|
|
298
|
-
await fsp.unlink(this._filePath);
|
|
299
|
-
} catch (err) {
|
|
300
|
-
if (err?.code !== 'ENOENT') {
|
|
301
|
-
this._logger?.warn?.('[vectorStore] drop(): could not unlink file', { path: this._filePath, err: err.message });
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Force a flush. Public because callers occasionally want to ensure
|
|
308
|
-
* persistence before a critical handoff (e.g. shutdown).
|
|
309
|
-
*/
|
|
310
|
-
async flush() {
|
|
311
|
-
await this._flush();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/** @private */
|
|
315
|
-
_assertLoaded() {
|
|
316
|
-
if (!this._loaded) {
|
|
317
|
-
throw new Error('VectorStore not loaded — call await store.load() first');
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/** @private */
|
|
322
|
-
_validateVector(v) {
|
|
323
|
-
if (!(v instanceof Float32Array)) {
|
|
324
|
-
throw new Error('vector must be a Float32Array');
|
|
325
|
-
}
|
|
326
|
-
if (v.length !== this._dimensions) {
|
|
327
|
-
throw new Error(`vector has wrong dimensions (got ${v.length}, expected ${this._dimensions})`);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/** @private */
|
|
332
|
-
async _flush() {
|
|
333
|
-
const payload = {
|
|
334
|
-
version: FILE_VERSION,
|
|
335
|
-
dimensions: this._dimensions,
|
|
336
|
-
modelFingerprint: this._modelFingerprint,
|
|
337
|
-
savedAt: new Date().toISOString(),
|
|
338
|
-
rows: this._rows.map(r => ({
|
|
339
|
-
id: r.id,
|
|
340
|
-
vector: Array.from(r.vector), // JSON can't hold typed arrays
|
|
341
|
-
metadata: r.metadata,
|
|
342
|
-
})),
|
|
343
|
-
};
|
|
344
|
-
const tmpPath = `${this._filePath}.tmp`;
|
|
345
|
-
await fsp.mkdir(path.dirname(this._filePath), { recursive: true });
|
|
346
|
-
await fsp.writeFile(tmpPath, JSON.stringify(payload));
|
|
347
|
-
await fsp.rename(tmpPath, this._filePath);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/** Dot product over two equal-length Float32Arrays. Hot path — no allocation. */
|
|
352
|
-
function dot(a, b) {
|
|
353
|
-
let s = 0;
|
|
354
|
-
for (let i = 0; i < a.length; i++) s += a[i] * b[i];
|
|
355
|
-
return s;
|
|
356
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* InMemoryJsonStore — concrete VectorStore backed by a single JSON file.
|
|
3
|
+
*
|
|
4
|
+
* Design choices:
|
|
5
|
+
* - Vectors held in memory as Float32Array (~3 KB each at 768 dims).
|
|
6
|
+
* At our scale (~10K vectors per agent) that's <30 MB resident.
|
|
7
|
+
* - Cosine similarity reduces to a dot product because the base-class
|
|
8
|
+
* normalizes every stored + queried vector. Tight loop in V8.
|
|
9
|
+
* - Single-file persistence with atomic write (write to `.tmp`, then
|
|
10
|
+
* fs.rename — atomic on the same filesystem). No partial reads.
|
|
11
|
+
* - File format is human-inspectable JSON (verbose but debuggable).
|
|
12
|
+
* The 4× size penalty vs binary is fine until we hit 100K+ vectors,
|
|
13
|
+
* at which point sqlite-vec is the planned drop-in.
|
|
14
|
+
* - Substring search is plain `String.includes()` on `metadata.text`
|
|
15
|
+
* after lowercasing both sides. No regex, matches the codebase's
|
|
16
|
+
* "native string ops" preference.
|
|
17
|
+
* - Fingerprint/dimension drift on load: silently empties the store
|
|
18
|
+
* (we treat the on-disk file as garbage). The orchestrator's
|
|
19
|
+
* responsibility is to backfill from source.
|
|
20
|
+
*
|
|
21
|
+
* Concurrency: not safe for multiple writers on the same file from
|
|
22
|
+
* different processes. Loxia is single-process per agent state, so
|
|
23
|
+
* this is fine. If we ever multiprocess, switch to sqlite-vec.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import fsp from 'fs/promises';
|
|
27
|
+
import path from 'path';
|
|
28
|
+
import { reciprocalRankFusion } from './storeInterface.js';
|
|
29
|
+
|
|
30
|
+
const FILE_VERSION = 1;
|
|
31
|
+
|
|
32
|
+
export class InMemoryJsonStore {
|
|
33
|
+
/**
|
|
34
|
+
* @param {object} opts
|
|
35
|
+
* @param {string} opts.filePath - Absolute path to the .vec.json file.
|
|
36
|
+
* @param {number} opts.dimensions - Expected vector dimensionality.
|
|
37
|
+
* @param {string} opts.modelFingerprint - From EmbeddingProvider.getModelFingerprint().
|
|
38
|
+
* @param {object} [opts.logger]
|
|
39
|
+
*/
|
|
40
|
+
constructor({ filePath, dimensions, modelFingerprint, logger = null }) {
|
|
41
|
+
if (!filePath) throw new Error('InMemoryJsonStore requires filePath');
|
|
42
|
+
if (!Number.isInteger(dimensions) || dimensions <= 0) {
|
|
43
|
+
throw new Error('InMemoryJsonStore requires positive integer dimensions');
|
|
44
|
+
}
|
|
45
|
+
if (!modelFingerprint) throw new Error('InMemoryJsonStore requires modelFingerprint');
|
|
46
|
+
|
|
47
|
+
this._filePath = filePath;
|
|
48
|
+
this._dimensions = dimensions;
|
|
49
|
+
this._modelFingerprint = modelFingerprint;
|
|
50
|
+
this._logger = logger;
|
|
51
|
+
|
|
52
|
+
/** @type {Array<{id: string, vector: Float32Array, metadata: object}>} */
|
|
53
|
+
this._rows = [];
|
|
54
|
+
/** @type {Map<string, number>} id → index into _rows */
|
|
55
|
+
this._idIndex = new Map();
|
|
56
|
+
this._loaded = false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Load from disk. Idempotent; safe to call repeatedly. If the file
|
|
61
|
+
* doesn't exist, or its fingerprint / dimensions don't match the
|
|
62
|
+
* constructor args, the store starts empty (caller re-embeds).
|
|
63
|
+
*/
|
|
64
|
+
async load() {
|
|
65
|
+
if (this._loaded) return;
|
|
66
|
+
this._loaded = true;
|
|
67
|
+
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = await fsp.readFile(this._filePath, 'utf8');
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (err?.code === 'ENOENT') return; // first run, file doesn't exist
|
|
73
|
+
this._logger?.warn?.('[vectorStore] failed to read store; starting empty', { path: this._filePath, err: err.message });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = JSON.parse(raw);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
this._logger?.warn?.('[vectorStore] corrupt JSON; starting empty', { path: this._filePath, err: err.message });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (parsed?.version !== FILE_VERSION) {
|
|
86
|
+
this._logger?.info?.('[vectorStore] file version mismatch; starting empty', {
|
|
87
|
+
path: this._filePath, found: parsed?.version, expected: FILE_VERSION,
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (parsed.dimensions !== this._dimensions) {
|
|
92
|
+
this._logger?.info?.('[vectorStore] dimension mismatch; starting empty (re-embed required)', {
|
|
93
|
+
path: this._filePath, fileDims: parsed.dimensions, expectedDims: this._dimensions,
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (parsed.modelFingerprint !== this._modelFingerprint) {
|
|
98
|
+
this._logger?.info?.('[vectorStore] fingerprint mismatch; starting empty (re-embed required)', {
|
|
99
|
+
path: this._filePath, fileFp: parsed.modelFingerprint, expectedFp: this._modelFingerprint,
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (!Array.isArray(parsed.rows)) return;
|
|
104
|
+
|
|
105
|
+
for (const r of parsed.rows) {
|
|
106
|
+
if (!r || typeof r.id !== 'string' || !Array.isArray(r.vector)) continue;
|
|
107
|
+
if (r.vector.length !== this._dimensions) continue;
|
|
108
|
+
this._rows.push({
|
|
109
|
+
id: r.id,
|
|
110
|
+
vector: Float32Array.from(r.vector),
|
|
111
|
+
metadata: r.metadata || {},
|
|
112
|
+
});
|
|
113
|
+
this._idIndex.set(r.id, this._rows.length - 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async stats() {
|
|
118
|
+
let newestTs = null;
|
|
119
|
+
for (const r of this._rows) {
|
|
120
|
+
const ts = r.metadata?.createdAt;
|
|
121
|
+
if (typeof ts === 'string' && (!newestTs || ts > newestTs)) {
|
|
122
|
+
newestTs = ts;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
count: this._rows.length,
|
|
127
|
+
dimensions: this._dimensions,
|
|
128
|
+
modelFingerprint: this._modelFingerprint,
|
|
129
|
+
lastIndexedAt: newestTs,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async upsert(id, vector, metadata = {}) {
|
|
134
|
+
this._assertLoaded();
|
|
135
|
+
this._validateVector(vector);
|
|
136
|
+
if (typeof id !== 'string' || !id) throw new Error('upsert: id must be a non-empty string');
|
|
137
|
+
|
|
138
|
+
const existing = this._idIndex.get(id);
|
|
139
|
+
if (existing !== undefined) {
|
|
140
|
+
this._rows[existing] = { id, vector, metadata };
|
|
141
|
+
} else {
|
|
142
|
+
this._rows.push({ id, vector, metadata });
|
|
143
|
+
this._idIndex.set(id, this._rows.length - 1);
|
|
144
|
+
}
|
|
145
|
+
await this._flush();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async upsertBatch(rows) {
|
|
149
|
+
this._assertLoaded();
|
|
150
|
+
if (!Array.isArray(rows)) throw new Error('upsertBatch: rows must be an array');
|
|
151
|
+
for (const r of rows) {
|
|
152
|
+
this._validateVector(r?.vector);
|
|
153
|
+
if (typeof r?.id !== 'string' || !r.id) throw new Error('upsertBatch: each row needs an id');
|
|
154
|
+
const existing = this._idIndex.get(r.id);
|
|
155
|
+
if (existing !== undefined) {
|
|
156
|
+
this._rows[existing] = { id: r.id, vector: r.vector, metadata: r.metadata || {} };
|
|
157
|
+
} else {
|
|
158
|
+
this._rows.push({ id: r.id, vector: r.vector, metadata: r.metadata || {} });
|
|
159
|
+
this._idIndex.set(r.id, this._rows.length - 1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
await this._flush();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async delete(id) {
|
|
166
|
+
this._assertLoaded();
|
|
167
|
+
const idx = this._idIndex.get(id);
|
|
168
|
+
if (idx === undefined) return;
|
|
169
|
+
// Swap-remove for O(1). Update the moved row's index.
|
|
170
|
+
const last = this._rows.length - 1;
|
|
171
|
+
if (idx !== last) {
|
|
172
|
+
this._rows[idx] = this._rows[last];
|
|
173
|
+
this._idIndex.set(this._rows[idx].id, idx);
|
|
174
|
+
}
|
|
175
|
+
this._rows.pop();
|
|
176
|
+
this._idIndex.delete(id);
|
|
177
|
+
await this._flush();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Delete every row whose metadata satisfies `predicate`. Used when a
|
|
182
|
+
* single source object (e.g. a conversation message) produced multiple
|
|
183
|
+
* chunks under the convention `${sourceId}#${chunkIndex}` — calling
|
|
184
|
+
* `delete()` per chunk would require N round-trips and N flushes.
|
|
185
|
+
*
|
|
186
|
+
* Returns the number of rows removed. One atomic flush at the end.
|
|
187
|
+
*
|
|
188
|
+
* @param {(metadata: object) => boolean} predicate
|
|
189
|
+
* @returns {Promise<number>}
|
|
190
|
+
*/
|
|
191
|
+
async deleteWhere(predicate) {
|
|
192
|
+
this._assertLoaded();
|
|
193
|
+
if (typeof predicate !== 'function') {
|
|
194
|
+
throw new Error('deleteWhere: predicate must be a function');
|
|
195
|
+
}
|
|
196
|
+
let removed = 0;
|
|
197
|
+
// Walk from the tail so swap-remove indices stay valid as we splice.
|
|
198
|
+
for (let i = this._rows.length - 1; i >= 0; i--) {
|
|
199
|
+
const row = this._rows[i];
|
|
200
|
+
let match;
|
|
201
|
+
try { match = !!predicate(row.metadata); } catch { match = false; }
|
|
202
|
+
if (!match) continue;
|
|
203
|
+
const last = this._rows.length - 1;
|
|
204
|
+
if (i !== last) {
|
|
205
|
+
this._rows[i] = this._rows[last];
|
|
206
|
+
this._idIndex.set(this._rows[i].id, i);
|
|
207
|
+
}
|
|
208
|
+
this._rows.pop();
|
|
209
|
+
this._idIndex.delete(row.id);
|
|
210
|
+
removed++;
|
|
211
|
+
}
|
|
212
|
+
if (removed > 0) await this._flush();
|
|
213
|
+
return removed;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Cosine query. Vectors are normalized, so cosine = dot product.
|
|
218
|
+
* Linear scan — fine up to ~100K rows. For larger corpora we swap
|
|
219
|
+
* to sqlite-vec (HNSW) without changing this interface.
|
|
220
|
+
*
|
|
221
|
+
* @param {Float32Array} queryVector
|
|
222
|
+
* @param {object} [opts]
|
|
223
|
+
* @param {number} [opts.topK=10]
|
|
224
|
+
* @param {(metadata: object) => boolean} [opts.filter]
|
|
225
|
+
* @param {(baseScore: number, metadata: object) => number} [opts.scoring]
|
|
226
|
+
* Optional per-row score adjuster — used by the multi-signal
|
|
227
|
+
* ranking layer (recency + access boosts). See
|
|
228
|
+
* `vectorStore/scoring.js`. Identity when omitted.
|
|
229
|
+
*/
|
|
230
|
+
async query(queryVector, { topK = 10, filter = null, scoring = null } = {}) {
|
|
231
|
+
this._assertLoaded();
|
|
232
|
+
this._validateVector(queryVector);
|
|
233
|
+
const adjust = typeof scoring === 'function' ? scoring : null;
|
|
234
|
+
|
|
235
|
+
const scored = [];
|
|
236
|
+
for (const row of this._rows) {
|
|
237
|
+
if (filter && !filter(row.metadata)) continue;
|
|
238
|
+
const base = dot(queryVector, row.vector);
|
|
239
|
+
const score = adjust ? adjust(base, row.metadata) : base;
|
|
240
|
+
scored.push({ id: row.id, score, metadata: row.metadata });
|
|
241
|
+
}
|
|
242
|
+
scored.sort((a, b) => b.score - a.score);
|
|
243
|
+
return scored.slice(0, topK);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Hybrid query: rank-fuse semantic results with substring matches
|
|
248
|
+
* over `metadata.text`. RRF is used because raw scores live on
|
|
249
|
+
* different scales (cosine vs boolean) and RRF only needs ranks.
|
|
250
|
+
*
|
|
251
|
+
* @param {Float32Array} queryVector
|
|
252
|
+
* @param {string} queryText - For substring matching.
|
|
253
|
+
* @param {object} [opts]
|
|
254
|
+
* @param {number} [opts.topK=10]
|
|
255
|
+
* @param {Function} [opts.filter] - Same shape as query().
|
|
256
|
+
* @returns {Promise<Array<{id, score, metadata}>>}
|
|
257
|
+
*/
|
|
258
|
+
async hybridQuery(queryVector, queryText, { topK = 10, filter = null, scoring = null } = {}) {
|
|
259
|
+
this._assertLoaded();
|
|
260
|
+
// The semantic candidate set is the one that benefits from scoring
|
|
261
|
+
// adjustments. The substring path is rank-only, so reweighting
|
|
262
|
+
// wouldn't affect RRF anyway.
|
|
263
|
+
const semantic = await this.query(queryVector, { topK: topK * 4, filter, scoring });
|
|
264
|
+
const substring = await this._substringMatches(queryText, { topK: topK * 4, filter });
|
|
265
|
+
const fused = reciprocalRankFusion([semantic, substring], { topK });
|
|
266
|
+
// Hydrate ids back to full rows.
|
|
267
|
+
return fused.map(({ id, score }) => {
|
|
268
|
+
const idx = this._idIndex.get(id);
|
|
269
|
+
const row = idx !== undefined ? this._rows[idx] : null;
|
|
270
|
+
return { id, score, metadata: row?.metadata || {} };
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** @private */
|
|
275
|
+
async _substringMatches(queryText, { topK, filter }) {
|
|
276
|
+
if (typeof queryText !== 'string' || !queryText) return [];
|
|
277
|
+
const needle = queryText.toLowerCase();
|
|
278
|
+
const matches = [];
|
|
279
|
+
for (const row of this._rows) {
|
|
280
|
+
if (filter && !filter(row.metadata)) continue;
|
|
281
|
+
const haystack = String(row.metadata?.text || '').toLowerCase();
|
|
282
|
+
if (haystack.length === 0) continue;
|
|
283
|
+
const idx = haystack.indexOf(needle);
|
|
284
|
+
if (idx === -1) continue;
|
|
285
|
+
// Score = inverse position (earlier matches rank higher). Used only
|
|
286
|
+
// for ordering inside this list — final fusion ignores raw scores.
|
|
287
|
+
matches.push({ id: row.id, score: 1 / (1 + idx) });
|
|
288
|
+
}
|
|
289
|
+
matches.sort((a, b) => b.score - a.score);
|
|
290
|
+
return matches.slice(0, topK);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async drop() {
|
|
294
|
+
this._assertLoaded();
|
|
295
|
+
this._rows = [];
|
|
296
|
+
this._idIndex.clear();
|
|
297
|
+
try {
|
|
298
|
+
await fsp.unlink(this._filePath);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
if (err?.code !== 'ENOENT') {
|
|
301
|
+
this._logger?.warn?.('[vectorStore] drop(): could not unlink file', { path: this._filePath, err: err.message });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Force a flush. Public because callers occasionally want to ensure
|
|
308
|
+
* persistence before a critical handoff (e.g. shutdown).
|
|
309
|
+
*/
|
|
310
|
+
async flush() {
|
|
311
|
+
await this._flush();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** @private */
|
|
315
|
+
_assertLoaded() {
|
|
316
|
+
if (!this._loaded) {
|
|
317
|
+
throw new Error('VectorStore not loaded — call await store.load() first');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** @private */
|
|
322
|
+
_validateVector(v) {
|
|
323
|
+
if (!(v instanceof Float32Array)) {
|
|
324
|
+
throw new Error('vector must be a Float32Array');
|
|
325
|
+
}
|
|
326
|
+
if (v.length !== this._dimensions) {
|
|
327
|
+
throw new Error(`vector has wrong dimensions (got ${v.length}, expected ${this._dimensions})`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** @private */
|
|
332
|
+
async _flush() {
|
|
333
|
+
const payload = {
|
|
334
|
+
version: FILE_VERSION,
|
|
335
|
+
dimensions: this._dimensions,
|
|
336
|
+
modelFingerprint: this._modelFingerprint,
|
|
337
|
+
savedAt: new Date().toISOString(),
|
|
338
|
+
rows: this._rows.map(r => ({
|
|
339
|
+
id: r.id,
|
|
340
|
+
vector: Array.from(r.vector), // JSON can't hold typed arrays
|
|
341
|
+
metadata: r.metadata,
|
|
342
|
+
})),
|
|
343
|
+
};
|
|
344
|
+
const tmpPath = `${this._filePath}.tmp`;
|
|
345
|
+
await fsp.mkdir(path.dirname(this._filePath), { recursive: true });
|
|
346
|
+
await fsp.writeFile(tmpPath, JSON.stringify(payload));
|
|
347
|
+
await fsp.rename(tmpPath, this._filePath);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Dot product over two equal-length Float32Arrays. Hot path — no allocation. */
|
|
352
|
+
function dot(a, b) {
|
|
353
|
+
let s = 0;
|
|
354
|
+
for (let i = 0; i < a.length; i++) s += a[i] * b[i];
|
|
355
|
+
return s;
|
|
356
|
+
}
|