@romiluz/clawmongo 2026.3.26 → 2026.3.28
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/README.md +84 -49
- package/dist/{accounts-boH28BFM.js → accounts-lL2y51Ag.js} +46 -46
- package/dist/{acp-cli-DLaTb29R.js → acp-cli-BZvVHRY8.js} +46 -46
- package/dist/{action-runtime-Bk-7pvN2.js → action-runtime-DMYRUL4q.js} +10 -10
- package/dist/{actions.runtime-Y529miLb.js → actions.runtime-Bd-NMAq6.js} +46 -46
- package/dist/{actions.runtime-DVQ4pmcp.js → actions.runtime-gPSeXscW.js} +49 -49
- package/dist/{agent-scope-BROpmzKv.js → agent-scope-DXZH506l.js} +1 -1
- package/dist/{agents-DZqtbDMD.js → agents-Bt25bmDR.js} +13 -13
- package/dist/{agents-BbO-i90j.js → agents-CyJmttnS.js} +114 -114
- package/dist/{agents.config-CDS6iAat.js → agents.config-BWm70Hr6.js} +2 -2
- package/dist/{agents.config-iY500LY-.js → agents.config-UsCw0kOR.js} +4 -4
- package/dist/{audit-Cmj7BNcZ.js → audit-Dg8ZiJrJ.js} +9 -9
- package/dist/{audit-DmXeao7s.js → audit-DhXhWoiv.js} +1 -1
- package/dist/{audit-channel.collect.runtime-DhP09fjv.js → audit-channel.collect.runtime-CvPUHy1X.js} +2 -2
- package/dist/{audit-channel.runtime-C-watgwg.js → audit-channel.runtime-B6ZnOPFc.js} +46 -46
- package/dist/{audit-extra.async-B-7dzgcz.js → audit-extra.async-826UZZhJ.js} +3 -3
- package/dist/{audit-membership-runtime-CbLi3-5b.js → audit-membership-runtime-DLQrV7Rr.js} +46 -46
- package/dist/{audit.deep.runtime-D5VgrTOT.js → audit.deep.runtime-DQDtV7Bc.js} +4 -4
- package/dist/{audit.nondeep.runtime-B7M0-7FZ.js → audit.nondeep.runtime-H6B-2xal.js} +4 -4
- package/dist/{audit.runtime-BUknqGaP.js → audit.runtime-D2ZRC2A_.js} +47 -47
- package/dist/{auth-choice-DfJRosb4.js → auth-choice-CEowrO66.js} +57 -57
- package/dist/{auth-choice-CpB99A-L.js → auth-choice-DiufM1b8.js} +55 -55
- package/dist/{auth-choice-Bnnngmkx.js → auth-choice-YrGxwB9A.js} +5 -5
- package/dist/{auth-choice-options-DvqJHFOp.js → auth-choice-options-n3_uFdT5.js} +2 -2
- package/dist/{auth-choice-prompt-DtTjWfPT.js → auth-choice-prompt-DYFzoWa6.js} +50 -50
- package/dist/{auth-choice-prompt-Cxz8du6E.js → auth-choice-prompt-sLET2Bkw.js} +1 -1
- package/dist/{auth-choice.apply-helpers-Bm5p2ZX7.js → auth-choice.apply-helpers-GU6nZntg.js} +1 -1
- package/dist/{auth-choice.plugin-providers.runtime-Dsu6-vb8.js → auth-choice.plugin-providers.runtime-BNqOEEtb.js} +47 -47
- package/dist/{auth-profiles-2-OV37OF.js → auth-profiles-BWBQJ6X_.js} +67 -76
- package/dist/{auth-profiles.runtime-HcQMBs3K.js → auth-profiles.runtime-DfKRAmQR.js} +46 -46
- package/dist/{backend-config-avgzgS5Z.js → backend-config--L236wE2.js} +26 -1
- package/dist/{backup-create-B9F0M7-J.js → backup-create-Bll6DgoT.js} +2 -2
- package/dist/{base-session-key-DyLtSGkj.js → base-session-key-CA4SoGLF.js} +1 -1
- package/dist/{bluebubbles-BTR7u4zE.js → bluebubbles-BsX68JOY.js} +6 -6
- package/dist/{browser-cli-tmytvFaa.js → browser-cli-B5euA0cQ.js} +8 -8
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +46 -46
- package/dist/bundled/bootstrap-extra-files/handler.js +1 -1
- package/dist/bundled/session-memory/handler.js +47 -47
- package/dist/{call-Cqem-bCB.js → call-C-_XQxw5.js} +1 -1
- package/dist/{call-CxVOiYz-.js → call-lPTaDgAg.js} +6 -6
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{channel-Br8MF00M.js → channel-5o-oIU2B.js} +1 -1
- package/dist/{channel-BvRm4jSj.js → channel-C1zZg_8b.js} +2 -2
- package/dist/{channel-CqkxOhz2.js → channel-CEytBPH-.js} +4 -4
- package/dist/{channel-D_h7IfYK.js → channel-Cm65A1lo.js} +7 -7
- package/dist/{channel-ngZRDeE3.js → channel-D4K0MVgr.js} +5 -5
- package/dist/{channel-account-context-DZhZw4oo.js → channel-account-context-CNZZPDSe.js} +1 -1
- package/dist/{channel-plugin-resolution-CXm5HIcm.js → channel-plugin-resolution-WWO690RK.js} +3 -3
- package/dist/{channel-reply-pipeline-DdDsf-Lc.js → channel-reply-pipeline-B17-tBLU.js} +1 -1
- package/dist/{channel-shared-VIRIADYn.js → channel-shared-RH6YsZ0I.js} +1 -1
- package/dist/{channel-summary-BTJxLPN8.js → channel-summary-Cy7WDRjQ.js} +7 -7
- package/dist/{channel-summary-DdJtHlvH.js → channel-summary-DV4_b3HZ.js} +2 -2
- package/dist/{channel-tFDEkWt9.js → channel-yCiI29Ju.js} +6 -6
- package/dist/{channel.runtime-DGnRryi2.js → channel.runtime-C3m1vacV.js} +47 -47
- package/dist/{channel.runtime-CdPEA_wb.js → channel.runtime-CUSE7Dn0.js} +47 -47
- package/dist/{channel.runtime-0n3_Hz_Y.js → channel.runtime-CtWi36oj.js} +49 -49
- package/dist/{channel.runtime-CkHcsWQ3.js → channel.runtime-LUpQZiWg.js} +49 -49
- package/dist/{channel.runtime-msXRrVzC.js → channel.runtime-QOkM4mJV.js} +51 -51
- package/dist/{channel.runtime-khqV1QRG.js → channel.runtime-rYuUs2po.js} +4 -4
- package/dist/{channels-DNza27NY.js → channels-4VTbN2Gt.js} +103 -103
- package/dist/{channels-CLZoq3SY.js → channels-BUMnLXLQ.js} +1 -1
- package/dist/{channels-cli-Bhsnjsix.js → channels-cli-BYmLj8zw.js} +55 -55
- package/dist/{clawbot-cli-9YJNF9pF.js → clawbot-cli-CIYY1u-6.js} +47 -47
- package/dist/cli/daemon-cli.js +1 -1
- package/dist/{cli-FF5823nM.js → cli-DUA0FvhM.js} +46 -46
- package/dist/{command-registry-Dw-TONf0.js → command-registry-B1ECZip_.js} +13 -13
- package/dist/{command-registry-TeN0aKPi.js → command-registry-DOAwIs0Y.js} +2 -2
- package/dist/{command-secret-gateway-CzHSHmXG.js → command-secret-gateway-Big-n6JY.js} +46 -46
- package/dist/{compact.runtime-Bye-pm7Z.js → compact.runtime-BKnPPv9X.js} +46 -46
- package/dist/{completion-cli-D08RAGPz.js → completion-cli-BeLNvVTI.js} +3 -3
- package/dist/{completion-cli-C0mwyiAb.js → completion-cli-CHwHDPuI.js} +2 -2
- package/dist/{config-Ca7pLyBD.js → config-BOWZMmDA.js} +1 -1
- package/dist/{config-GKOWhVMv.js → config-C68iwvDj.js} +5 -5
- package/dist/{config-cli-CxPspN-S.js → config-cli-BnC336Lu.js} +48 -48
- package/dist/{config-guard-BK2hWyPi.js → config-guard-Bn6rZnzK.js} +6 -6
- package/dist/{config-validation-DO6o_Kt_.js → config-validation-BBuJZ-WH.js} +2 -2
- package/dist/{configure-CODqvxU-.js → configure-CHJDsjOD.js} +120 -120
- package/dist/{configure-Dg65gBEw.js → configure-Cctw7tyJ.js} +19 -23
- package/dist/{connection-auth-zhL6PVn0.js → connection-auth-C2XaPpF5.js} +1 -1
- package/dist/{control-ui-shared-_VwcOcc_.js → control-ui-shared-BC-g150y.js} +1 -1
- package/dist/{core-CzwQmKcn.js → core-Cb3XxL6S.js} +1 -1
- package/dist/{cron-cli-Dp_EQt2v.js → cron-cli-C10feOtH.js} +7 -7
- package/dist/{daemon-cli-Dgpv6Y0R.js → daemon-cli-Ds8mu2VZ.js} +4 -4
- package/dist/{daemon-install-Dq1Ix-FO.js → daemon-install-B__sP_7j.js} +49 -49
- package/dist/{delegate-BVapk4rY.js → delegate-ByCLviVI.js} +1 -1
- package/dist/{deliver-runtime-DPzMjhNU.js → deliver-Co7G5ubS.js} +46 -46
- package/dist/{deliver-C32Gg-xU.js → deliver-runtime-2svrtAf1.js} +46 -46
- package/dist/{devices-cli-3WN_wB1C.js → devices-cli-CH8nWgcU.js} +6 -6
- package/dist/{diagnostic-BbXfhLMi.js → diagnostic-DHTG43d_.js} +1 -1
- package/dist/{directory-cli-D_5BYdXm.js → directory-cli-B0REFlKo.js} +48 -48
- package/dist/{directory.static-CsajbHw1.js → directory.static-wnw_R8dE.js} +1 -1
- package/dist/{discord-C-4y9vOT.js → discord-Cws9MsXn.js} +4 -4
- package/dist/{discord-B3mmVXuG.js → discord-b8Ff_BKB.js} +46 -46
- package/dist/{dns-cli-CdAnUzRi.js → dns-cli-aRTleL5e.js} +5 -5
- package/dist/{doctor-completion-BnqTtLhL.js → doctor-completion-KQWBMnEi.js} +1 -1
- package/dist/{doctor-config-preflight-BJ0lGLTO.js → doctor-config-preflight-BDYe5di1.js} +2 -2
- package/dist/{doctor-config-preflight-D32oVOWD.js → doctor-config-preflight-Dn5a_Dbr.js} +6 -6
- package/dist/{doctor-state-migrations-BklDIib1.js → doctor-state-migrations-BI6HzFyq.js} +47 -47
- package/dist/{doctor-state-migrations-Cdk3ep_f.js → doctor-state-migrations-DUPe9zNr.js} +2 -2
- package/dist/entry.js +1 -1
- package/dist/{exec-approvals-D8OOtgGc.js → exec-approvals-CZz2LqIW.js} +1 -1
- package/dist/{exec-approvals-cli-dGISWHE3.js → exec-approvals-cli-KbFpgd-p.js} +9 -9
- package/dist/extensionAPI.js +46 -46
- package/dist/extensions/amazon-bedrock/index.js +46 -46
- package/dist/extensions/anthropic/index.js +46 -46
- package/dist/extensions/bluebubbles/index.js +50 -50
- package/dist/extensions/bluebubbles/setup-entry.js +48 -48
- package/dist/extensions/byteplus/index.js +46 -46
- package/dist/extensions/chutes/index.js +48 -48
- package/dist/extensions/cloudflare-ai-gateway/index.js +47 -47
- package/dist/extensions/device-pair/index.js +46 -46
- package/dist/extensions/discord/index.js +48 -48
- package/dist/extensions/discord/node_modules/.package-lock.json +3 -3
- package/dist/extensions/discord/node_modules/hono/dist/adapter/service-worker/index.js +1 -3
- package/dist/extensions/discord/node_modules/hono/dist/cjs/adapter/service-worker/index.js +1 -3
- package/dist/extensions/discord/node_modules/hono/dist/cjs/helper/ssg/ssg.js +1 -1
- package/dist/extensions/discord/node_modules/hono/dist/cjs/middleware/cors/index.js +5 -2
- package/dist/extensions/discord/node_modules/hono/dist/cjs/request.js +1 -1
- package/dist/extensions/discord/node_modules/hono/dist/helper/ssg/ssg.js +1 -1
- package/dist/extensions/discord/node_modules/hono/dist/middleware/cors/index.js +5 -2
- package/dist/extensions/discord/node_modules/hono/dist/request.js +1 -1
- package/dist/extensions/discord/node_modules/hono/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/extensions/discord/node_modules/hono/dist/types/client/index.d.ts +1 -1
- package/dist/extensions/discord/node_modules/hono/dist/types/client/types.d.ts +20 -0
- package/dist/extensions/discord/node_modules/hono/dist/types/request.d.ts +1 -3
- package/dist/extensions/discord/node_modules/hono/package.json +1 -1
- package/dist/extensions/discord/setup-entry.js +48 -48
- package/dist/extensions/elevenlabs/index.js +46 -46
- package/dist/extensions/fal/index.js +46 -46
- package/dist/extensions/feishu/index.js +55 -55
- package/dist/extensions/feishu/setup-entry.js +51 -51
- package/dist/extensions/firecrawl/index.js +46 -46
- package/dist/extensions/github-copilot/index.js +47 -47
- package/dist/extensions/google/index.js +46 -46
- package/dist/extensions/huggingface/index.js +47 -47
- package/dist/extensions/imessage/index.js +49 -49
- package/dist/extensions/imessage/setup-entry.js +49 -49
- package/dist/extensions/irc/index.js +49 -49
- package/dist/extensions/irc/setup-entry.js +48 -48
- package/dist/extensions/kilocode/index.js +47 -47
- package/dist/extensions/kimi-coding/index.js +47 -47
- package/dist/extensions/line/index.js +9 -9
- package/dist/extensions/line/setup-entry.js +8 -8
- package/dist/extensions/llm-task/index.js +46 -46
- package/dist/extensions/lobster/index.js +5 -5
- package/dist/extensions/mattermost/index.js +49 -49
- package/dist/extensions/mattermost/setup-entry.js +48 -48
- package/dist/extensions/microsoft/index.js +46 -46
- package/dist/extensions/minimax/index.js +48 -48
- package/dist/extensions/mistral/index.js +47 -47
- package/dist/extensions/modelstudio/index.js +47 -47
- package/dist/extensions/moonshot/index.js +46 -46
- package/dist/extensions/nextcloud-talk/index.js +50 -50
- package/dist/extensions/nextcloud-talk/setup-entry.js +49 -49
- package/dist/extensions/ollama/index.js +5 -5
- package/dist/extensions/openai/index.js +47 -47
- package/dist/extensions/opencode/index.js +47 -47
- package/dist/extensions/opencode-go/index.js +47 -47
- package/dist/extensions/openrouter/index.js +47 -47
- package/dist/extensions/openshell/index.js +46 -46
- package/dist/extensions/qianfan/index.js +47 -47
- package/dist/extensions/qwen-portal-auth/index.js +47 -47
- package/dist/extensions/sglang/index.js +46 -46
- package/dist/extensions/signal/index.js +49 -49
- package/dist/extensions/signal/setup-entry.js +49 -49
- package/dist/extensions/slack/index.js +50 -50
- package/dist/extensions/slack/setup-entry.js +50 -50
- package/dist/extensions/synology-chat/index.js +9 -9
- package/dist/extensions/synology-chat/setup-entry.js +8 -8
- package/dist/extensions/synthetic/index.js +47 -47
- package/dist/extensions/talk-voice/index.js +46 -46
- package/dist/extensions/tavily/index.js +46 -46
- package/dist/extensions/telegram/index.js +48 -48
- package/dist/extensions/telegram/setup-entry.js +48 -48
- package/dist/extensions/together/index.js +47 -47
- package/dist/extensions/venice/index.js +47 -47
- package/dist/extensions/vercel-ai-gateway/index.js +47 -47
- package/dist/extensions/vllm/index.js +46 -46
- package/dist/extensions/voice-call/index.js +46 -46
- package/dist/extensions/volcengine/index.js +46 -46
- package/dist/extensions/xai/index.js +46 -46
- package/dist/extensions/xiaomi/index.js +47 -47
- package/dist/extensions/zai/index.js +47 -47
- package/dist/extensions/zalo/index.js +49 -49
- package/dist/extensions/zalo/setup-entry.js +48 -48
- package/dist/{feishu-C637DYYe.js → feishu-D2fuiOiy.js} +4 -4
- package/dist/{gateway-cli-Cuk9d7J2.js → gateway-cli-nOgyXtih.js} +72 -106
- package/dist/{gateway-install-token-DlcVm1rP.js → gateway-install-token-nvsTK8KN.js} +4 -4
- package/dist/{gateway-rpc-siKa8KpM.js → gateway-rpc-DrH142-v.js} +1 -1
- package/dist/{gateway-runtime-roiTaOKO.js → gateway-runtime-CQXKGzrv.js} +2 -2
- package/dist/{github-copilot-auth-DJljh3gq.js → github-copilot-auth-C4z2AAd8.js} +3 -3
- package/dist/{health-DU_pBiid.js → health-DEgLPyA9.js} +7 -7
- package/dist/{health-B1OK1kJg.js → health-H5nbiXvA.js} +48 -48
- package/dist/{heartbeat-summary-CMwt9qam.js → heartbeat-summary-CNCptWmA.js} +1 -1
- package/dist/{hooks-cli-D42hQEUb.js → hooks-cli-jBhsJaOg.js} +46 -46
- package/dist/{identity-file-8MUyIAOy.js → identity-file-CYQnH12I.js} +1 -1
- package/dist/{imessage-zqZjecTU.js → imessage-DYqgZpLc.js} +6 -6
- package/dist/{imessage-CZb_pS8U.js → imessage-Dau6WdE3.js} +46 -46
- package/dist/{inbound-reply-dispatch-B73AkQh4.js → inbound-reply-dispatch-BFE3xy1S.js} +2 -2
- package/dist/index.js +2 -2
- package/dist/{internal-Bg_k56Pk.js → internal-DLE9baj7.js} +0 -24
- package/dist/{io-DE9vm7Eo.js → io-Du0b8gMO.js} +2 -2
- package/dist/{io-B7rO2wud.js → io-dJgqp8U8.js} +4 -4
- package/dist/{irc-BWzsfr2V.js → irc-BRaOVUse.js} +2 -2
- package/dist/{kb-cli-BOPGkNfJ.js → kb-cli-Cdif_vwn.js} +12 -12
- package/dist/{library-i-2ymInt.js → library-BwjFIWw3.js} +46 -46
- package/dist/{lifecycle-core-DwIo1PfK.js → lifecycle-core-DNO4MItg.js} +1 -1
- package/dist/line/send.js +6 -6
- package/dist/{line-DbTKdVgY.js → line-BCXUGrVz.js} +2 -2
- package/dist/{llm-slug-generator-Dm30OM2W.js → llm-slug-generator-B55FZ1aG.js} +3 -3
- package/dist/llm-slug-generator.js +47 -47
- package/dist/{logging-BM4mQ53W.js → logging-BvOzg0cM.js} +1 -1
- package/dist/{logging-0tvlVvFG.js → logging-nWyKsj9d.js} +5 -5
- package/dist/{login-qr-DQPSabxI.js → login-qr-C0QA3j4x.js} +46 -46
- package/dist/{logs-cli-ZnHk5eku.js → logs-cli-thlXBA9n.js} +7 -7
- package/dist/{manager.runtime-D3vjUOZF.js → manager.runtime-SoTq-tT4.js} +46 -46
- package/dist/{matrix-migration-snapshot-CRKiHq6Y.js → matrix-migration-snapshot-_6Rg-iLO.js} +2 -2
- package/dist/{mattermost-Bqn7Fd5U.js → mattermost-2nv5O_jQ.js} +2 -2
- package/dist/{mcp-cli-7aN2vJv-.js → mcp-cli-1vpy_yti.js} +5 -5
- package/dist/{mcp-config-NVrqojpu.js → mcp-config-Bmi2GUum.js} +1 -1
- package/dist/{media-understanding.runtime-DesF8Xhs.js → media-understanding.runtime-Wh-_SFK_.js} +46 -46
- package/dist/{memory-cli-CWqIJQS5.js → memory-cli-COJRHkaJ.js} +46 -46
- package/dist/{memory-search-DyxoUpq2.js → memory-search-CGmdrdM1.js} +1 -1
- package/dist/{memory-search-CgoWYj0V.js → memory-search-Cy36nO15.js} +3 -3
- package/dist/{model-picker-DX9P5pDr.js → model-picker-CYWvoS3z.js} +48 -48
- package/dist/{model-picker-Ds7-VqDS.js → model-picker-_32ihKqK.js} +4 -4
- package/dist/{model-picker.runtime-DqDt4s3S.js → model-picker.runtime-DBT5uEFi.js} +49 -49
- package/dist/{model-selection-DXFVauys.js → model-selection-014eeYCV.js} +1 -1
- package/dist/{model-suppression.runtime-8mU0VJs6.js → model-suppression.runtime-GTI9Rm85.js} +46 -46
- package/dist/{models-GXQSWyBX.js → models-Be9EWpVm.js} +54 -54
- package/dist/{models-CVG-VMBa.js → models-CX35daXC.js} +14 -14
- package/dist/{models-cli-Cvy8rGqU.js → models-cli-BYjac3oq.js} +54 -54
- package/dist/{models-config-BdanqM9X.js → models-config-Agv-ThDH.js} +46 -46
- package/dist/{models-config.providers.discovery-BHZ3WglC.js → models-config.providers.discovery-BJwjDHsg.js} +1 -1
- package/dist/{mongodb-analytics-BszyEhsq.js → mongodb-analytics-HJKYeseb.js} +2 -2
- package/dist/{mongodb-analytics-CcSYo_ae.js → mongodb-analytics-mnKJih5x.js} +1 -1
- package/dist/{mongodb-auto-setup-QcwgZSN9.js → mongodb-auto-setup-CCElSwNy.js} +2 -2
- package/dist/{mongodb-kb-C-VmGOq7.js → mongodb-kb-1tSOXXb9.js} +3 -3
- package/dist/{mongodb-kb-BotgVda9.js → mongodb-kb-CdSvNe3w.js} +2 -2
- package/dist/{mongodb-kb-search-CoIAFX8n.js → mongodb-kb-search-Dq6E746K.js} +1 -1
- package/dist/{mongodb-kb-search-BBYY_d_r.js → mongodb-kb-search-DvsXIUy6.js} +3 -3
- package/dist/{mongodb-manager-BVfTfpHf.js → mongodb-manager-DEZIQXuo.js} +10 -10
- package/dist/{mongodb-manager-BJ0PAYF_.js → mongodb-manager-NkerSpvH.js} +1183 -331
- package/dist/{mongodb-procedures-DNPmmW5r.js → mongodb-procedures-DI-_Dakz.js} +7 -3
- package/dist/{mongodb-procedures-D3M2Ph8E.js → mongodb-procedures-tjhGdBV7.js} +3 -3
- package/dist/{mongodb-schema-JpDXcAUV.js → mongodb-schema-DN3aspLa.js} +1 -1
- package/dist/{mongodb-schema-BI4Ze_ZV.js → mongodb-schema-Dt6jxcPL.js} +298 -4
- package/dist/{mongodb-search-VFKd72IZ.js → mongodb-search-DMsUyfpa.js} +2 -2
- package/dist/{mongodb-structured-memory-DnwUJ6SA.js → mongodb-structured-memory-D-3SEfTu.js} +58 -2
- package/dist/{mongodb-structured-memory-BySGexcm.js → mongodb-structured-memory-lpyyW0kn.js} +3 -3
- package/dist/{monitor-DGE0bx3s.js → monitor-BZFy1RTb.js} +47 -47
- package/dist/{monitor-Dfc0KXMD.js → monitor-DPYGxeY_.js} +5 -5
- package/dist/{monitor-CZZlkQUU.js → monitor-Duykki-j.js} +51 -51
- package/dist/{monitor-B61bVnMW.js → monitor-gq31SALd.js} +8 -8
- package/dist/{nextcloud-talk-CnwOv1rG.js → nextcloud-talk-C_-LfGeq.js} +2 -2
- package/dist/{node-cli-Avub0RKe.js → node-cli-NpJzvfQW.js} +12 -12
- package/dist/{nodes-cli-qSE-cmgX.js → nodes-cli-O5HciXeP.js} +10 -10
- package/dist/{nodes-screen-DQw8F5rA.js → nodes-screen-BIwiB35h.js} +1 -1
- package/dist/{oauth.runtime-825pMCgB.js → oauth.runtime-BxjW8DFO.js} +46 -46
- package/dist/{oauth.runtime-BCwH9-Yl.js → oauth.runtime-DKU2STuA.js} +46 -46
- package/dist/{oauth.runtime-BSddaUzc.js → oauth.runtime-mFizWM72.js} +46 -46
- package/dist/{onboard-CUbnVxXL.js → onboard-B6H0qDtg.js} +1 -1
- package/dist/{onboard-BwC0LbCx.js → onboard-C1AmXQ6f.js} +8 -8
- package/dist/{onboard-Cw65XmEU.js → onboard-DPdj0IBu.js} +2 -2
- package/dist/{onboard-channels-BYNDTtRI.js → onboard-channels-Cmj_5qXQ.js} +24 -24
- package/dist/{onboard-channels-CIR1ZSii.js → onboard-channels-Wf3nY9Bf.js} +97 -97
- package/dist/{onboard-custom-FImARgQC.js → onboard-custom-DILgXkiq.js} +50 -50
- package/dist/{onboard-custom-C4qOVxtG.js → onboard-custom-DlDCjvIw.js} +4 -4
- package/dist/{onboard-helpers-DW9Mskds.js → onboard-helpers-CqpD9TVU.js} +48 -48
- package/dist/{onboard-helpers-D3xV_T96.js → onboard-helpers-D-PLdtHT.js} +3 -3
- package/dist/{onboard-hooks-B0gJVtBY.js → onboard-hooks-MQ8QOguv.js} +2 -2
- package/dist/{onboard-remote-BMLo6WKH.js → onboard-remote-BZKWgKVw.js} +50 -50
- package/dist/{onboard-remote-XUah3N3G.js → onboard-remote-Bnad5LMv.js} +2 -2
- package/dist/{onboard-search-DHCzqxgq.js → onboard-search-Dyv1IuQ4.js} +46 -46
- package/dist/{onboard-skills-LXCIpyir.js → onboard-skills-DdCu1_hE.js} +1 -1
- package/dist/{onboard-skills-CH6q90Pf.js → onboard-skills-W_252asS.js} +49 -49
- package/dist/{onboarding-memory-BWEsBe08.js → onboarding-memory-BRHSmwx3.js} +24 -15
- package/dist/{outbound-media-CqfP0r4a.js → outbound-media-CHc08Sj8.js} +1 -1
- package/dist/{pairing-cli-BdCkQG2S.js → pairing-cli-oNWkjwCt.js} +5 -5
- package/dist/{persistent-dedupe-DNnh7hrR.js → persistent-dedupe-CS_uyVoq.js} +1 -1
- package/dist/{pi-model-discovery-runtime-DyT9C3Ap.js → pi-model-discovery-runtime-BJVREOXf.js} +46 -46
- package/dist/{pi-tools.before-tool-call.runtime-CA2js1Ig.js → pi-tools.before-tool-call.runtime-w-Q4HA_S.js} +6 -6
- package/dist/{plugin-install-DgvJfz7X.js → plugin-install-BysMw7Sl.js} +47 -47
- package/dist/{plugin-install-BKuy_--2.js → plugin-install-EyES0vGP.js} +2 -2
- package/dist/{plugin-registry-D-6OBqUU.js → plugin-registry-BenF9SYR.js} +47 -47
- package/dist/{plugin-registry-Dsx_6z3N.js → plugin-registry-CRV_Bc8K.js} +3 -3
- package/dist/plugin-sdk/account-resolution.js +46 -46
- package/dist/plugin-sdk/acp-runtime.js +46 -46
- package/dist/plugin-sdk/agent-runtime.js +46 -46
- package/dist/plugin-sdk/channel-inbound.js +46 -46
- package/dist/plugin-sdk/channel-reply-pipeline.js +3 -3
- package/dist/plugin-sdk/channel-runtime.js +46 -46
- package/dist/plugin-sdk/channel-setup.js +1 -1
- package/dist/plugin-sdk/command-auth.js +46 -46
- package/dist/plugin-sdk/compat.js +5 -5
- package/dist/plugin-sdk/config-runtime.js +46 -46
- package/dist/plugin-sdk/conversation-runtime.js +46 -46
- package/dist/plugin-sdk/core.js +5 -5
- package/dist/plugin-sdk/directory-runtime.js +1 -1
- package/dist/plugin-sdk/discord.js +46 -46
- package/dist/plugin-sdk/gateway-runtime.js +8 -8
- package/dist/plugin-sdk/image-generation.js +46 -46
- package/dist/plugin-sdk/index.js +46 -46
- package/dist/plugin-sdk/infra-runtime.js +46 -46
- package/dist/plugin-sdk/llm-task.js +46 -46
- package/dist/plugin-sdk/matrix-runtime-heavy.js +50 -50
- package/dist/plugin-sdk/media-runtime.js +46 -46
- package/dist/plugin-sdk/media-understanding-runtime.js +46 -46
- package/dist/plugin-sdk/media-understanding.js +46 -46
- package/dist/plugin-sdk/ollama-setup.js +8 -8
- package/dist/plugin-sdk/plugin-runtime.js +46 -46
- package/dist/plugin-sdk/provider-auth-api-key.js +46 -46
- package/dist/plugin-sdk/provider-auth-login.js +1 -1
- package/dist/plugin-sdk/provider-auth.js +46 -46
- package/dist/plugin-sdk/provider-models.js +5 -5
- package/dist/plugin-sdk/provider-onboard.js +5 -5
- package/dist/plugin-sdk/provider-setup.js +49 -49
- package/dist/plugin-sdk/provider-stream.js +46 -46
- package/dist/plugin-sdk/provider-usage.js +4 -4
- package/dist/plugin-sdk/reply-history.js +3 -3
- package/dist/plugin-sdk/reply-runtime.js +46 -46
- package/dist/plugin-sdk/routing.js +3 -3
- package/dist/plugin-sdk/sandbox.js +46 -46
- package/dist/plugin-sdk/self-hosted-provider-setup.js +48 -48
- package/dist/plugin-sdk/setup-runtime.js +1 -1
- package/dist/plugin-sdk/setup.js +1 -1
- package/dist/plugin-sdk/speech-runtime.js +46 -46
- package/dist/plugin-sdk/speech.js +46 -46
- package/dist/plugin-sdk/src/agents/workspace.d.ts +1 -3
- package/dist/plugin-sdk/src/config/types.memory.d.ts +44 -0
- package/dist/plugin-sdk/src/memory/backend-config.d.ts +24 -0
- package/dist/plugin-sdk/src/memory/index.d.ts +12 -4
- package/dist/plugin-sdk/src/memory/mongodb-entity-extractor.d.ts +33 -0
- package/dist/plugin-sdk/src/memory/mongodb-episodes.d.ts +16 -0
- package/dist/plugin-sdk/src/memory/mongodb-events.d.ts +9 -0
- package/dist/plugin-sdk/src/memory/mongodb-graph.d.ts +30 -3
- package/dist/plugin-sdk/src/memory/mongodb-manager.d.ts +18 -0
- package/dist/plugin-sdk/src/memory/mongodb-mutations.d.ts +38 -0
- package/dist/plugin-sdk/src/memory/mongodb-procedures.d.ts +32 -0
- package/dist/plugin-sdk/src/memory/mongodb-profile.d.ts +71 -0
- package/dist/plugin-sdk/src/memory/mongodb-query-cache.d.ts +68 -0
- package/dist/plugin-sdk/src/memory/mongodb-query-rewriter.d.ts +39 -0
- package/dist/plugin-sdk/src/memory/mongodb-reranker.d.ts +32 -0
- package/dist/plugin-sdk/src/memory/mongodb-schema.d.ts +3 -0
- package/dist/plugin-sdk/src/memory/mongodb-telemetry.d.ts +69 -0
- package/dist/plugin-sdk/text-runtime.js +6 -6
- package/dist/plugin-sdk/web-media.js +3 -3
- package/dist/plugin-sdk/zalo.js +47 -47
- package/dist/plugin-sdk/zalouser.js +47 -47
- package/dist/plugins/build-smoke-entry.js +46 -46
- package/dist/plugins/runtime/index.js +46 -46
- package/dist/{plugins-cli-C6wGAkD9.js → plugins-cli-BUiP4x7l.js} +46 -46
- package/dist/{policy-CcgojW9R.js → policy-DnUfJkOZ.js} +1 -1
- package/dist/{preflight-audio.runtime-Cyz9Zu89.js → preflight-audio.runtime-D3_iaSgF.js} +46 -46
- package/dist/{probe-auth-BmluVNJZ.js → probe-auth-BbNdYwb0.js} +1 -1
- package/dist/{probe-auth-DrgTJ7ki.js → probe-auth-CB9y2dLl.js} +7 -7
- package/dist/{program-CHFcfOlC.js → program-uHYlUP3c.js} +4 -4
- package/dist/{prompt-select-styled-Ck38XMb3.js → prompt-select-styled-DoTAWghe.js} +25 -51
- package/dist/{provider-api-key-auth.runtime-AT16DTa8.js → provider-api-key-auth.runtime-B3H0dODg.js} +46 -46
- package/dist/{provider-auth-choice-UhIkLc6q.js → provider-auth-choice-HRfxXEHk.js} +6 -6
- package/dist/{provider-auth-choice-helpers-CXWmWOdR.js → provider-auth-choice-helpers-2jZnBKMm.js} +1 -1
- package/dist/{provider-auth-choice-preference-TgulgKlz.js → provider-auth-choice-preference-CqKryjBB.js} +6 -6
- package/dist/{provider-auth-choice.runtime-FTNgi8Yh.js → provider-auth-choice.runtime-BaFSZgQG.js} +48 -48
- package/dist/{provider-auth-choice.runtime-CP91b3vK.js → provider-auth-choice.runtime-DPHuj1_l.js} +2 -2
- package/dist/{provider-auth-choices-BfWvatIg.js → provider-auth-choices-CqFh00uK.js} +1 -1
- package/dist/{provider-auth-guidance-D4-q7IHl.js → provider-auth-guidance-DmdBoDfS.js} +2 -2
- package/dist/{provider-auth-input-DnQ-RiX5.js → provider-auth-input-FZYEJh19.js} +46 -46
- package/dist/{provider-auth-login-D7eLUZwy.js → provider-auth-login-B-XedaK5.js} +1 -1
- package/dist/{provider-auth-login.runtime-BG_qqxZk.js → provider-auth-login.runtime-f9dxfJUB.js} +49 -49
- package/dist/{provider-model-allowlist-CC0lIQ6w.js → provider-model-allowlist-C16pn0B8.js} +1 -1
- package/dist/{provider-models-DbK6xrje.js → provider-models-PaymKOme.js} +1 -1
- package/dist/{provider-ollama-setup-B4RWr9oj.js → provider-ollama-setup-k5ozCUi2.js} +3 -3
- package/dist/{provider-onboarding-config-W5sF0oD8.js → provider-onboarding-config-qCltsaVl.js} +1 -1
- package/dist/{provider-runtime.runtime-Cva8S4wx.js → provider-runtime.runtime-CzVe0WBb.js} +46 -46
- package/dist/{provider-self-hosted-setup-jAzqLaqv.js → provider-self-hosted-setup-zxYnIftX.js} +3 -3
- package/dist/{provider-usage-CEgSCMW4.js → provider-usage-C9KdAhuS.js} +46 -46
- package/dist/{provider-usage-CCIC3SdY.js → provider-usage-DexJNI_0.js} +1 -1
- package/dist/{provider-wizard-DQd5eYhX.js → provider-wizard-D4RbMR2D.js} +2 -2
- package/dist/{push-apns-DQN5pcl6.js → push-apns-BAc0-Jy5.js} +1 -1
- package/dist/{pw-ai-BiXz8un2.js → pw-ai-C8v0s5wH.js} +6 -6
- package/dist/{qr-cli-B8bBpCd2.js → qr-cli-BpqLcmYC.js} +47 -47
- package/dist/{qr-cli-DOuhqzho.js → qr-cli-D0zqiQMl.js} +4 -4
- package/dist/{reactions-BkyHqIw4.js → reactions-CjJbniYK.js} +1 -1
- package/dist/{read-only-account-inspect-Cfaj7PFb.js → read-only-account-inspect-CEJ1r7AW.js} +3 -3
- package/dist/{read-only-account-inspect.discord.runtime-kreMwVgq.js → read-only-account-inspect.discord.runtime-C1n8r_Kj.js} +46 -46
- package/dist/{read-only-account-inspect.slack.runtime-DgV5VZ-n.js → read-only-account-inspect.slack.runtime-DAOzA9ke.js} +46 -46
- package/dist/{read-only-account-inspect.telegram.runtime-BQaHHCIS.js → read-only-account-inspect.telegram.runtime-CfNlnogC.js} +46 -46
- package/dist/{redact-snapshot-PisBVQFW.js → redact-snapshot-qQFn3bz8.js} +3 -3
- package/dist/{register.agent-CXTssAWM.js → register.agent-DC5QbIE7.js} +114 -114
- package/dist/{register.backup-MRTb86c6.js → register.backup-BRxspFkM.js} +6 -6
- package/dist/{register.configure-BfE3p-3h.js → register.configure-B7zhRBla.js} +120 -120
- package/dist/{register.maintenance-D_Gn-ZDc.js → register.maintenance-CCmppLW1.js} +65 -65
- package/dist/{register.message-s1z2QSP2.js → register.message-DSBPJS4x.js} +47 -47
- package/dist/{register.onboard-Cd-OV7xm.js → register.onboard-C4D9pjf7.js} +54 -54
- package/dist/{register.setup-DclQVR9m.js → register.setup-C4pDa0HW.js} +52 -52
- package/dist/{register.status-health-sessions-D-Xp8ae7.js → register.status-health-sessions-ClxLTjC5.js} +55 -55
- package/dist/{register.subclis-pcAQ13jU.js → register.subclis-BauDruMA.js} +30 -30
- package/dist/{register.subclis-BCvQmGkr.js → register.subclis-WyYRaoa-.js} +1 -1
- package/dist/{replies-DQwDaTBP.js → replies-CZGcXYVE.js} +1 -1
- package/dist/{reply-history-DVLrt4Es.js → reply-history-1yT9Tzib.js} +1 -1
- package/dist/{routes-CBWjQBhD.js → routes-D8CYDLDF.js} +5 -5
- package/dist/{rpc-O719GSVf.js → rpc-D8I_Qzen.js} +1 -1
- package/dist/{run-main-C_W2kjf-.js → run-main-BwEbDjI-.js} +19 -19
- package/dist/{runtime-COpSaRtb.js → runtime-CmSMHqwN.js} +1 -1
- package/dist/{runtime-PbP8BVEV.js → runtime-DQaeo-1L.js} +2 -2
- package/dist/{runtime-discord-ops.runtime-CmStqYK4.js → runtime-discord-ops.runtime-8w-055sR.js} +46 -46
- package/dist/{runtime-slack-ops.runtime-Cm1935hR.js → runtime-slack-ops.runtime-XJJrByCY.js} +48 -48
- package/dist/{runtime-telegram-ops.runtime-CKozoVxf.js → runtime-telegram-ops.runtime-wOdrd2eH.js} +46 -46
- package/dist/{sandbox-cli-BIyJ-1r-.js → sandbox-cli-CvFmY6Kq.js} +46 -46
- package/dist/{search-manager-BVE1EPHv.js → search-manager-ZNiamJHa.js} +6 -6
- package/dist/{search-manager-DMTYqpmg.js → search-manager-zaZ4tAYz.js} +5 -5
- package/dist/{secrets-cli-CMMtWzst.js → secrets-cli-D5a_lvAP.js} +47 -47
- package/dist/{security-cli-Bw4cVkTN.js → security-cli-DJovxmST.js} +47 -47
- package/dist/{send-CfI8y11o.js → send-C3KhjjcU.js} +1 -1
- package/dist/{send-C8HDmafP.js → send-CIkS5fLj.js} +2 -2
- package/dist/{server-0n2tu0ff.js → server-B1z10Ohi.js} +6 -6
- package/dist/{server-node-events-J5-mGOea.js → server-node-events-D3_b2nU-.js} +47 -47
- package/dist/{server-startup-matrix-migration-CMBUtdN2.js → server-startup-matrix-migration-DDRaKUPQ.js} +3 -3
- package/dist/{session-cost-usage-CrPCO4HN.js → session-cost-usage-BwIud0lY.js} +46 -46
- package/dist/{sessions-n_Z6bcbr.js → sessions-B5Pffwj6.js} +3 -3
- package/dist/{sessions-BK_M3Nu1.js → sessions-ClamZkvP.js} +47 -47
- package/dist/{setup-OCrVlmv7.js → setup-B8gsbmH4.js} +18 -18
- package/dist/{setup-core-BVBCTInv.js → setup-core-B6csKf5s.js} +2 -2
- package/dist/{setup-core-z8Q1sgUU.js → setup-core-DkgiVKzw.js} +2 -2
- package/dist/{setup-entry-CvuaW-4I.js → setup-entry-C8XH3da9.js} +2 -2
- package/dist/{setup-entry-Jf6V23s6.js → setup-entry-CMSlnfft.js} +3 -3
- package/dist/{setup-entry-Bo3chgoG.js → setup-entry-CZVAwPKZ.js} +2 -2
- package/dist/{setup-entry-Co-YP41_.js → setup-entry-Duh-ewBV.js} +3 -3
- package/dist/{setup-entry-BnSZlMP1.js → setup-entry-ksUWY45r.js} +2 -2
- package/dist/{setup-entry-BNSYJMzp.js → setup-entry-vQgAuveW.js} +2 -2
- package/dist/{setup-group-access-BYV3O8yu.js → setup-group-access-CTlnq-M9.js} +1 -1
- package/dist/{setup-surface-B6XBqyMJ.js → setup-surface-B7uYEI9F.js} +2 -2
- package/dist/{setup-surface-fixjWejm.js → setup-surface-CMgQr2R9.js} +5 -5
- package/dist/{setup-surface-CzzV3QV6.js → setup-surface-Yd-YLGfa.js} +46 -46
- package/dist/{setup-wizard-proxy-DFDQV7FN.js → setup-wizard-proxy-CHGAY6ob.js} +1 -1
- package/dist/{setup.finalize-WT9kXSLX.js → setup.finalize-C2bq4D8j.js} +58 -58
- package/dist/{setup.gateway-config-Bp50kjo3.js → setup.gateway-config-BGgVOvQf.js} +48 -48
- package/dist/{shared-CyR3Ki--.js → shared-BEMZg0vb.js} +5 -5
- package/dist/{shared-DXzPv5D7.js → shared-BYRyVoVx.js} +5 -5
- package/dist/{shared-DCOVJ3QB.js → shared-Bj3fwdyM.js} +4 -4
- package/dist/{shared-B8_JHpU2.js → shared-CSydqOgE.js} +4 -4
- package/dist/{shared-C3fKAUbw.js → shared-DLAg-pKT.js} +3 -3
- package/dist/{signal-D16eMrBf.js → signal-Dh6z2uaT.js} +5 -5
- package/dist/{signal-oGrspg1k.js → signal-FEtxekyc.js} +46 -46
- package/dist/{skills-cli-CY6lUTRv.js → skills-cli-9NuRJd3Z.js} +5 -5
- package/dist/{slack-ueYeeNF7.js → slack-Ci1VArkq.js} +48 -48
- package/dist/{slack-B1GgT1_u.js → slack-CjslLjTc.js} +5 -5
- package/dist/{slash-commands.runtime-1q-llUpe.js → slash-commands.runtime-COXzcGjL.js} +46 -46
- package/dist/{slash-dispatch.runtime-BqJ1FZZ6.js → slash-dispatch.runtime-D5j8d7dg.js} +47 -47
- package/dist/{slash-skill-commands.runtime-D-BEZgQ1.js → slash-skill-commands.runtime-6U65Nany.js} +46 -46
- package/dist/{status-CnKcjD2h.js → status-BWUft8B5.js} +16 -16
- package/dist/{status-C1BR9Hft.js → status-BjV1ysoW.js} +50 -50
- package/dist/{status-D_1nxvoi.js → status-CM77XYRR.js} +4 -4
- package/dist/{status-Dp3OriYl.js → status-D7XHAzLz.js} +46 -46
- package/dist/{status-DoSH4nEL.js → status-DwO4xEHI.js} +54 -54
- package/dist/{status-json-DwNPzoCk.js → status-json-BYDBfkr3.js} +19 -19
- package/dist/{status-B45v-A8b.js → status-yoA_KX2O.js} +1 -1
- package/dist/{status.link-channel-Cz8GoHZ2.js → status.link-channel-DkISMfW8.js} +2 -2
- package/dist/{status.scan.deps.runtime-BQGei2B_.js → status.scan.deps.runtime-B6__B0kL.js} +14 -14
- package/dist/{status.scan.runtime-D4HkKTZu.js → status.scan.runtime-BAkcX3vO.js} +2 -2
- package/dist/{status.summary-Dxo5qDuD.js → status.summary-DNaMhaXy.js} +8 -8
- package/dist/{subagent-orphan-recovery-BPa7yoId.js → subagent-orphan-recovery-DtK8inah.js} +46 -46
- package/dist/{subagent-registry-runtime-B6homy_H.js → subagent-registry-runtime-02s7QJo3.js} +46 -46
- package/dist/{synology-chat-DY8xNv_g.js → synology-chat-QURTpvMf.js} +2 -2
- package/dist/{system-cli-CkWRbLu4.js → system-cli-BXd7evEt.js} +7 -7
- package/dist/{system-run-command-jY6Is_ri.js → system-run-command-CQCx0f24.js} +1 -1
- package/dist/telegram/audit.js +1 -1
- package/dist/telegram/token.js +46 -46
- package/dist/{telegram-uQdpyLeS.js → telegram-Btwvg0PX.js} +46 -46
- package/dist/{telegram-Bnigf1Qe.js → telegram-Dh5gM1mc.js} +7 -7
- package/dist/{tool-policy-match-BLASiL8y.js → tool-policy-match-B6J0bSfQ.js} +1 -1
- package/dist/{tui-Dj52JiFV.js → tui-CKGcNyM8.js} +6 -6
- package/dist/{tui-cli-B4SN4wzX.js → tui-cli-D3CLnnB9.js} +47 -47
- package/dist/{update-cli-CEAEBCp2.js → update-cli-DQ4j_nIh.js} +69 -69
- package/dist/{update-offset-store-Bp1RjZK2.js → update-offset-store-RxVdgbyo.js} +46 -46
- package/dist/{upsert-with-lock-CFIy4b7I.js → upsert-with-lock-BqkAnFym.js} +1 -1
- package/dist/{web-media-BJ-azd7j.js → web-media-BM1Mg6AN.js} +1 -1
- package/dist/{webhook-shared-DYKTXPVw.js → webhook-shared-UDKLpQnU.js} +1 -1
- package/dist/{webhooks-cli-CEBJbLqS.js → webhooks-cli-Ca3PlK8h.js} +5 -5
- package/dist/{whatsapp-63jqHVrE.js → whatsapp-CHEvDa2g.js} +46 -46
- package/dist/{with-timeout-CvaBvNie.js → with-timeout-CvBH67nj.js} +2 -2
- package/dist/{workspace-DuH1agxz.js → workspace-uCYzunu4.js} +5 -33
- package/dist/{zalo-CTrI2C4i.js → zalo-Dr4ysJLW.js} +1 -1
- package/dist/{zalo-Sw_XHo3-.js → zalo-keqX1Wnx.js} +2 -2
- package/docs/concepts/agent-workspace.md +0 -5
- package/docs/concepts/memory.md +6 -12
- package/docs/plans/2026-03-22-semantic-cache-telemetry-docs-plan.md +1431 -0
- package/docs/plans/2026-03-22-supermemory-steals-plan.md +1679 -0
- package/docs/plans/2026-03-23-almost-perfect-sprint-plan.md +1080 -0
- package/docs/plans/2026-03-23-master-steal-list.md +224 -0
- package/docs/plans/2026-03-23-memory-md-deprecation-plan.md +632 -0
- package/docs/plans/2026-03-23-production-readiness-e2e-plan.md +659 -0
- package/docs/plans/2026-03-23-supermemory-audit-fixes-plan.md +1291 -0
- package/docs/reference/clawmongo-vs-default-memory.md +2 -2
- package/docs/reference/heart-brain-boundary.md +8 -10
- package/docs/reference/memory-config.md +3 -4
- package/docs/reference/mongodb-capabilities.md +246 -9
- package/docs/reference/templates/AGENTS.md +5 -10
- package/docs/research/2026-03-22-atlas-local-preview-web.md +41 -31
- package/docs/research/2026-03-23-agent-management-ui-github.md +482 -0
- package/docs/research/2026-03-23-almost-perfect-mongodb-docs.md +255 -0
- package/docs/research/2026-03-23-company-os-agent-ui-web.md +511 -0
- package/docs/research/2026-03-23-supermemory-audit-fixes-mongodb-research.md +995 -0
- package/docs/start/clawmongo-getting-started.md +1 -1
- package/package.json +1 -1
- /package/dist/{memory-BAVM2Jxh.js → memory-CcbELE82.js} +0 -0
|
@@ -0,0 +1,1291 @@
|
|
|
1
|
+
# SuperMemory Audit Fixes Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED: Follow this plan task-by-task using TDD.
|
|
4
|
+
> **Audit Source:** Two audit agents found 12 dead code issues (3 HIGH) and 19 improvement findings (3 CRITICAL, 5 HIGH, 6 MEDIUM).
|
|
5
|
+
> **Research:** See `docs/research/2026-03-23-supermemory-audit-fixes-mongodb-research.md` for MongoDB documentation research.
|
|
6
|
+
|
|
7
|
+
**Goal:** Fix all CRITICAL + HIGH issues from the supermemory audit, plus quick-win MEDIUMs. 15 fixes total across 9 files.
|
|
8
|
+
|
|
9
|
+
**Architecture:** Surgical fixes to existing modules. No new collections, no new files (except tests). Manual RRF for score normalization. `bulkWrite` for N+1 entity upserts. `$percentile` for server-side latency stats.
|
|
10
|
+
|
|
11
|
+
**Tech Stack:** TypeScript ESM, MongoDB latest (atlas-local:preview — always latest version, currently 8.2+), Vitest
|
|
12
|
+
|
|
13
|
+
**MongoDB Version Policy:** ClawMongo targets ONLY `mongodb-atlas-local:preview` which always ships the latest MongoDB. No version fallbacks, no backward compatibility concerns, no feature-gating by version. Use the most innovative features available.
|
|
14
|
+
|
|
15
|
+
**Prerequisites:** All existing tests pass. `pnpm test -- src/memory` green baseline.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Plan: SuperMemory Audit Fixes
|
|
20
|
+
|
|
21
|
+
### Request Summary
|
|
22
|
+
|
|
23
|
+
- Fix 15 audit findings (3 CRITICAL, 5 HIGH, 7 MEDIUM quick-wins) to harden the supermemory subsystem.
|
|
24
|
+
|
|
25
|
+
### Requirements Snapshot
|
|
26
|
+
|
|
27
|
+
- C1: Add `AbortSignal.timeout(10_000)` to Voyage rerank API fetch
|
|
28
|
+
- C2: Add `synthesizeProfile()` method to manager; split `$or` in `$lookup` to two indexed `$eq` lookups
|
|
29
|
+
- C3: Implement manual RRF in `searchV2` to normalize scores across paths
|
|
30
|
+
- H1: Replace sequential entity/relation upserts with `bulkWrite({ ordered: false })`
|
|
31
|
+
- H2: Remove `LLMEntityExtractor` config false bridge; add explicit log warning for `graph.entityExtraction` config
|
|
32
|
+
- H3: Throw validation error for "llm"/"hyde" query rewrite methods instead of silent fallback
|
|
33
|
+
- H4: Derive cache TTL from `pathsExecuted` (per-document TTL) instead of static config
|
|
34
|
+
- H5: Filter empty snippets before sending to reranker
|
|
35
|
+
- H6: Entity-extraction telemetry: add `emitTelemetry` to `extractAndUpsertEntities`
|
|
36
|
+
- H7: Clean up aggressive synonym expansions, add max expansion ratio
|
|
37
|
+
- M1: Emit reranker telemetry on failure path
|
|
38
|
+
- M2: Default limit for `getEventsByTimeRange` raw-window path in searchV2 (50)
|
|
39
|
+
- M3: Split profile entity `$lookup` `$or` into two `$eq` lookups (merged with C2)
|
|
40
|
+
- M4: Replace `$push` + client-side percentiles with `$percentile` aggregation
|
|
41
|
+
|
|
42
|
+
### Constraints Snapshot
|
|
43
|
+
|
|
44
|
+
- MongoDB-only (Community + mongot + atlas-local:preview)
|
|
45
|
+
- No new collections or search indexes
|
|
46
|
+
- Must not break existing 81/81 e2e tests or ~600+ unit tests
|
|
47
|
+
- TDD: write test first, then implement
|
|
48
|
+
- Fire-and-forget telemetry pattern via `emitTelemetry`
|
|
49
|
+
- `=== true` for disabled-by-default features
|
|
50
|
+
- DO NOT USE mongodb-agent-skills; use ONLY mcp**mongodb**search-knowledge MCP
|
|
51
|
+
|
|
52
|
+
### In Scope
|
|
53
|
+
|
|
54
|
+
- All 15 fixes listed in Requirements Snapshot
|
|
55
|
+
- Tests for each fix
|
|
56
|
+
- Score normalization via manual RRF across search paths
|
|
57
|
+
- `bulkWrite` batch optimization for entity extraction
|
|
58
|
+
- `$percentile` server-side aggregation for latency stats
|
|
59
|
+
|
|
60
|
+
### Out Of Scope
|
|
61
|
+
|
|
62
|
+
- Change Stream watcher for async LLM enrichment (deferred — needs separate design phase)
|
|
63
|
+
- `$rankFusion`/`$scoreFusion` for cross-path fusion (not a version issue — these operators only work on a single collection; ClawMongo merges results from multiple collections, so manual RRF remains the correct approach)
|
|
64
|
+
- LLM function injection from agent runtime (architectural seam — runtime doesn't expose LLM callable to memory layer yet)
|
|
65
|
+
- New collections, new search indexes
|
|
66
|
+
|
|
67
|
+
### Planning Mode
|
|
68
|
+
|
|
69
|
+
- Plan mode: `execution_plan`
|
|
70
|
+
- Verification rigor: `standard`
|
|
71
|
+
|
|
72
|
+
### Open Decisions
|
|
73
|
+
|
|
74
|
+
- None
|
|
75
|
+
|
|
76
|
+
### Differences From Agreement
|
|
77
|
+
|
|
78
|
+
- None
|
|
79
|
+
|
|
80
|
+
### Recommended Defaults
|
|
81
|
+
|
|
82
|
+
- RRF constant k=60 (standard from original RRF paper, matches existing `mongodb-hybrid.ts`)
|
|
83
|
+
- Rerank fetch timeout: 10 seconds (generous for cross-encoder API call over network)
|
|
84
|
+
- Raw-window event limit: 50 (balances context window budget vs recency)
|
|
85
|
+
- Cache TTL mapping: vector/hybrid -> `conversationTtlSec`, kb -> `kbTtlSec`, structured/episodic/graph -> `conversationTtlSec`, profile -> `kbTtlSec`
|
|
86
|
+
- Synonym expansion max ratio: 3x (original word count)
|
|
87
|
+
|
|
88
|
+
### Current State
|
|
89
|
+
|
|
90
|
+
- `src/memory/mongodb-reranker.ts:81` — `fetch()` with no timeout or AbortSignal
|
|
91
|
+
- `src/memory/mongodb-manager.ts:2688-3026` — `searchV2` merges raw scores from different paths (vector 0-1, BM25 0-inf, episode 0.85-synthetic, graph 0.25-0.9 synthetic)
|
|
92
|
+
- `src/memory/mongodb-profile.ts:165-183` — `$lookup` with `$or` in `$expr` (cannot use index)
|
|
93
|
+
- `src/memory/mongodb-manager.ts` — no `synthesizeProfile` delegation method
|
|
94
|
+
- `src/memory/mongodb-graph.ts:898-913` — sequential `upsertEntity()` in loop (N+1)
|
|
95
|
+
- `src/memory/mongodb-graph.ts:917-955` — sequential `upsertRelation()` + `upsertEntityLink()` in loop
|
|
96
|
+
- `src/memory/mongodb-entity-extractor.ts:170-207` — `LLMEntityExtractor` class exists but config never creates it
|
|
97
|
+
- `src/memory/backend-config.ts:354-363` — `entityExtraction` config fields resolved but never consumed
|
|
98
|
+
- `src/memory/mongodb-query-rewriter.ts:137-143` — "llm"/"hyde" silently fall back to synonym-expansion
|
|
99
|
+
- `src/memory/mongodb-manager.ts:817-818` — cache TTL uses static `kbTtlSec` vs `conversationTtlSec` based on `kb.enabled`, not actual paths used
|
|
100
|
+
- `src/memory/mongodb-reranker.ts:78` — sends all candidate snippets to reranker including empty graph strings
|
|
101
|
+
- `src/memory/mongodb-telemetry.ts:20` — `"entity-extraction"` operation defined but never emitted
|
|
102
|
+
- `src/memory/mongodb-query-rewriter.ts:32-45` — `api: ["endpoint", "route", "rest"]` cross-domain expansion
|
|
103
|
+
- `src/memory/mongodb-reranker.ts:141-143` — catch block doesn't emit telemetry
|
|
104
|
+
- `src/memory/mongodb-telemetry.ts:89-112` — `getLatencyStats` loads all durations into client memory
|
|
105
|
+
|
|
106
|
+
### Alternatives
|
|
107
|
+
|
|
108
|
+
- Score normalization: Could use min-max normalization per batch instead of RRF. RRF is simpler, more robust, and already implemented in `mongodb-hybrid.ts`.
|
|
109
|
+
- Entity batch: Could use transactions instead of `bulkWrite`. `bulkWrite` is simpler and sufficient for independent upserts.
|
|
110
|
+
|
|
111
|
+
### Drawbacks
|
|
112
|
+
|
|
113
|
+
- Manual RRF discards magnitude information (a score of 0.99 vs 0.50 both become rank-based). Acceptable tradeoff — raw scores were already incomparable across paths.
|
|
114
|
+
- `$percentile` is approximate (t-digest algorithm). Acceptable — telemetry stats don't need exact values.
|
|
115
|
+
- Removing aggressive synonym expansions may slightly reduce recall for abbreviated queries. Acceptable — false positives were worse than missed expansions.
|
|
116
|
+
|
|
117
|
+
### Critical-Path Verification Design
|
|
118
|
+
|
|
119
|
+
- Behavior contract: Not required
|
|
120
|
+
- Edge-case catalog: Concise — empty results, single-result paths, all-paths-fail, empty snippets, zero-entity extraction
|
|
121
|
+
- Provable properties: None
|
|
122
|
+
- Purity boundary map: Not required
|
|
123
|
+
- Verification strategy: Unit tests per fix + existing e2e regression
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Relevant Codebase Files
|
|
128
|
+
|
|
129
|
+
### Files to Modify
|
|
130
|
+
|
|
131
|
+
- `src/memory/mongodb-reranker.ts` — timeout + empty snippet filter + failure telemetry (C1, H5, M1)
|
|
132
|
+
- `src/memory/mongodb-manager.ts` — RRF normalization in searchV2 + cache TTL from paths + raw-window limit + synthesizeProfile method (C3, H4, M2, C2-manager)
|
|
133
|
+
- `src/memory/mongodb-profile.ts` — split $or $lookup into two indexed $eq lookups (C2/M3)
|
|
134
|
+
- `src/memory/mongodb-graph.ts` — bulkWrite for entity/relation upserts + entity-extraction telemetry (H1, H6)
|
|
135
|
+
- `src/memory/mongodb-entity-extractor.ts` — document LLM stub clearly (H2)
|
|
136
|
+
- `src/memory/backend-config.ts` — add log warning for entity extraction config (H2)
|
|
137
|
+
- `src/memory/mongodb-query-rewriter.ts` — throw on unimplemented methods + clean synonym map (H3, H7)
|
|
138
|
+
- `src/memory/mongodb-telemetry.ts` — $percentile aggregation (M4)
|
|
139
|
+
- `src/memory/mongodb-query-cache.ts` — no changes needed (TTL logic change is in manager)
|
|
140
|
+
|
|
141
|
+
### Test Files to Modify/Create
|
|
142
|
+
|
|
143
|
+
- `src/memory/mongodb-reranker.test.ts` — new or extended (C1, H5, M1)
|
|
144
|
+
- `src/memory/mongodb-manager.test.ts` — extended (C3, H4, M2, C2-manager)
|
|
145
|
+
- `src/memory/mongodb-profile.test.ts` — new (C2/M3)
|
|
146
|
+
- `src/memory/mongodb-graph.test.ts` — extended (H1, H6)
|
|
147
|
+
- `src/memory/mongodb-entity-extractor.test.ts` — extended (H2)
|
|
148
|
+
- `src/memory/backend-config.test.ts` — extended (H2)
|
|
149
|
+
- `src/memory/mongodb-query-rewriter.test.ts` — new or extended (H3, H7)
|
|
150
|
+
- `src/memory/mongodb-telemetry.test.ts` — extended (M4)
|
|
151
|
+
|
|
152
|
+
### Patterns to Follow
|
|
153
|
+
|
|
154
|
+
- `src/memory/mongodb-hybrid.ts` (lines 48-66) — existing RRF scoring functions (rrfScore, normalizeVectorScore, normalizeBM25Score)
|
|
155
|
+
- `src/memory/mongodb-telemetry.ts` (lines 58-65) — fire-and-forget emitTelemetry pattern
|
|
156
|
+
- `src/memory/mongodb-graph.ts` (lines 182-229) — upsertEntity pattern (convert to bulkWrite)
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Phase 1: CRITICAL Fixes (C1 + C2 + C3)
|
|
161
|
+
|
|
162
|
+
> **Exit Criteria:** Reranker fetch has timeout. Profile $lookup uses indexed queries. searchV2 normalizes scores via RRF. All existing tests pass.
|
|
163
|
+
|
|
164
|
+
### Task 1.1: Reranker Fetch Timeout (C1)
|
|
165
|
+
|
|
166
|
+
**Files:**
|
|
167
|
+
|
|
168
|
+
- Modify: `src/memory/mongodb-reranker.ts:81`
|
|
169
|
+
- Test: `src/memory/mongodb-reranker.test.ts`
|
|
170
|
+
|
|
171
|
+
**Step 1: Write failing test**
|
|
172
|
+
|
|
173
|
+
Test that `crossEncoderRerank` aborts when the fetch takes longer than 10 seconds.
|
|
174
|
+
Use a mock server or mock `fetch` that never resolves, verify the function returns fallback results within a reasonable timeframe.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
test("crossEncoderRerank aborts on fetch timeout", async () => {
|
|
178
|
+
// Mock fetch that hangs
|
|
179
|
+
const originalFetch = globalThis.fetch;
|
|
180
|
+
globalThis.fetch = vi.fn(() => new Promise(() => {})); // never resolves
|
|
181
|
+
try {
|
|
182
|
+
const result = await crossEncoderRerank({
|
|
183
|
+
db: mockDb,
|
|
184
|
+
prefix: "test_",
|
|
185
|
+
agentId: "agent1",
|
|
186
|
+
query: "test query",
|
|
187
|
+
results: twoResults,
|
|
188
|
+
config: { ...defaultConfig, enabled: true, voyageApiKey: "pa-test" },
|
|
189
|
+
});
|
|
190
|
+
// Should fall back gracefully, not hang
|
|
191
|
+
expect(result.reranked).toBe(false);
|
|
192
|
+
expect(result.results).toEqual(twoResults);
|
|
193
|
+
} finally {
|
|
194
|
+
globalThis.fetch = originalFetch;
|
|
195
|
+
}
|
|
196
|
+
}, 15_000); // test timeout > rerank timeout
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Step 2: Run test, verify it fails (hangs or times out)**
|
|
200
|
+
|
|
201
|
+
Run: `pnpm test -- src/memory/mongodb-reranker.test.ts`
|
|
202
|
+
Expected: Test hangs/times out because fetch has no timeout.
|
|
203
|
+
|
|
204
|
+
**Step 3: Implement `AbortSignal.timeout(10_000)` on fetch**
|
|
205
|
+
|
|
206
|
+
In `src/memory/mongodb-reranker.ts`, add signal to the fetch call at line 81:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const response = await fetch(rerankUrl, {
|
|
210
|
+
method: "POST",
|
|
211
|
+
headers: {
|
|
212
|
+
"Content-Type": "application/json",
|
|
213
|
+
Authorization: `Bearer ${config.voyageApiKey}`,
|
|
214
|
+
},
|
|
215
|
+
body: JSON.stringify({
|
|
216
|
+
model: config.model,
|
|
217
|
+
query: config.instruction ? `${config.instruction}\n${query}` : query,
|
|
218
|
+
documents,
|
|
219
|
+
top_k: candidates.length,
|
|
220
|
+
}),
|
|
221
|
+
signal: AbortSignal.timeout(10_000),
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Step 4: Run test, verify it passes**
|
|
226
|
+
|
|
227
|
+
Run: `pnpm test -- src/memory/mongodb-reranker.test.ts`
|
|
228
|
+
Expected: PASS — function returns fallback within timeout.
|
|
229
|
+
|
|
230
|
+
### Task 1.2: Profile $lookup Index Fix (C2/M3)
|
|
231
|
+
|
|
232
|
+
**Files:**
|
|
233
|
+
|
|
234
|
+
- Modify: `src/memory/mongodb-profile.ts:165-183`
|
|
235
|
+
- Test: `src/memory/mongodb-profile.test.ts` (new or extend)
|
|
236
|
+
|
|
237
|
+
**Step 1: Write test**
|
|
238
|
+
|
|
239
|
+
Test that `synthesizeProfile` returns correct `topEntities` when relations reference entities via both `fromEntityId` and `toEntityId`. Verify the pipeline produces the same results as before (functional equivalence).
|
|
240
|
+
|
|
241
|
+
**Step 2: Implement the split**
|
|
242
|
+
|
|
243
|
+
Replace the single `$lookup` with `$or` (lines 165-183 of `mongodb-profile.ts`) with two separate `$lookup` stages, each using `$count` inside the sub-pipeline (memory-efficient — no full relation docs materialized):
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// Lookup 1: outgoing relations count (uses index on fromEntityId)
|
|
247
|
+
{
|
|
248
|
+
$lookup: {
|
|
249
|
+
from: `${prefix}relations`,
|
|
250
|
+
let: { eid: "$entityId" },
|
|
251
|
+
pipeline: [
|
|
252
|
+
{ $match: { $expr: { $eq: ["$fromEntityId", "$$eid"] }, ...scopeFilter } },
|
|
253
|
+
{ $count: "cnt" },
|
|
254
|
+
],
|
|
255
|
+
as: "outRels",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
// Lookup 2: incoming relations count (uses index on toEntityId)
|
|
259
|
+
{
|
|
260
|
+
$lookup: {
|
|
261
|
+
from: `${prefix}relations`,
|
|
262
|
+
let: { eid: "$entityId" },
|
|
263
|
+
pipeline: [
|
|
264
|
+
{ $match: { $expr: { $eq: ["$toEntityId", "$$eid"] }, ...scopeFilter } },
|
|
265
|
+
{ $count: "cnt" },
|
|
266
|
+
],
|
|
267
|
+
as: "inRels",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
// Sum the two counts (no full relation docs in memory)
|
|
271
|
+
{
|
|
272
|
+
$addFields: {
|
|
273
|
+
relationCount: {
|
|
274
|
+
$add: [
|
|
275
|
+
{ $ifNull: [{ $arrayElemAt: ["$outRels.cnt", 0] }, 0] },
|
|
276
|
+
{ $ifNull: [{ $arrayElemAt: ["$inRels.cnt", 0] }, 0] },
|
|
277
|
+
],
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**IMPORTANT:** This requires a compound index on `{ toEntityId: 1, agentId: 1, scope: 1, scopeRef: 1 }` in the relations collection. The existing index only covers `fromEntityId`. See Task 1.2b below.
|
|
284
|
+
|
|
285
|
+
**Step 3: Run tests**
|
|
286
|
+
|
|
287
|
+
Run: `pnpm test -- src/memory/mongodb-profile.test.ts`
|
|
288
|
+
Expected: PASS
|
|
289
|
+
|
|
290
|
+
### Task 1.2b: Add toEntityId Compound Index to Relations Collection
|
|
291
|
+
|
|
292
|
+
**Files:**
|
|
293
|
+
|
|
294
|
+
- Modify: `src/memory/mongodb-schema.ts` (RELATIONS_INDEXES array)
|
|
295
|
+
- Test: `src/memory/mongodb-schema.test.ts`
|
|
296
|
+
|
|
297
|
+
**Why:** The existing relations index covers `{ agentId, scope, scopeRef, fromEntityId, type }` but the new split $lookup for incoming relations needs `toEntityId` as a prefix key. Without this, the incoming lookup still does a COLLSCAN. Research ref: M4 — "$expr in $lookup only uses indexes for $eq comparisons."
|
|
298
|
+
|
|
299
|
+
**Step 1: Add index**
|
|
300
|
+
|
|
301
|
+
Add to `RELATIONS_INDEXES` in `mongodb-schema.ts`:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
{ key: { toEntityId: 1, agentId: 1, scope: 1, scopeRef: 1 }, name: "idx_relations_to_entity_scope" },
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Step 2: Update EXPECTED_STANDARD_INDEX_COUNT**
|
|
308
|
+
|
|
309
|
+
Increment the count in schema tests and e2e tests (currently 58 → 59).
|
|
310
|
+
|
|
311
|
+
**Step 3: Run tests**
|
|
312
|
+
|
|
313
|
+
Run: `pnpm test -- src/memory/mongodb-schema.test.ts`
|
|
314
|
+
Expected: PASS
|
|
315
|
+
|
|
316
|
+
### Task 1.3: Add synthesizeProfile to Manager (C2-manager)
|
|
317
|
+
|
|
318
|
+
**Files:**
|
|
319
|
+
|
|
320
|
+
- Modify: `src/memory/mongodb-manager.ts`
|
|
321
|
+
- Test: `src/memory/mongodb-manager.test.ts`
|
|
322
|
+
|
|
323
|
+
**Step 1: Write test**
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
test("synthesizeProfile delegates to standalone function", async () => {
|
|
327
|
+
// Mock the standalone synthesizeProfile
|
|
328
|
+
const result = await manager.synthesizeProfile({ scope: "agent", scopeRef: "agent1" });
|
|
329
|
+
expect(result).toBeDefined();
|
|
330
|
+
expect(result.agentId).toBe("agent1");
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Step 2: Implement delegation**
|
|
335
|
+
|
|
336
|
+
Add a `synthesizeProfile` method to `MongoDBMemoryManager` that delegates to the standalone `synthesizeProfile` function from `mongodb-profile.ts`:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
async synthesizeProfile(params: {
|
|
340
|
+
scope?: MemoryScope;
|
|
341
|
+
scopeRef?: string;
|
|
342
|
+
maxPerType?: number;
|
|
343
|
+
maxEntities?: number;
|
|
344
|
+
maxEpisodes?: number;
|
|
345
|
+
activityWindowMs?: number;
|
|
346
|
+
}): Promise<ProfileSynthesis> {
|
|
347
|
+
return synthesizeProfile({
|
|
348
|
+
db: this.db,
|
|
349
|
+
prefix: this.prefix,
|
|
350
|
+
agentId: this.agentId,
|
|
351
|
+
scope: params.scope ?? "agent",
|
|
352
|
+
scopeRef: params.scopeRef ?? this.agentScopeRef,
|
|
353
|
+
maxPerType: params.maxPerType,
|
|
354
|
+
maxEntities: params.maxEntities,
|
|
355
|
+
maxEpisodes: params.maxEpisodes,
|
|
356
|
+
activityWindowMs: params.activityWindowMs,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Step 3: Run tests**
|
|
362
|
+
|
|
363
|
+
Run: `pnpm test -- src/memory/mongodb-manager.test.ts`
|
|
364
|
+
Expected: PASS
|
|
365
|
+
|
|
366
|
+
### Task 1.4: Score Normalization via Manual RRF (C3)
|
|
367
|
+
|
|
368
|
+
**Files:**
|
|
369
|
+
|
|
370
|
+
- Modify: `src/memory/mongodb-manager.ts:2688-2996` (searchV2 function)
|
|
371
|
+
- Test: `src/memory/mongodb-manager.test.ts`
|
|
372
|
+
|
|
373
|
+
**IMPORTANT:** `MemorySearchResult.filePath` is OPTIONAL. The deduplication function `deduplicateSearchResults` uses `result.snippet` as the dedup key. Use `snippet` (not `filePath`) as the RRF map key.
|
|
374
|
+
|
|
375
|
+
**Step 1: Structural change — preserve per-path result lists**
|
|
376
|
+
|
|
377
|
+
Currently `searchV2` accumulates all results into a flat `results: MemorySearchResult[]` array. To apply per-path RRF, we must also keep per-path lists:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Add alongside existing `const results: MemorySearchResult[] = []`
|
|
381
|
+
const perPathResults: Record<string, MemorySearchResult[]> = {};
|
|
382
|
+
|
|
383
|
+
// In each path's try/catch block, after `results.push(...pathResults)`, also:
|
|
384
|
+
perPathResults[path.path] = pathResults;
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
This applies to ALL paths including backstop paths (procedural backstop ~line 2943-2967, hybrid backstop ~line 2969-2996). Backstop paths must also track their results in `perPathResults`.
|
|
388
|
+
|
|
389
|
+
**Step 2: Write tests**
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
describe("searchV2 score normalization", () => {
|
|
393
|
+
test("results from different paths are RRF-normalized", async () => {
|
|
394
|
+
// Setup: mock paths to return results with different score ranges
|
|
395
|
+
const result = await searchV2(...);
|
|
396
|
+
// All final scores should be RRF-based, in (0, 1] range
|
|
397
|
+
for (const r of result.results) {
|
|
398
|
+
expect(r.score).toBeGreaterThan(0);
|
|
399
|
+
expect(r.score).toBeLessThanOrEqual(1);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("single-path results preserve relative ordering", async () => {
|
|
404
|
+
// When only one path returns results, rank ordering is preserved
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test("backstop path results are also RRF-normalized", async () => {
|
|
408
|
+
// When backstop fires, its results should also get RRF scores
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Step 3: Implement RRF normalization AFTER ALL paths (including backstops)**
|
|
414
|
+
|
|
415
|
+
Place this code AFTER the hybrid backstop block (~line 2996) and BEFORE the final `rerankResults` call:
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import { rrfScore } from "./mongodb-hybrid.js";
|
|
419
|
+
|
|
420
|
+
// RRF normalization: replace raw scores with rank-based scores, summed across paths
|
|
421
|
+
// Uses `snippet` as the dedup key (matches deduplicateSearchResults behavior)
|
|
422
|
+
const rrfMap = new Map<string, number>();
|
|
423
|
+
for (const [_pathName, pathResults] of Object.entries(perPathResults)) {
|
|
424
|
+
// Each path's results are already sorted by native score descending
|
|
425
|
+
for (let rank = 0; rank < pathResults.length; rank++) {
|
|
426
|
+
const key = pathResults[rank].snippet;
|
|
427
|
+
rrfMap.set(key, (rrfMap.get(key) ?? 0) + rrfScore(rank + 1));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Apply fused RRF scores back to the flat results array before dedup
|
|
432
|
+
for (const r of results) {
|
|
433
|
+
const rrfVal = rrfMap.get(r.snippet);
|
|
434
|
+
if (rrfVal !== undefined) r.score = rrfVal;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Dedup then re-sort by fused score (existing deduplicateSearchResults call)
|
|
438
|
+
const deduped = deduplicateSearchResults(results);
|
|
439
|
+
deduped.sort((a, b) => b.score - a.score);
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Step 3: Run tests**
|
|
443
|
+
|
|
444
|
+
Run: `pnpm test -- src/memory/mongodb-manager.test.ts`
|
|
445
|
+
Expected: PASS
|
|
446
|
+
|
|
447
|
+
**Step 4: Commit Phase 1**
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
scripts/committer "Fix(memory): CRITICAL audit fixes — rerank timeout, profile $lookup index, RRF score normalization, synthesizeProfile delegation" \
|
|
451
|
+
src/memory/mongodb-reranker.ts \
|
|
452
|
+
src/memory/mongodb-profile.ts \
|
|
453
|
+
src/memory/mongodb-manager.ts \
|
|
454
|
+
src/memory/mongodb-reranker.test.ts \
|
|
455
|
+
src/memory/mongodb-profile.test.ts \
|
|
456
|
+
src/memory/mongodb-manager.test.ts
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Phase 2: HIGH Fixes — Dead Code + Config (H2, H3)
|
|
462
|
+
|
|
463
|
+
> **Exit Criteria:** LLM entity extractor config is honest about stub status. Query rewriter throws on unimplemented methods. Entity extraction config logs warning.
|
|
464
|
+
|
|
465
|
+
### Task 2.1: LLMEntityExtractor Config Honesty (H2)
|
|
466
|
+
|
|
467
|
+
**Files:**
|
|
468
|
+
|
|
469
|
+
- Modify: `src/memory/backend-config.ts:354-363`
|
|
470
|
+
- Modify: `src/memory/mongodb-entity-extractor.ts` (add clear documentation)
|
|
471
|
+
- Test: `src/memory/backend-config.test.ts`
|
|
472
|
+
|
|
473
|
+
**Step 1: Write test**
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
test("resolveMongoDBConfig logs warning when entityExtraction.method is 'llm' but no LLM function available", () => {
|
|
477
|
+
// Config with method: "llm" should produce a resolved config with a warning log
|
|
478
|
+
const spy = vi.spyOn(log, "warn");
|
|
479
|
+
const resolved = resolveMongoDBConfig({
|
|
480
|
+
graph: { entityExtraction: { method: "llm" } },
|
|
481
|
+
});
|
|
482
|
+
expect(spy).toHaveBeenCalledWith(
|
|
483
|
+
expect.stringContaining(
|
|
484
|
+
"entity extraction method 'llm' configured but LLM function not injected",
|
|
485
|
+
),
|
|
486
|
+
);
|
|
487
|
+
// Config field stays as-is (method: "llm") for future injection
|
|
488
|
+
expect(resolved.graph.entityExtraction.method).toBe("llm");
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Step 2: Implement warning**
|
|
493
|
+
|
|
494
|
+
In `backend-config.ts`, after resolving `graph.entityExtraction`, add:
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
if (resolved.graph.entityExtraction.method === "llm") {
|
|
498
|
+
log.warn(
|
|
499
|
+
"entity extraction method 'llm' configured but LLM function not injected — regex extractor will be used at runtime. " +
|
|
500
|
+
"Set graph.entityExtraction.method to 'regex' to suppress this warning.",
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Step 3: Run tests**
|
|
506
|
+
|
|
507
|
+
Run: `pnpm test -- src/memory/backend-config.test.ts`
|
|
508
|
+
Expected: PASS
|
|
509
|
+
|
|
510
|
+
### Task 2.2: Query Rewriter Validation Error (H3)
|
|
511
|
+
|
|
512
|
+
**Files:**
|
|
513
|
+
|
|
514
|
+
- Modify: `src/memory/mongodb-query-rewriter.ts:131-148`
|
|
515
|
+
- Test: `src/memory/mongodb-query-rewriter.test.ts` (new or extend)
|
|
516
|
+
|
|
517
|
+
**Step 1: Write tests**
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
test("rewriteQuery throws ConfigValidationError for 'llm' method", async () => {
|
|
521
|
+
await expect(
|
|
522
|
+
rewriteQuery({
|
|
523
|
+
db: mockDb,
|
|
524
|
+
prefix: "test_",
|
|
525
|
+
agentId: "a1",
|
|
526
|
+
query: "test",
|
|
527
|
+
config: { enabled: true, method: "llm", maxTokens: 128 },
|
|
528
|
+
}),
|
|
529
|
+
).rejects.toThrow(/not yet implemented/);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
test("rewriteQuery throws ConfigValidationError for 'hyde' method", async () => {
|
|
533
|
+
await expect(
|
|
534
|
+
rewriteQuery({
|
|
535
|
+
db: mockDb,
|
|
536
|
+
prefix: "test_",
|
|
537
|
+
agentId: "a1",
|
|
538
|
+
query: "test",
|
|
539
|
+
config: { enabled: true, method: "hyde", maxTokens: 128 },
|
|
540
|
+
}),
|
|
541
|
+
).rejects.toThrow(/not yet implemented/);
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**Step 2: Implement validation error**
|
|
546
|
+
|
|
547
|
+
Replace the silent fallback in `mongodb-query-rewriter.ts` lines 137-143:
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
case "llm":
|
|
551
|
+
case "hyde":
|
|
552
|
+
throw new Error(
|
|
553
|
+
`Query rewrite method "${config.method}" is not yet implemented. ` +
|
|
554
|
+
`Use "synonym-expansion" or disable query rewriting (queryRewriting.enabled: false).`,
|
|
555
|
+
);
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Step 3: Run tests**
|
|
559
|
+
|
|
560
|
+
Run: `pnpm test -- src/memory/mongodb-query-rewriter.test.ts`
|
|
561
|
+
Expected: PASS
|
|
562
|
+
|
|
563
|
+
### Task 2.3: Clean Up Aggressive Synonym Expansions (H7)
|
|
564
|
+
|
|
565
|
+
**Files:**
|
|
566
|
+
|
|
567
|
+
- Modify: `src/memory/mongodb-query-rewriter.ts:32-45`
|
|
568
|
+
- Test: `src/memory/mongodb-query-rewriter.test.ts`
|
|
569
|
+
|
|
570
|
+
**Step 1: Write tests**
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
test("'api' does not expand to unrelated domains", () => {
|
|
574
|
+
const result = expandSynonyms("api");
|
|
575
|
+
expect(result).not.toContain("route");
|
|
576
|
+
expect(result).not.toContain("rest");
|
|
577
|
+
// Should only contain api (original) + direct abbreviation expansions
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
test("expansion respects max ratio of 3x original word count", () => {
|
|
581
|
+
const result = expandSynonyms("auth db api");
|
|
582
|
+
const originalCount = 3;
|
|
583
|
+
const expandedCount = result.split(/\s+/).length;
|
|
584
|
+
expect(expandedCount).toBeLessThanOrEqual(originalCount * 3);
|
|
585
|
+
});
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Step 2: Implement**
|
|
589
|
+
|
|
590
|
+
1. Remove cross-domain expansions from SYNONYM_MAP:
|
|
591
|
+
- `api: ["endpoint", "route", "rest"]` -> REMOVE entirely (api is not a synonym of route/rest)
|
|
592
|
+
- `ui: ["interface", "frontend", "component"]` -> REMOVE (too broad)
|
|
593
|
+
- Keep domain-specific: `auth`, `db`, `bug`, `perf`, `config`, `deps`, `deploy`, `docs`, `test`, `refactor`
|
|
594
|
+
|
|
595
|
+
**NOTE:** Existing tests in `mongodb-query-rewriter.test.ts` likely assert "api" expands to include "endpoint". Those tests MUST be updated to match the new SYNONYM_MAP. This is expected — the old behavior was wrong (cross-domain false positives).
|
|
596
|
+
|
|
597
|
+
2. Add max expansion ratio cap (3x):
|
|
598
|
+
|
|
599
|
+
```typescript
|
|
600
|
+
export function expandSynonyms(query: string): string {
|
|
601
|
+
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
602
|
+
const expanded = new Set(words);
|
|
603
|
+
const maxExpanded = words.length * 3;
|
|
604
|
+
|
|
605
|
+
for (const word of words) {
|
|
606
|
+
if (expanded.size >= maxExpanded) break;
|
|
607
|
+
const abbr = ABBREVIATION_MAP[word];
|
|
608
|
+
if (abbr) expanded.add(abbr);
|
|
609
|
+
const syns = SYNONYM_MAP[word];
|
|
610
|
+
if (syns) {
|
|
611
|
+
for (const syn of syns) {
|
|
612
|
+
if (expanded.size >= maxExpanded) break;
|
|
613
|
+
expanded.add(syn);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return [...expanded].join(" ");
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
**Step 3: Run tests**
|
|
623
|
+
|
|
624
|
+
Run: `pnpm test -- src/memory/mongodb-query-rewriter.test.ts`
|
|
625
|
+
Expected: PASS
|
|
626
|
+
|
|
627
|
+
**Step 4: Commit Phase 2**
|
|
628
|
+
|
|
629
|
+
```bash
|
|
630
|
+
scripts/committer "Fix(memory): HIGH audit fixes — entity extractor config honesty, query rewriter validation, synonym cleanup" \
|
|
631
|
+
src/memory/backend-config.ts \
|
|
632
|
+
src/memory/mongodb-entity-extractor.ts \
|
|
633
|
+
src/memory/mongodb-query-rewriter.ts \
|
|
634
|
+
src/memory/backend-config.test.ts \
|
|
635
|
+
src/memory/mongodb-query-rewriter.test.ts
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## Phase 3: HIGH Fixes — Performance + Telemetry (H1, H4, H5, H6)
|
|
641
|
+
|
|
642
|
+
> **Exit Criteria:** Entity upserts use bulkWrite. Cache TTL derived from paths. Empty snippets filtered from reranker. Entity-extraction telemetry emitted.
|
|
643
|
+
|
|
644
|
+
### Task 3.1: bulkWrite for Entity Upserts (H1)
|
|
645
|
+
|
|
646
|
+
**Files:**
|
|
647
|
+
|
|
648
|
+
- Modify: `src/memory/mongodb-graph.ts:896-955` (extractAndUpsertEntities)
|
|
649
|
+
- Test: `src/memory/mongodb-graph.test.ts`
|
|
650
|
+
|
|
651
|
+
**Step 1: Write test**
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
test("extractAndUpsertEntities uses bulkWrite for entities", async () => {
|
|
655
|
+
const bulkWriteSpy = vi.spyOn(entitiesCol, "bulkWrite");
|
|
656
|
+
await extractAndUpsertEntities({
|
|
657
|
+
db: mockDb,
|
|
658
|
+
prefix: "test_",
|
|
659
|
+
agentId: "a1",
|
|
660
|
+
eventContent: "@alice mentioned @bob working on #projectX",
|
|
661
|
+
scope: "agent",
|
|
662
|
+
sourceEventId: "ev1",
|
|
663
|
+
});
|
|
664
|
+
// Should call bulkWrite once instead of N sequential upsertEntity calls
|
|
665
|
+
expect(bulkWriteSpy).toHaveBeenCalledTimes(1);
|
|
666
|
+
const ops = bulkWriteSpy.mock.calls[0][0];
|
|
667
|
+
expect(ops.length).toBeGreaterThanOrEqual(2); // at least alice + bob
|
|
668
|
+
// Each op should be updateOne with upsert: true
|
|
669
|
+
for (const op of ops) {
|
|
670
|
+
expect(op).toHaveProperty("updateOne");
|
|
671
|
+
expect(op.updateOne.upsert).toBe(true);
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
**Step 2: Implement bulkWrite**
|
|
677
|
+
|
|
678
|
+
Replace the sequential entity upsert loop (lines 898-913) with:
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
// Batch upsert entities via bulkWrite
|
|
682
|
+
const entityOps = extracted.map((entity) => ({
|
|
683
|
+
updateOne: {
|
|
684
|
+
filter: { entityId: entity.entityId, agentId, scope, scopeRef },
|
|
685
|
+
update: {
|
|
686
|
+
$set: {
|
|
687
|
+
entityId: entity.entityId,
|
|
688
|
+
name: entity.name,
|
|
689
|
+
type: entity.type,
|
|
690
|
+
agentId,
|
|
691
|
+
scope,
|
|
692
|
+
scopeRef,
|
|
693
|
+
updatedAt: new Date(),
|
|
694
|
+
...(sourceEventId ? { sourceEventIds: [sourceEventId] } : {}),
|
|
695
|
+
},
|
|
696
|
+
$setOnInsert: { createdAt: new Date() },
|
|
697
|
+
},
|
|
698
|
+
upsert: true,
|
|
699
|
+
},
|
|
700
|
+
}));
|
|
701
|
+
if (entityOps.length > 0) {
|
|
702
|
+
await entitiesCollection(db, prefix).bulkWrite(entityOps, { ordered: false });
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
Similarly, batch the relation + entity-link upserts into two `bulkWrite` calls.
|
|
707
|
+
|
|
708
|
+
**CRITICAL: Preserve existing logic.** The pairwise loop (lines 918-955) uses `inferEntityLinkType`, `canonicalizeEntityPair`, `makeEntityLinkId`, and the 6-field compound filter for entity links. The bulkWrite conversion must replicate the EXACT filter/update from `upsertRelation` and `upsertEntityLink` — just batch them. Also preserve the bounded loop indices (`i < 5`, `j < 6`).
|
|
709
|
+
|
|
710
|
+
```typescript
|
|
711
|
+
// Build ops from the pairwise loop (same logic, batched)
|
|
712
|
+
const relationOps = [];
|
|
713
|
+
const linkOps = [];
|
|
714
|
+
for (let i = 0; i < Math.min(extracted.length - 1, 5); i++) {
|
|
715
|
+
for (let j = i + 1; j < Math.min(extracted.length, 6); j++) {
|
|
716
|
+
// ... inferEntityLinkType, canonicalizeEntityPair, makeEntityLinkId ...
|
|
717
|
+
// ... same filter/update as existing upsertRelation/upsertEntityLink ...
|
|
718
|
+
relationOps.push({
|
|
719
|
+
updateOne: {
|
|
720
|
+
filter: {
|
|
721
|
+
/* existing fields */
|
|
722
|
+
},
|
|
723
|
+
update: {
|
|
724
|
+
/* existing $set/$setOnInsert */
|
|
725
|
+
},
|
|
726
|
+
upsert: true,
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
linkOps.push({
|
|
730
|
+
updateOne: {
|
|
731
|
+
filter: {
|
|
732
|
+
/* existing 6-field filter */
|
|
733
|
+
},
|
|
734
|
+
update: {
|
|
735
|
+
/* existing fields */
|
|
736
|
+
},
|
|
737
|
+
upsert: true,
|
|
738
|
+
},
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (relationOps.length > 0) {
|
|
743
|
+
await relationsCollection(db, prefix).bulkWrite(relationOps, { ordered: false });
|
|
744
|
+
}
|
|
745
|
+
if (linkOps.length > 0) {
|
|
746
|
+
await entityLinksCollection(db, prefix).bulkWrite(linkOps, { ordered: false });
|
|
747
|
+
}
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Error handling for partial failures:** `bulkWrite` with `ordered: false` may succeed partially. Wrap in try/catch and log `BulkWriteError.writeErrors` with `log.warn`.
|
|
751
|
+
|
|
752
|
+
**Step 3: Run tests**
|
|
753
|
+
|
|
754
|
+
Run: `pnpm test -- src/memory/mongodb-graph.test.ts`
|
|
755
|
+
Expected: PASS
|
|
756
|
+
|
|
757
|
+
### Task 3.2: Cache TTL from Path (H4)
|
|
758
|
+
|
|
759
|
+
**Files:**
|
|
760
|
+
|
|
761
|
+
- Modify: `src/memory/mongodb-manager.ts:816-831`
|
|
762
|
+
- Test: `src/memory/mongodb-manager.test.ts`
|
|
763
|
+
|
|
764
|
+
**Step 1: Write test**
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
test("cache TTL uses kbTtlSec when kb path was executed", () => {
|
|
768
|
+
// When pathsExecuted includes "kb", TTL should use kbTtlSec
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
test("cache TTL uses conversationTtlSec when only conversation paths executed", () => {
|
|
772
|
+
// When pathsExecuted is ["hybrid", "structured"], TTL should use conversationTtlSec
|
|
773
|
+
});
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
**Step 2: Implement**
|
|
777
|
+
|
|
778
|
+
Replace the static TTL derivation at line 817-818:
|
|
779
|
+
|
|
780
|
+
```typescript
|
|
781
|
+
// Derive TTL from actual paths executed (not static config)
|
|
782
|
+
const hasKbPath = v2.metadata.pathsExecuted.includes("kb");
|
|
783
|
+
const ttlSec = hasKbPath ? mongoCfg.cache.kbTtlSec : mongoCfg.cache.conversationTtlSec;
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
**Step 3: Run tests**
|
|
787
|
+
|
|
788
|
+
Run: `pnpm test -- src/memory/mongodb-manager.test.ts`
|
|
789
|
+
Expected: PASS
|
|
790
|
+
|
|
791
|
+
### Task 3.3: Filter Empty Snippets Before Reranking (H5)
|
|
792
|
+
|
|
793
|
+
**Files:**
|
|
794
|
+
|
|
795
|
+
- Modify: `src/memory/mongodb-reranker.ts:78`
|
|
796
|
+
- Test: `src/memory/mongodb-reranker.test.ts`
|
|
797
|
+
|
|
798
|
+
**Step 1: Write test**
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
test("crossEncoderRerank filters out results with empty/blank snippets", async () => {
|
|
802
|
+
const results = [
|
|
803
|
+
{ snippet: "Alice works on ProjectX", score: 0.9 /* ... */ },
|
|
804
|
+
{ snippet: "", score: 0.8 /* ... */ }, // empty — should be filtered
|
|
805
|
+
{ snippet: " ", score: 0.7 /* ... */ }, // blank — should be filtered
|
|
806
|
+
{ snippet: "Bob manages TeamY", score: 0.6 /* ... */ },
|
|
807
|
+
];
|
|
808
|
+
// Mock fetch to return reranked indices for non-empty docs only
|
|
809
|
+
// Verify only 2 documents sent to API, empty results appended at end
|
|
810
|
+
});
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
**Step 2: Implement**
|
|
814
|
+
|
|
815
|
+
Before building the `documents` array for the API call, filter empty snippets:
|
|
816
|
+
|
|
817
|
+
```typescript
|
|
818
|
+
// Filter out candidates with empty/blank snippets (graph relations can produce near-empty text)
|
|
819
|
+
const validCandidates = candidates.filter((r) => r.snippet.trim().length > 0);
|
|
820
|
+
const emptySnippetCandidates = candidates.filter((r) => r.snippet.trim().length === 0);
|
|
821
|
+
|
|
822
|
+
if (validCandidates.length <= 1) {
|
|
823
|
+
return { results, reranked: false, latencyMs: 0 };
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const documents = validCandidates.map((r) => r.snippet);
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
After reranking, append emptySnippetCandidates before overflow and below:
|
|
830
|
+
|
|
831
|
+
```typescript
|
|
832
|
+
return {
|
|
833
|
+
results: [...reranked, ...emptySnippetCandidates, ...overflow, ...below],
|
|
834
|
+
reranked: true,
|
|
835
|
+
latencyMs,
|
|
836
|
+
};
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**Step 3: Run tests**
|
|
840
|
+
|
|
841
|
+
Run: `pnpm test -- src/memory/mongodb-reranker.test.ts`
|
|
842
|
+
Expected: PASS
|
|
843
|
+
|
|
844
|
+
### Task 3.4: Entity-Extraction Telemetry (H6)
|
|
845
|
+
|
|
846
|
+
**Files:**
|
|
847
|
+
|
|
848
|
+
- Modify: `src/memory/mongodb-graph.ts` (extractAndUpsertEntities)
|
|
849
|
+
- Test: `src/memory/mongodb-graph.test.ts`
|
|
850
|
+
|
|
851
|
+
**Step 1: Write test**
|
|
852
|
+
|
|
853
|
+
```typescript
|
|
854
|
+
test("extractAndUpsertEntities emits entity-extraction telemetry", async () => {
|
|
855
|
+
const telemetrySpy = vi.spyOn(telemetryModule, "emitTelemetry");
|
|
856
|
+
await extractAndUpsertEntities({
|
|
857
|
+
db: mockDb,
|
|
858
|
+
prefix: "test_",
|
|
859
|
+
agentId: "a1",
|
|
860
|
+
eventContent: "@alice",
|
|
861
|
+
scope: "agent",
|
|
862
|
+
});
|
|
863
|
+
expect(telemetrySpy).toHaveBeenCalledWith(
|
|
864
|
+
mockDb,
|
|
865
|
+
"test_",
|
|
866
|
+
expect.objectContaining({
|
|
867
|
+
meta: { agentId: "a1", operation: "entity-extraction" },
|
|
868
|
+
ok: true,
|
|
869
|
+
extractionMethod: "regex",
|
|
870
|
+
entitiesExtracted: 1,
|
|
871
|
+
}),
|
|
872
|
+
);
|
|
873
|
+
});
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
**Step 2: Implement**
|
|
877
|
+
|
|
878
|
+
Add `emitTelemetry` calls to `extractAndUpsertEntities` in both success and failure paths:
|
|
879
|
+
|
|
880
|
+
```typescript
|
|
881
|
+
// After successful extraction + upsert:
|
|
882
|
+
emitTelemetry(db, prefix, {
|
|
883
|
+
meta: { agentId, operation: "entity-extraction" },
|
|
884
|
+
durationMs: Date.now() - startMs,
|
|
885
|
+
ok: true,
|
|
886
|
+
extractionMethod: extractorResults[0]?.extractionMethod ?? "regex", // use result's method, not instanceof
|
|
887
|
+
entitiesExtracted: extracted.length,
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// In catch block:
|
|
891
|
+
emitTelemetry(db, prefix, {
|
|
892
|
+
meta: { agentId, operation: "entity-extraction" },
|
|
893
|
+
durationMs: Date.now() - startMs,
|
|
894
|
+
ok: false,
|
|
895
|
+
extractionMethod: extractor instanceof RegexEntityExtractor ? "regex" : "llm",
|
|
896
|
+
entitiesExtracted: 0,
|
|
897
|
+
});
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
**Step 3: Run tests**
|
|
901
|
+
|
|
902
|
+
Run: `pnpm test -- src/memory/mongodb-graph.test.ts`
|
|
903
|
+
Expected: PASS
|
|
904
|
+
|
|
905
|
+
**Step 4: Commit Phase 3**
|
|
906
|
+
|
|
907
|
+
```bash
|
|
908
|
+
scripts/committer "Fix(memory): HIGH audit fixes — bulkWrite entity upserts, path-based cache TTL, empty snippet filter, entity-extraction telemetry" \
|
|
909
|
+
src/memory/mongodb-graph.ts \
|
|
910
|
+
src/memory/mongodb-manager.ts \
|
|
911
|
+
src/memory/mongodb-reranker.ts \
|
|
912
|
+
src/memory/mongodb-graph.test.ts \
|
|
913
|
+
src/memory/mongodb-manager.test.ts \
|
|
914
|
+
src/memory/mongodb-reranker.test.ts
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
919
|
+
## Phase 4: MEDIUM Quick-Wins (M1, M2, M4)
|
|
920
|
+
|
|
921
|
+
> **Exit Criteria:** Reranker emits telemetry on failure. Raw-window events capped at 50. getLatencyStats uses $percentile.
|
|
922
|
+
|
|
923
|
+
### Task 4.1: Reranker Failure Telemetry (M1)
|
|
924
|
+
|
|
925
|
+
**Files:**
|
|
926
|
+
|
|
927
|
+
- Modify: `src/memory/mongodb-reranker.ts:141-143`
|
|
928
|
+
- Test: `src/memory/mongodb-reranker.test.ts`
|
|
929
|
+
|
|
930
|
+
**Step 1: Write test**
|
|
931
|
+
|
|
932
|
+
```typescript
|
|
933
|
+
test("crossEncoderRerank emits telemetry on failure", async () => {
|
|
934
|
+
globalThis.fetch = vi.fn(() => Promise.reject(new Error("network error")));
|
|
935
|
+
const telemetrySpy = vi.spyOn(telemetryModule, "emitTelemetry");
|
|
936
|
+
const result = await crossEncoderRerank({
|
|
937
|
+
/* valid params with enabled config */
|
|
938
|
+
});
|
|
939
|
+
expect(result.reranked).toBe(false);
|
|
940
|
+
expect(telemetrySpy).toHaveBeenCalledWith(
|
|
941
|
+
expect.anything(),
|
|
942
|
+
expect.anything(),
|
|
943
|
+
expect.objectContaining({ ok: false }),
|
|
944
|
+
);
|
|
945
|
+
});
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
**Step 2: Implement**
|
|
949
|
+
|
|
950
|
+
Add `emitTelemetry` to the catch block in `crossEncoderRerank`:
|
|
951
|
+
|
|
952
|
+
```typescript
|
|
953
|
+
} catch (err) {
|
|
954
|
+
log.warn("rerank failed, falling back to input order", { error: err });
|
|
955
|
+
emitTelemetry(db, prefix, {
|
|
956
|
+
meta: { agentId, operation: "rerank" },
|
|
957
|
+
durationMs: Date.now() - rerankStart,
|
|
958
|
+
ok: false,
|
|
959
|
+
rerankModel: config.model,
|
|
960
|
+
rerankLatencyMs: Date.now() - rerankStart,
|
|
961
|
+
});
|
|
962
|
+
return { results, reranked: false, latencyMs: Date.now() - rerankStart };
|
|
963
|
+
}
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
**Step 3: Run tests**
|
|
967
|
+
|
|
968
|
+
Run: `pnpm test -- src/memory/mongodb-reranker.test.ts`
|
|
969
|
+
Expected: PASS
|
|
970
|
+
|
|
971
|
+
### Task 4.2: Raw-Window Event Cap (M2)
|
|
972
|
+
|
|
973
|
+
**Files:**
|
|
974
|
+
|
|
975
|
+
- Modify: `src/memory/mongodb-manager.ts` (searchV2, raw-window case)
|
|
976
|
+
- Test: `src/memory/mongodb-manager.test.ts`
|
|
977
|
+
|
|
978
|
+
**Step 1: Write test**
|
|
979
|
+
|
|
980
|
+
```typescript
|
|
981
|
+
test("searchV2 raw-window path caps events at 50", async () => {
|
|
982
|
+
// Mock getEventsByTimeRange to return 100 events
|
|
983
|
+
// Verify only 50 are used in pathResults
|
|
984
|
+
});
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
**Step 2: Implement**
|
|
988
|
+
|
|
989
|
+
In the `raw-window` case of searchV2 (around line 2744), pass an explicit limit:
|
|
990
|
+
|
|
991
|
+
```typescript
|
|
992
|
+
case "raw-window": {
|
|
993
|
+
const rawWindowLimit = 50;
|
|
994
|
+
const events = await getEventsByTimeRange({
|
|
995
|
+
db,
|
|
996
|
+
prefix,
|
|
997
|
+
agentId,
|
|
998
|
+
start: timeRange?.start ?? new Date(Date.now() - 24 * 60 * 60 * 1000),
|
|
999
|
+
end: timeRange?.end ?? new Date(),
|
|
1000
|
+
scope,
|
|
1001
|
+
scopeRef: agentScopeRef,
|
|
1002
|
+
limit: rawWindowLimit,
|
|
1003
|
+
});
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
Note: `getEventsByTimeRange` already accepts a `limit` parameter (default 1000). We just pass 50.
|
|
1007
|
+
|
|
1008
|
+
**Step 3: Run tests**
|
|
1009
|
+
|
|
1010
|
+
Run: `pnpm test -- src/memory/mongodb-manager.test.ts`
|
|
1011
|
+
Expected: PASS
|
|
1012
|
+
|
|
1013
|
+
### Task 4.3: Server-Side $percentile for Latency Stats (M4)
|
|
1014
|
+
|
|
1015
|
+
**Files:**
|
|
1016
|
+
|
|
1017
|
+
- Modify: `src/memory/mongodb-telemetry.ts:89-112` (getLatencyStats)
|
|
1018
|
+
- Test: `src/memory/mongodb-telemetry.test.ts`
|
|
1019
|
+
|
|
1020
|
+
**Step 1: Write test**
|
|
1021
|
+
|
|
1022
|
+
```typescript
|
|
1023
|
+
test("getLatencyStats uses $percentile aggregation", async () => {
|
|
1024
|
+
// Insert telemetry documents
|
|
1025
|
+
// Verify the aggregation pipeline uses $percentile instead of $push
|
|
1026
|
+
const spy = vi.spyOn(collection, "aggregate");
|
|
1027
|
+
await getLatencyStats({ db, prefix, agentId: "a1" });
|
|
1028
|
+
const pipeline = spy.mock.calls[0][0];
|
|
1029
|
+
// Verify no $push in $group, and $percentile is used
|
|
1030
|
+
const groupStage = pipeline.find((s) => s.$group);
|
|
1031
|
+
expect(groupStage.$group).not.toHaveProperty("durations");
|
|
1032
|
+
expect(groupStage.$group.p50).toBeDefined();
|
|
1033
|
+
});
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
**Step 2: Implement**
|
|
1037
|
+
|
|
1038
|
+
Replace the current `$push` + client-side percentile calculation with server-side `$percentile`:
|
|
1039
|
+
|
|
1040
|
+
```typescript
|
|
1041
|
+
const pipeline = [
|
|
1042
|
+
{ $match: matchStage },
|
|
1043
|
+
{
|
|
1044
|
+
$group: {
|
|
1045
|
+
_id: null,
|
|
1046
|
+
count: { $sum: 1 },
|
|
1047
|
+
p50: {
|
|
1048
|
+
$percentile: {
|
|
1049
|
+
input: "$durationMs",
|
|
1050
|
+
p: [0.5],
|
|
1051
|
+
method: "approximate",
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
p95: {
|
|
1055
|
+
$percentile: {
|
|
1056
|
+
input: "$durationMs",
|
|
1057
|
+
p: [0.95],
|
|
1058
|
+
method: "approximate",
|
|
1059
|
+
},
|
|
1060
|
+
},
|
|
1061
|
+
p99: {
|
|
1062
|
+
$percentile: {
|
|
1063
|
+
input: "$durationMs",
|
|
1064
|
+
p: [0.99],
|
|
1065
|
+
method: "approximate",
|
|
1066
|
+
},
|
|
1067
|
+
},
|
|
1068
|
+
},
|
|
1069
|
+
},
|
|
1070
|
+
];
|
|
1071
|
+
|
|
1072
|
+
const results = await telemetryCollection(db, prefix).aggregate(pipeline).toArray();
|
|
1073
|
+
if (results.length === 0 || results[0].count === 0) {
|
|
1074
|
+
return { p50: 0, p95: 0, p99: 0, count: 0 };
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
return {
|
|
1078
|
+
p50: results[0].p50?.[0] ?? 0,
|
|
1079
|
+
p95: results[0].p95?.[0] ?? 0,
|
|
1080
|
+
p99: results[0].p99?.[0] ?? 0,
|
|
1081
|
+
count: results[0].count,
|
|
1082
|
+
};
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
Note: `$percentile` returns an array (one value per percentile requested). Since we request one percentile per field, we take index [0].
|
|
1086
|
+
|
|
1087
|
+
**Step 3: Run tests**
|
|
1088
|
+
|
|
1089
|
+
Run: `pnpm test -- src/memory/mongodb-telemetry.test.ts`
|
|
1090
|
+
Expected: PASS
|
|
1091
|
+
|
|
1092
|
+
**Step 4: Commit Phase 4**
|
|
1093
|
+
|
|
1094
|
+
```bash
|
|
1095
|
+
scripts/committer "Fix(memory): MEDIUM audit fixes — reranker failure telemetry, raw-window event cap, $percentile latency stats" \
|
|
1096
|
+
src/memory/mongodb-reranker.ts \
|
|
1097
|
+
src/memory/mongodb-manager.ts \
|
|
1098
|
+
src/memory/mongodb-telemetry.ts \
|
|
1099
|
+
src/memory/mongodb-reranker.test.ts \
|
|
1100
|
+
src/memory/mongodb-manager.test.ts \
|
|
1101
|
+
src/memory/mongodb-telemetry.test.ts
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
---
|
|
1105
|
+
|
|
1106
|
+
## Phase 5: Final Validation
|
|
1107
|
+
|
|
1108
|
+
> **Exit Criteria:** All memory tests pass. Build succeeds. No regressions.
|
|
1109
|
+
|
|
1110
|
+
### Task 5.1: Full Test Suite
|
|
1111
|
+
|
|
1112
|
+
**Step 1: Run full memory test suite**
|
|
1113
|
+
|
|
1114
|
+
Run: `pnpm test -- src/memory`
|
|
1115
|
+
Expected: All tests pass (baseline + new tests)
|
|
1116
|
+
|
|
1117
|
+
**Step 2: Run build**
|
|
1118
|
+
|
|
1119
|
+
Run: `pnpm build`
|
|
1120
|
+
Expected: Exit 0
|
|
1121
|
+
|
|
1122
|
+
**Step 3: Run lint/format**
|
|
1123
|
+
|
|
1124
|
+
Run: `pnpm check`
|
|
1125
|
+
Expected: Clean (or baseline-only issues)
|
|
1126
|
+
|
|
1127
|
+
**Step 4: Run e2e tests (if MONGODB_TEST_URI available)**
|
|
1128
|
+
|
|
1129
|
+
Run: `MONGODB_TEST_URI=... pnpm test -- --config vitest.e2e.config.ts src/memory/mongodb-e2e.e2e.test.ts`
|
|
1130
|
+
Expected: All scenarios pass
|
|
1131
|
+
|
|
1132
|
+
**Step 5: Final commit if any cleanup needed**
|
|
1133
|
+
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
## Risks And Mitigations
|
|
1137
|
+
|
|
1138
|
+
| Risk | P | I | Score | Mitigation |
|
|
1139
|
+
| ------------------------------------------------------- | --- | --- | ----- | -------------------------------------------------------------------------------------- |
|
|
1140
|
+
| RRF normalization changes result ordering | 3 | 3 | 9 | Existing heuristic reranker + cross-encoder reranker run AFTER RRF, preserving quality |
|
|
1141
|
+
| `$percentile` mock complexity | 1 | 2 | 2 | atlas-local:preview always has latest MongoDB with $percentile; mock in unit tests |
|
|
1142
|
+
| bulkWrite partial failure | 2 | 3 | 6 | `ordered: false` continues on error; log failures from BulkWriteError |
|
|
1143
|
+
| Removing synonym expansions reduces recall | 2 | 2 | 4 | Only removing cross-domain (api->route); keeping domain-specific |
|
|
1144
|
+
| Profile $lookup split changes entity count due to dedup | 2 | 2 | 4 | Test for functional equivalence; relations with same entity on both sides are rare |
|
|
1145
|
+
|
|
1146
|
+
## Acceptance Checks
|
|
1147
|
+
|
|
1148
|
+
- `pnpm test -- src/memory` — all tests pass
|
|
1149
|
+
- `pnpm build` — exit 0
|
|
1150
|
+
- `pnpm check` — clean (or baseline-only)
|
|
1151
|
+
- Each CRITICAL fix has at least 2 unit tests
|
|
1152
|
+
- Each HIGH fix has at least 1 unit test
|
|
1153
|
+
- Score normalization produces scores in [0, 1] range
|
|
1154
|
+
- Reranker fetch aborts within 10 seconds on timeout
|
|
1155
|
+
- Entity upserts use bulkWrite (verify via spy or mock)
|
|
1156
|
+
- `entity-extraction` telemetry is emitted
|
|
1157
|
+
|
|
1158
|
+
## Summary
|
|
1159
|
+
|
|
1160
|
+
- Plan saved: `docs/plans/2026-03-23-supermemory-audit-fixes-plan.md`
|
|
1161
|
+
- Phases: 5
|
|
1162
|
+
- Risks: 5 identified
|
|
1163
|
+
- Key decisions: Manual RRF for score normalization, bulkWrite for entity batching, $percentile for server-side stats, throw on unimplemented query rewrite methods
|
|
1164
|
+
|
|
1165
|
+
## Recommended Skills for BUILD (SKILL_HINTS for Router)
|
|
1166
|
+
|
|
1167
|
+
- `cc10x:architecture-patterns` (multi-file schema/integration work)
|
|
1168
|
+
|
|
1169
|
+
## Confidence Score: 88/100
|
|
1170
|
+
|
|
1171
|
+
- Context References included with file:line (+25)
|
|
1172
|
+
- All edge cases documented (+20)
|
|
1173
|
+
- Test commands specific (+20)
|
|
1174
|
+
- Risk mitigations defined (+20)
|
|
1175
|
+
- File paths exact (+15)
|
|
1176
|
+
- Minor uncertainty: mock complexity for RRF normalization tests (-6), profile test setup for split $lookup (-6)
|
|
1177
|
+
|
|
1178
|
+
**Key Assumptions:**
|
|
1179
|
+
|
|
1180
|
+
- atlas-local:preview always ships latest MongoDB — all features ($percentile, $scoreFusion, etc.) are available
|
|
1181
|
+
- `AbortSignal.timeout()` available in Node 22+ runtime (confirmed: Node 18+)
|
|
1182
|
+
- Existing `rrfScore()` function from `mongodb-hybrid.ts` is correct and reusable
|
|
1183
|
+
- bulkWrite `ordered: false` is safe because entity/relation upserts are independent
|
|
1184
|
+
|
|
1185
|
+
## Findings
|
|
1186
|
+
|
|
1187
|
+
- `mongodb-hybrid.ts` already has RRF scoring, normalization utilities, and OR-join FTS — well-positioned for searchV2 integration
|
|
1188
|
+
- `getEventsByTimeRange` already has a `limit` parameter (default 1000) — M2 fix is trivial
|
|
1189
|
+
- `LLMEntityExtractor` class is well-structured with timeout + fallback — the dead code is only the config-to-instance bridge in `backend-config.ts`
|
|
1190
|
+
- Profile synthesis `$lookup` with `$or` is the only non-indexed aggregation in the supermemory subsystem
|
|
1191
|
+
|
|
1192
|
+
## Task Status
|
|
1193
|
+
|
|
1194
|
+
- Follow-up tasks created: None
|
|
1195
|
+
- **CRITICAL:** Now execute the `TaskUpdate` tool to mark task as completed.
|
|
1196
|
+
|
|
1197
|
+
## Router Contract (MACHINE-READABLE)
|
|
1198
|
+
|
|
1199
|
+
```yaml
|
|
1200
|
+
STATUS: PLAN_CREATED
|
|
1201
|
+
PLAN_MODE: execution_plan
|
|
1202
|
+
VERIFICATION_RIGOR: standard
|
|
1203
|
+
CONFIDENCE: 88
|
|
1204
|
+
PLAN_FILE: "docs/plans/2026-03-23-supermemory-audit-fixes-plan.md"
|
|
1205
|
+
PHASES: 5
|
|
1206
|
+
RISKS_IDENTIFIED: 5
|
|
1207
|
+
SCENARIOS:
|
|
1208
|
+
- name: "Reranker fetch timeout"
|
|
1209
|
+
given: "Voyage API is unresponsive"
|
|
1210
|
+
when: "crossEncoderRerank is called"
|
|
1211
|
+
then: "Returns fallback results within 10s, emits ok:false telemetry"
|
|
1212
|
+
- name: "RRF score normalization"
|
|
1213
|
+
given: "searchV2 returns results from vector (0-1), graph (synthetic), and episode (synthetic) paths"
|
|
1214
|
+
when: "Results are merged and deduplicated"
|
|
1215
|
+
then: "All final scores are RRF-normalized in [0,1] range, sorted by fused RRF score"
|
|
1216
|
+
- name: "bulkWrite entity upserts"
|
|
1217
|
+
given: "extractAndUpsertEntities receives content with 5 entities"
|
|
1218
|
+
when: "Entities and relations are persisted"
|
|
1219
|
+
then: "One bulkWrite call for entities, one for relations, one for links (3 round-trips, not 25)"
|
|
1220
|
+
- name: "Empty snippet filtering"
|
|
1221
|
+
given: "Reranker receives results with empty graph snippets"
|
|
1222
|
+
when: "Candidates are prepared for API call"
|
|
1223
|
+
then: "Empty snippets are excluded from API call and appended after reranked results"
|
|
1224
|
+
- name: "Query rewriter validation"
|
|
1225
|
+
given: "Config sets queryRewriting.method to 'llm'"
|
|
1226
|
+
when: "rewriteQuery is called"
|
|
1227
|
+
then: "Throws Error with clear message about unimplemented method"
|
|
1228
|
+
- name: "Server-side percentile stats"
|
|
1229
|
+
given: "Telemetry collection has 100+ latency documents"
|
|
1230
|
+
when: "getLatencyStats is called"
|
|
1231
|
+
then: "Pipeline uses $percentile aggregation, no client-side array processing"
|
|
1232
|
+
- name: "Cache TTL from paths"
|
|
1233
|
+
given: "searchV2 executed kb path"
|
|
1234
|
+
when: "Cache write fires"
|
|
1235
|
+
then: "TTL uses kbTtlSec, not static config"
|
|
1236
|
+
- name: "Profile $lookup indexed"
|
|
1237
|
+
given: "Entity has relations via both fromEntityId and toEntityId"
|
|
1238
|
+
when: "synthesizeProfile is called"
|
|
1239
|
+
then: "Two separate indexed $eq lookups are used instead of $or in $expr"
|
|
1240
|
+
ASSUMPTIONS:
|
|
1241
|
+
[
|
|
1242
|
+
"atlas-local 8.2 supports $percentile",
|
|
1243
|
+
"AbortSignal.timeout available in Node 22+",
|
|
1244
|
+
"rrfScore from mongodb-hybrid.ts is correct",
|
|
1245
|
+
"bulkWrite ordered:false safe for independent upserts",
|
|
1246
|
+
]
|
|
1247
|
+
DECISIONS:
|
|
1248
|
+
[
|
|
1249
|
+
"Manual RRF for cross-path score normalization",
|
|
1250
|
+
"bulkWrite for entity batching",
|
|
1251
|
+
"$percentile for server-side stats",
|
|
1252
|
+
"Throw on unimplemented query rewrite methods",
|
|
1253
|
+
"Remove cross-domain synonym expansions",
|
|
1254
|
+
]
|
|
1255
|
+
OPEN_DECISIONS: []
|
|
1256
|
+
DIFFERENCES_FROM_AGREEMENT: []
|
|
1257
|
+
RECOMMENDED_DEFAULTS:
|
|
1258
|
+
["RRF k=60", "Rerank timeout 10s", "Raw-window limit 50", "Synonym max ratio 3x"]
|
|
1259
|
+
ALTERNATIVES: ["Min-max normalization instead of RRF", "Transactions instead of bulkWrite"]
|
|
1260
|
+
DRAWBACKS:
|
|
1261
|
+
[
|
|
1262
|
+
"RRF discards score magnitude information",
|
|
1263
|
+
"$percentile is approximate",
|
|
1264
|
+
"Removing synonym expansions may reduce recall",
|
|
1265
|
+
]
|
|
1266
|
+
PROVABLE_PROPERTIES: []
|
|
1267
|
+
BLOCKING: false
|
|
1268
|
+
NEXT_ACTION: "build"
|
|
1269
|
+
REMEDIATION_NEEDED: false
|
|
1270
|
+
REQUIRES_REMEDIATION: false
|
|
1271
|
+
REMEDIATION_REASON: null
|
|
1272
|
+
GATE_PASSED: true
|
|
1273
|
+
USER_INPUT_NEEDED: []
|
|
1274
|
+
MEMORY_NOTES:
|
|
1275
|
+
learnings:
|
|
1276
|
+
[
|
|
1277
|
+
"15 audit fixes planned across 9 source files",
|
|
1278
|
+
"mongodb-hybrid.ts RRF utilities reusable in searchV2",
|
|
1279
|
+
"getEventsByTimeRange already has limit param",
|
|
1280
|
+
"Profile $lookup with $or is only non-indexed aggregation",
|
|
1281
|
+
]
|
|
1282
|
+
patterns:
|
|
1283
|
+
[
|
|
1284
|
+
"Manual RRF for cross-path score normalization",
|
|
1285
|
+
"bulkWrite ordered:false for independent entity upserts",
|
|
1286
|
+
"$percentile GA since MongoDB 7.0",
|
|
1287
|
+
"AbortSignal.timeout for external API calls",
|
|
1288
|
+
]
|
|
1289
|
+
verification:
|
|
1290
|
+
["Plan: docs/plans/2026-03-23-supermemory-audit-fixes-plan.md with 88/100 confidence"]
|
|
1291
|
+
```
|