@romiluz/clawmongo 2026.3.27 → 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.
Files changed (507) hide show
  1. package/README.md +72 -49
  2. package/dist/{accounts-boH28BFM.js → accounts-lL2y51Ag.js} +46 -46
  3. package/dist/{acp-cli-DLaTb29R.js → acp-cli-BZvVHRY8.js} +46 -46
  4. package/dist/{action-runtime-Bk-7pvN2.js → action-runtime-DMYRUL4q.js} +10 -10
  5. package/dist/{actions.runtime-Y529miLb.js → actions.runtime-Bd-NMAq6.js} +46 -46
  6. package/dist/{actions.runtime-DVQ4pmcp.js → actions.runtime-gPSeXscW.js} +49 -49
  7. package/dist/{agent-scope-BROpmzKv.js → agent-scope-DXZH506l.js} +1 -1
  8. package/dist/{agents-DZqtbDMD.js → agents-Bt25bmDR.js} +13 -13
  9. package/dist/{agents-BbO-i90j.js → agents-CyJmttnS.js} +114 -114
  10. package/dist/{agents.config-CDS6iAat.js → agents.config-BWm70Hr6.js} +2 -2
  11. package/dist/{agents.config-iY500LY-.js → agents.config-UsCw0kOR.js} +4 -4
  12. package/dist/{audit-Cmj7BNcZ.js → audit-Dg8ZiJrJ.js} +9 -9
  13. package/dist/{audit-DmXeao7s.js → audit-DhXhWoiv.js} +1 -1
  14. package/dist/{audit-channel.collect.runtime-DhP09fjv.js → audit-channel.collect.runtime-CvPUHy1X.js} +2 -2
  15. package/dist/{audit-channel.runtime-C-watgwg.js → audit-channel.runtime-B6ZnOPFc.js} +46 -46
  16. package/dist/{audit-extra.async-B-7dzgcz.js → audit-extra.async-826UZZhJ.js} +3 -3
  17. package/dist/{audit-membership-runtime-CbLi3-5b.js → audit-membership-runtime-DLQrV7Rr.js} +46 -46
  18. package/dist/{audit.deep.runtime-D5VgrTOT.js → audit.deep.runtime-DQDtV7Bc.js} +4 -4
  19. package/dist/{audit.nondeep.runtime-B7M0-7FZ.js → audit.nondeep.runtime-H6B-2xal.js} +4 -4
  20. package/dist/{audit.runtime-BUknqGaP.js → audit.runtime-D2ZRC2A_.js} +47 -47
  21. package/dist/{auth-choice-DfJRosb4.js → auth-choice-CEowrO66.js} +57 -57
  22. package/dist/{auth-choice-CpB99A-L.js → auth-choice-DiufM1b8.js} +55 -55
  23. package/dist/{auth-choice-Bnnngmkx.js → auth-choice-YrGxwB9A.js} +5 -5
  24. package/dist/{auth-choice-options-DvqJHFOp.js → auth-choice-options-n3_uFdT5.js} +2 -2
  25. package/dist/{auth-choice-prompt-DtTjWfPT.js → auth-choice-prompt-DYFzoWa6.js} +50 -50
  26. package/dist/{auth-choice-prompt-Cxz8du6E.js → auth-choice-prompt-sLET2Bkw.js} +1 -1
  27. package/dist/{auth-choice.apply-helpers-Bm5p2ZX7.js → auth-choice.apply-helpers-GU6nZntg.js} +1 -1
  28. package/dist/{auth-choice.plugin-providers.runtime-Dsu6-vb8.js → auth-choice.plugin-providers.runtime-BNqOEEtb.js} +47 -47
  29. package/dist/{auth-profiles-2-OV37OF.js → auth-profiles-BWBQJ6X_.js} +67 -76
  30. package/dist/{auth-profiles.runtime-HcQMBs3K.js → auth-profiles.runtime-DfKRAmQR.js} +46 -46
  31. package/dist/{backend-config-avgzgS5Z.js → backend-config--L236wE2.js} +26 -1
  32. package/dist/{backup-create-B9F0M7-J.js → backup-create-Bll6DgoT.js} +2 -2
  33. package/dist/{base-session-key-DyLtSGkj.js → base-session-key-CA4SoGLF.js} +1 -1
  34. package/dist/{bluebubbles-BTR7u4zE.js → bluebubbles-BsX68JOY.js} +6 -6
  35. package/dist/{browser-cli-tmytvFaa.js → browser-cli-B5euA0cQ.js} +8 -8
  36. package/dist/build-info.json +3 -3
  37. package/dist/bundled/boot-md/handler.js +46 -46
  38. package/dist/bundled/bootstrap-extra-files/handler.js +1 -1
  39. package/dist/bundled/session-memory/handler.js +47 -47
  40. package/dist/{call-Cqem-bCB.js → call-C-_XQxw5.js} +1 -1
  41. package/dist/{call-CxVOiYz-.js → call-lPTaDgAg.js} +6 -6
  42. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  43. package/dist/{channel-Br8MF00M.js → channel-5o-oIU2B.js} +1 -1
  44. package/dist/{channel-BvRm4jSj.js → channel-C1zZg_8b.js} +2 -2
  45. package/dist/{channel-CqkxOhz2.js → channel-CEytBPH-.js} +4 -4
  46. package/dist/{channel-D_h7IfYK.js → channel-Cm65A1lo.js} +7 -7
  47. package/dist/{channel-ngZRDeE3.js → channel-D4K0MVgr.js} +5 -5
  48. package/dist/{channel-account-context-DZhZw4oo.js → channel-account-context-CNZZPDSe.js} +1 -1
  49. package/dist/{channel-plugin-resolution-CXm5HIcm.js → channel-plugin-resolution-WWO690RK.js} +3 -3
  50. package/dist/{channel-reply-pipeline-DdDsf-Lc.js → channel-reply-pipeline-B17-tBLU.js} +1 -1
  51. package/dist/{channel-shared-VIRIADYn.js → channel-shared-RH6YsZ0I.js} +1 -1
  52. package/dist/{channel-summary-BTJxLPN8.js → channel-summary-Cy7WDRjQ.js} +7 -7
  53. package/dist/{channel-summary-DdJtHlvH.js → channel-summary-DV4_b3HZ.js} +2 -2
  54. package/dist/{channel-tFDEkWt9.js → channel-yCiI29Ju.js} +6 -6
  55. package/dist/{channel.runtime-DGnRryi2.js → channel.runtime-C3m1vacV.js} +47 -47
  56. package/dist/{channel.runtime-CdPEA_wb.js → channel.runtime-CUSE7Dn0.js} +47 -47
  57. package/dist/{channel.runtime-0n3_Hz_Y.js → channel.runtime-CtWi36oj.js} +49 -49
  58. package/dist/{channel.runtime-CkHcsWQ3.js → channel.runtime-LUpQZiWg.js} +49 -49
  59. package/dist/{channel.runtime-msXRrVzC.js → channel.runtime-QOkM4mJV.js} +51 -51
  60. package/dist/{channel.runtime-khqV1QRG.js → channel.runtime-rYuUs2po.js} +4 -4
  61. package/dist/{channels-DNza27NY.js → channels-4VTbN2Gt.js} +103 -103
  62. package/dist/{channels-CLZoq3SY.js → channels-BUMnLXLQ.js} +1 -1
  63. package/dist/{channels-cli-Bhsnjsix.js → channels-cli-BYmLj8zw.js} +55 -55
  64. package/dist/{clawbot-cli-9YJNF9pF.js → clawbot-cli-CIYY1u-6.js} +47 -47
  65. package/dist/cli/daemon-cli.js +1 -1
  66. package/dist/{cli-FF5823nM.js → cli-DUA0FvhM.js} +46 -46
  67. package/dist/{command-registry-Bow_kWfU.js → command-registry-B1ECZip_.js} +13 -13
  68. package/dist/{command-registry-BEExVzem.js → command-registry-DOAwIs0Y.js} +2 -2
  69. package/dist/{command-secret-gateway-CzHSHmXG.js → command-secret-gateway-Big-n6JY.js} +46 -46
  70. package/dist/{compact.runtime-Bye-pm7Z.js → compact.runtime-BKnPPv9X.js} +46 -46
  71. package/dist/{completion-cli-B4hJ8HjW.js → completion-cli-BeLNvVTI.js} +3 -3
  72. package/dist/{completion-cli-DQrts0Ip.js → completion-cli-CHwHDPuI.js} +2 -2
  73. package/dist/{config-Ca7pLyBD.js → config-BOWZMmDA.js} +1 -1
  74. package/dist/{config-GKOWhVMv.js → config-C68iwvDj.js} +5 -5
  75. package/dist/{config-cli-CxPspN-S.js → config-cli-BnC336Lu.js} +48 -48
  76. package/dist/{config-guard-BK2hWyPi.js → config-guard-Bn6rZnzK.js} +6 -6
  77. package/dist/{config-validation-DO6o_Kt_.js → config-validation-BBuJZ-WH.js} +2 -2
  78. package/dist/{configure-CODqvxU-.js → configure-CHJDsjOD.js} +120 -120
  79. package/dist/{configure-Dg65gBEw.js → configure-Cctw7tyJ.js} +19 -23
  80. package/dist/{connection-auth-zhL6PVn0.js → connection-auth-C2XaPpF5.js} +1 -1
  81. package/dist/{control-ui-shared-_VwcOcc_.js → control-ui-shared-BC-g150y.js} +1 -1
  82. package/dist/{core-CzwQmKcn.js → core-Cb3XxL6S.js} +1 -1
  83. package/dist/{cron-cli-Dp_EQt2v.js → cron-cli-C10feOtH.js} +7 -7
  84. package/dist/{daemon-cli-Dgpv6Y0R.js → daemon-cli-Ds8mu2VZ.js} +4 -4
  85. package/dist/{daemon-install-Dq1Ix-FO.js → daemon-install-B__sP_7j.js} +49 -49
  86. package/dist/{delegate-BVapk4rY.js → delegate-ByCLviVI.js} +1 -1
  87. package/dist/{deliver-runtime-DPzMjhNU.js → deliver-Co7G5ubS.js} +46 -46
  88. package/dist/{deliver-C32Gg-xU.js → deliver-runtime-2svrtAf1.js} +46 -46
  89. package/dist/{devices-cli-3WN_wB1C.js → devices-cli-CH8nWgcU.js} +6 -6
  90. package/dist/{diagnostic-BbXfhLMi.js → diagnostic-DHTG43d_.js} +1 -1
  91. package/dist/{directory-cli-D_5BYdXm.js → directory-cli-B0REFlKo.js} +48 -48
  92. package/dist/{directory.static-CsajbHw1.js → directory.static-wnw_R8dE.js} +1 -1
  93. package/dist/{discord-C-4y9vOT.js → discord-Cws9MsXn.js} +4 -4
  94. package/dist/{discord-B3mmVXuG.js → discord-b8Ff_BKB.js} +46 -46
  95. package/dist/{dns-cli-CdAnUzRi.js → dns-cli-aRTleL5e.js} +5 -5
  96. package/dist/{doctor-completion-Dk8sgMOd.js → doctor-completion-KQWBMnEi.js} +1 -1
  97. package/dist/{doctor-config-preflight-BJ0lGLTO.js → doctor-config-preflight-BDYe5di1.js} +2 -2
  98. package/dist/{doctor-config-preflight-D32oVOWD.js → doctor-config-preflight-Dn5a_Dbr.js} +6 -6
  99. package/dist/{doctor-state-migrations-BklDIib1.js → doctor-state-migrations-BI6HzFyq.js} +47 -47
  100. package/dist/{doctor-state-migrations-Cdk3ep_f.js → doctor-state-migrations-DUPe9zNr.js} +2 -2
  101. package/dist/entry.js +1 -1
  102. package/dist/{exec-approvals-D8OOtgGc.js → exec-approvals-CZz2LqIW.js} +1 -1
  103. package/dist/{exec-approvals-cli-dGISWHE3.js → exec-approvals-cli-KbFpgd-p.js} +9 -9
  104. package/dist/extensionAPI.js +46 -46
  105. package/dist/extensions/amazon-bedrock/index.js +46 -46
  106. package/dist/extensions/anthropic/index.js +46 -46
  107. package/dist/extensions/bluebubbles/index.js +50 -50
  108. package/dist/extensions/bluebubbles/setup-entry.js +48 -48
  109. package/dist/extensions/byteplus/index.js +46 -46
  110. package/dist/extensions/chutes/index.js +48 -48
  111. package/dist/extensions/cloudflare-ai-gateway/index.js +47 -47
  112. package/dist/extensions/device-pair/index.js +46 -46
  113. package/dist/extensions/discord/index.js +48 -48
  114. package/dist/extensions/discord/node_modules/.package-lock.json +3 -3
  115. package/dist/extensions/discord/node_modules/hono/dist/adapter/service-worker/index.js +1 -3
  116. package/dist/extensions/discord/node_modules/hono/dist/cjs/adapter/service-worker/index.js +1 -3
  117. package/dist/extensions/discord/node_modules/hono/dist/cjs/helper/ssg/ssg.js +1 -1
  118. package/dist/extensions/discord/node_modules/hono/dist/cjs/middleware/cors/index.js +5 -2
  119. package/dist/extensions/discord/node_modules/hono/dist/cjs/request.js +1 -1
  120. package/dist/extensions/discord/node_modules/hono/dist/helper/ssg/ssg.js +1 -1
  121. package/dist/extensions/discord/node_modules/hono/dist/middleware/cors/index.js +5 -2
  122. package/dist/extensions/discord/node_modules/hono/dist/request.js +1 -1
  123. package/dist/extensions/discord/node_modules/hono/dist/tsconfig.build.tsbuildinfo +1 -1
  124. package/dist/extensions/discord/node_modules/hono/dist/types/client/index.d.ts +1 -1
  125. package/dist/extensions/discord/node_modules/hono/dist/types/client/types.d.ts +20 -0
  126. package/dist/extensions/discord/node_modules/hono/dist/types/request.d.ts +1 -3
  127. package/dist/extensions/discord/node_modules/hono/package.json +1 -1
  128. package/dist/extensions/discord/setup-entry.js +48 -48
  129. package/dist/extensions/elevenlabs/index.js +46 -46
  130. package/dist/extensions/fal/index.js +46 -46
  131. package/dist/extensions/feishu/index.js +55 -55
  132. package/dist/extensions/feishu/setup-entry.js +51 -51
  133. package/dist/extensions/firecrawl/index.js +46 -46
  134. package/dist/extensions/github-copilot/index.js +47 -47
  135. package/dist/extensions/google/index.js +46 -46
  136. package/dist/extensions/huggingface/index.js +47 -47
  137. package/dist/extensions/imessage/index.js +49 -49
  138. package/dist/extensions/imessage/setup-entry.js +49 -49
  139. package/dist/extensions/irc/index.js +49 -49
  140. package/dist/extensions/irc/setup-entry.js +48 -48
  141. package/dist/extensions/kilocode/index.js +47 -47
  142. package/dist/extensions/kimi-coding/index.js +47 -47
  143. package/dist/extensions/line/index.js +9 -9
  144. package/dist/extensions/line/setup-entry.js +8 -8
  145. package/dist/extensions/llm-task/index.js +46 -46
  146. package/dist/extensions/lobster/index.js +5 -5
  147. package/dist/extensions/mattermost/index.js +49 -49
  148. package/dist/extensions/mattermost/setup-entry.js +48 -48
  149. package/dist/extensions/microsoft/index.js +46 -46
  150. package/dist/extensions/minimax/index.js +48 -48
  151. package/dist/extensions/mistral/index.js +47 -47
  152. package/dist/extensions/modelstudio/index.js +47 -47
  153. package/dist/extensions/moonshot/index.js +46 -46
  154. package/dist/extensions/nextcloud-talk/index.js +50 -50
  155. package/dist/extensions/nextcloud-talk/setup-entry.js +49 -49
  156. package/dist/extensions/ollama/index.js +5 -5
  157. package/dist/extensions/openai/index.js +47 -47
  158. package/dist/extensions/opencode/index.js +47 -47
  159. package/dist/extensions/opencode-go/index.js +47 -47
  160. package/dist/extensions/openrouter/index.js +47 -47
  161. package/dist/extensions/openshell/index.js +46 -46
  162. package/dist/extensions/qianfan/index.js +47 -47
  163. package/dist/extensions/qwen-portal-auth/index.js +47 -47
  164. package/dist/extensions/sglang/index.js +46 -46
  165. package/dist/extensions/signal/index.js +49 -49
  166. package/dist/extensions/signal/setup-entry.js +49 -49
  167. package/dist/extensions/slack/index.js +50 -50
  168. package/dist/extensions/slack/setup-entry.js +50 -50
  169. package/dist/extensions/synology-chat/index.js +9 -9
  170. package/dist/extensions/synology-chat/setup-entry.js +8 -8
  171. package/dist/extensions/synthetic/index.js +47 -47
  172. package/dist/extensions/talk-voice/index.js +46 -46
  173. package/dist/extensions/tavily/index.js +46 -46
  174. package/dist/extensions/telegram/index.js +48 -48
  175. package/dist/extensions/telegram/setup-entry.js +48 -48
  176. package/dist/extensions/together/index.js +47 -47
  177. package/dist/extensions/venice/index.js +47 -47
  178. package/dist/extensions/vercel-ai-gateway/index.js +47 -47
  179. package/dist/extensions/vllm/index.js +46 -46
  180. package/dist/extensions/voice-call/index.js +46 -46
  181. package/dist/extensions/volcengine/index.js +46 -46
  182. package/dist/extensions/xai/index.js +46 -46
  183. package/dist/extensions/xiaomi/index.js +47 -47
  184. package/dist/extensions/zai/index.js +47 -47
  185. package/dist/extensions/zalo/index.js +49 -49
  186. package/dist/extensions/zalo/setup-entry.js +48 -48
  187. package/dist/{feishu-C637DYYe.js → feishu-D2fuiOiy.js} +4 -4
  188. package/dist/{gateway-cli-BAueAYsk.js → gateway-cli-nOgyXtih.js} +72 -106
  189. package/dist/{gateway-install-token-DlcVm1rP.js → gateway-install-token-nvsTK8KN.js} +4 -4
  190. package/dist/{gateway-rpc-siKa8KpM.js → gateway-rpc-DrH142-v.js} +1 -1
  191. package/dist/{gateway-runtime-roiTaOKO.js → gateway-runtime-CQXKGzrv.js} +2 -2
  192. package/dist/{github-copilot-auth-DJljh3gq.js → github-copilot-auth-C4z2AAd8.js} +3 -3
  193. package/dist/{health-DU_pBiid.js → health-DEgLPyA9.js} +7 -7
  194. package/dist/{health-B1OK1kJg.js → health-H5nbiXvA.js} +48 -48
  195. package/dist/{heartbeat-summary-CMwt9qam.js → heartbeat-summary-CNCptWmA.js} +1 -1
  196. package/dist/{hooks-cli-D42hQEUb.js → hooks-cli-jBhsJaOg.js} +46 -46
  197. package/dist/{identity-file-8MUyIAOy.js → identity-file-CYQnH12I.js} +1 -1
  198. package/dist/{imessage-zqZjecTU.js → imessage-DYqgZpLc.js} +6 -6
  199. package/dist/{imessage-CZb_pS8U.js → imessage-Dau6WdE3.js} +46 -46
  200. package/dist/{inbound-reply-dispatch-B73AkQh4.js → inbound-reply-dispatch-BFE3xy1S.js} +2 -2
  201. package/dist/index.js +2 -2
  202. package/dist/{internal-Bg_k56Pk.js → internal-DLE9baj7.js} +0 -24
  203. package/dist/{io-DE9vm7Eo.js → io-Du0b8gMO.js} +2 -2
  204. package/dist/{io-B7rO2wud.js → io-dJgqp8U8.js} +4 -4
  205. package/dist/{irc-BWzsfr2V.js → irc-BRaOVUse.js} +2 -2
  206. package/dist/{kb-cli-BOPGkNfJ.js → kb-cli-Cdif_vwn.js} +12 -12
  207. package/dist/{library-i-2ymInt.js → library-BwjFIWw3.js} +46 -46
  208. package/dist/{lifecycle-core-DwIo1PfK.js → lifecycle-core-DNO4MItg.js} +1 -1
  209. package/dist/line/send.js +6 -6
  210. package/dist/{line-DbTKdVgY.js → line-BCXUGrVz.js} +2 -2
  211. package/dist/{llm-slug-generator-Dm30OM2W.js → llm-slug-generator-B55FZ1aG.js} +3 -3
  212. package/dist/llm-slug-generator.js +47 -47
  213. package/dist/{logging-BM4mQ53W.js → logging-BvOzg0cM.js} +1 -1
  214. package/dist/{logging-0tvlVvFG.js → logging-nWyKsj9d.js} +5 -5
  215. package/dist/{login-qr-DQPSabxI.js → login-qr-C0QA3j4x.js} +46 -46
  216. package/dist/{logs-cli-ZnHk5eku.js → logs-cli-thlXBA9n.js} +7 -7
  217. package/dist/{manager.runtime-D3vjUOZF.js → manager.runtime-SoTq-tT4.js} +46 -46
  218. package/dist/{matrix-migration-snapshot-CRKiHq6Y.js → matrix-migration-snapshot-_6Rg-iLO.js} +2 -2
  219. package/dist/{mattermost-Bqn7Fd5U.js → mattermost-2nv5O_jQ.js} +2 -2
  220. package/dist/{mcp-cli-7aN2vJv-.js → mcp-cli-1vpy_yti.js} +5 -5
  221. package/dist/{mcp-config-NVrqojpu.js → mcp-config-Bmi2GUum.js} +1 -1
  222. package/dist/{media-understanding.runtime-DesF8Xhs.js → media-understanding.runtime-Wh-_SFK_.js} +46 -46
  223. package/dist/{memory-cli-CWqIJQS5.js → memory-cli-COJRHkaJ.js} +46 -46
  224. package/dist/{memory-search-DyxoUpq2.js → memory-search-CGmdrdM1.js} +1 -1
  225. package/dist/{memory-search-CgoWYj0V.js → memory-search-Cy36nO15.js} +3 -3
  226. package/dist/{model-picker-DX9P5pDr.js → model-picker-CYWvoS3z.js} +48 -48
  227. package/dist/{model-picker-Ds7-VqDS.js → model-picker-_32ihKqK.js} +4 -4
  228. package/dist/{model-picker.runtime-DqDt4s3S.js → model-picker.runtime-DBT5uEFi.js} +49 -49
  229. package/dist/{model-selection-DXFVauys.js → model-selection-014eeYCV.js} +1 -1
  230. package/dist/{model-suppression.runtime-8mU0VJs6.js → model-suppression.runtime-GTI9Rm85.js} +46 -46
  231. package/dist/{models-GXQSWyBX.js → models-Be9EWpVm.js} +54 -54
  232. package/dist/{models-CVG-VMBa.js → models-CX35daXC.js} +14 -14
  233. package/dist/{models-cli-Cvy8rGqU.js → models-cli-BYjac3oq.js} +54 -54
  234. package/dist/{models-config-BdanqM9X.js → models-config-Agv-ThDH.js} +46 -46
  235. package/dist/{models-config.providers.discovery-BHZ3WglC.js → models-config.providers.discovery-BJwjDHsg.js} +1 -1
  236. package/dist/{mongodb-analytics-BszyEhsq.js → mongodb-analytics-HJKYeseb.js} +2 -2
  237. package/dist/{mongodb-analytics-CcSYo_ae.js → mongodb-analytics-mnKJih5x.js} +1 -1
  238. package/dist/{mongodb-auto-setup-QcwgZSN9.js → mongodb-auto-setup-CCElSwNy.js} +2 -2
  239. package/dist/{mongodb-kb-C-VmGOq7.js → mongodb-kb-1tSOXXb9.js} +3 -3
  240. package/dist/{mongodb-kb-BotgVda9.js → mongodb-kb-CdSvNe3w.js} +2 -2
  241. package/dist/{mongodb-kb-search-CoIAFX8n.js → mongodb-kb-search-Dq6E746K.js} +1 -1
  242. package/dist/{mongodb-kb-search-BBYY_d_r.js → mongodb-kb-search-DvsXIUy6.js} +3 -3
  243. package/dist/{mongodb-manager-BVfTfpHf.js → mongodb-manager-DEZIQXuo.js} +10 -10
  244. package/dist/{mongodb-manager-BJ0PAYF_.js → mongodb-manager-NkerSpvH.js} +1183 -331
  245. package/dist/{mongodb-procedures-DNPmmW5r.js → mongodb-procedures-DI-_Dakz.js} +7 -3
  246. package/dist/{mongodb-procedures-D3M2Ph8E.js → mongodb-procedures-tjhGdBV7.js} +3 -3
  247. package/dist/{mongodb-schema-JpDXcAUV.js → mongodb-schema-DN3aspLa.js} +1 -1
  248. package/dist/{mongodb-schema-BI4Ze_ZV.js → mongodb-schema-Dt6jxcPL.js} +298 -4
  249. package/dist/{mongodb-search-VFKd72IZ.js → mongodb-search-DMsUyfpa.js} +2 -2
  250. package/dist/{mongodb-structured-memory-DnwUJ6SA.js → mongodb-structured-memory-D-3SEfTu.js} +58 -2
  251. package/dist/{mongodb-structured-memory-BySGexcm.js → mongodb-structured-memory-lpyyW0kn.js} +3 -3
  252. package/dist/{monitor-DGE0bx3s.js → monitor-BZFy1RTb.js} +47 -47
  253. package/dist/{monitor-Dfc0KXMD.js → monitor-DPYGxeY_.js} +5 -5
  254. package/dist/{monitor-CZZlkQUU.js → monitor-Duykki-j.js} +51 -51
  255. package/dist/{monitor-B61bVnMW.js → monitor-gq31SALd.js} +8 -8
  256. package/dist/{nextcloud-talk-CnwOv1rG.js → nextcloud-talk-C_-LfGeq.js} +2 -2
  257. package/dist/{node-cli-Avub0RKe.js → node-cli-NpJzvfQW.js} +12 -12
  258. package/dist/{nodes-cli-qSE-cmgX.js → nodes-cli-O5HciXeP.js} +10 -10
  259. package/dist/{nodes-screen-DQw8F5rA.js → nodes-screen-BIwiB35h.js} +1 -1
  260. package/dist/{oauth.runtime-825pMCgB.js → oauth.runtime-BxjW8DFO.js} +46 -46
  261. package/dist/{oauth.runtime-BCwH9-Yl.js → oauth.runtime-DKU2STuA.js} +46 -46
  262. package/dist/{oauth.runtime-BSddaUzc.js → oauth.runtime-mFizWM72.js} +46 -46
  263. package/dist/{onboard-CUbnVxXL.js → onboard-B6H0qDtg.js} +1 -1
  264. package/dist/{onboard-BF8cNljJ.js → onboard-C1AmXQ6f.js} +8 -8
  265. package/dist/{onboard-Cw65XmEU.js → onboard-DPdj0IBu.js} +2 -2
  266. package/dist/{onboard-channels-BYNDTtRI.js → onboard-channels-Cmj_5qXQ.js} +24 -24
  267. package/dist/{onboard-channels-CIR1ZSii.js → onboard-channels-Wf3nY9Bf.js} +97 -97
  268. package/dist/{onboard-custom-FImARgQC.js → onboard-custom-DILgXkiq.js} +50 -50
  269. package/dist/{onboard-custom-C4qOVxtG.js → onboard-custom-DlDCjvIw.js} +4 -4
  270. package/dist/{onboard-helpers-DW9Mskds.js → onboard-helpers-CqpD9TVU.js} +48 -48
  271. package/dist/{onboard-helpers-D3xV_T96.js → onboard-helpers-D-PLdtHT.js} +3 -3
  272. package/dist/{onboard-hooks-B0gJVtBY.js → onboard-hooks-MQ8QOguv.js} +2 -2
  273. package/dist/{onboard-remote-BMLo6WKH.js → onboard-remote-BZKWgKVw.js} +50 -50
  274. package/dist/{onboard-remote-XUah3N3G.js → onboard-remote-Bnad5LMv.js} +2 -2
  275. package/dist/{onboard-search-DHCzqxgq.js → onboard-search-Dyv1IuQ4.js} +46 -46
  276. package/dist/{onboard-skills-LXCIpyir.js → onboard-skills-DdCu1_hE.js} +1 -1
  277. package/dist/{onboard-skills-CH6q90Pf.js → onboard-skills-W_252asS.js} +49 -49
  278. package/dist/{onboarding-memory-CTB-Vkbl.js → onboarding-memory-BRHSmwx3.js} +6 -6
  279. package/dist/{outbound-media-CqfP0r4a.js → outbound-media-CHc08Sj8.js} +1 -1
  280. package/dist/{pairing-cli-BdCkQG2S.js → pairing-cli-oNWkjwCt.js} +5 -5
  281. package/dist/{persistent-dedupe-DNnh7hrR.js → persistent-dedupe-CS_uyVoq.js} +1 -1
  282. package/dist/{pi-model-discovery-runtime-DyT9C3Ap.js → pi-model-discovery-runtime-BJVREOXf.js} +46 -46
  283. package/dist/{pi-tools.before-tool-call.runtime-CA2js1Ig.js → pi-tools.before-tool-call.runtime-w-Q4HA_S.js} +6 -6
  284. package/dist/{plugin-install-DgvJfz7X.js → plugin-install-BysMw7Sl.js} +47 -47
  285. package/dist/{plugin-install-BKuy_--2.js → plugin-install-EyES0vGP.js} +2 -2
  286. package/dist/{plugin-registry-D-6OBqUU.js → plugin-registry-BenF9SYR.js} +47 -47
  287. package/dist/{plugin-registry-Dsx_6z3N.js → plugin-registry-CRV_Bc8K.js} +3 -3
  288. package/dist/plugin-sdk/account-resolution.js +46 -46
  289. package/dist/plugin-sdk/acp-runtime.js +46 -46
  290. package/dist/plugin-sdk/agent-runtime.js +46 -46
  291. package/dist/plugin-sdk/channel-inbound.js +46 -46
  292. package/dist/plugin-sdk/channel-reply-pipeline.js +3 -3
  293. package/dist/plugin-sdk/channel-runtime.js +46 -46
  294. package/dist/plugin-sdk/channel-setup.js +1 -1
  295. package/dist/plugin-sdk/command-auth.js +46 -46
  296. package/dist/plugin-sdk/compat.js +5 -5
  297. package/dist/plugin-sdk/config-runtime.js +46 -46
  298. package/dist/plugin-sdk/conversation-runtime.js +46 -46
  299. package/dist/plugin-sdk/core.js +5 -5
  300. package/dist/plugin-sdk/directory-runtime.js +1 -1
  301. package/dist/plugin-sdk/discord.js +46 -46
  302. package/dist/plugin-sdk/gateway-runtime.js +8 -8
  303. package/dist/plugin-sdk/image-generation.js +46 -46
  304. package/dist/plugin-sdk/index.js +46 -46
  305. package/dist/plugin-sdk/infra-runtime.js +46 -46
  306. package/dist/plugin-sdk/llm-task.js +46 -46
  307. package/dist/plugin-sdk/matrix-runtime-heavy.js +50 -50
  308. package/dist/plugin-sdk/media-runtime.js +46 -46
  309. package/dist/plugin-sdk/media-understanding-runtime.js +46 -46
  310. package/dist/plugin-sdk/media-understanding.js +46 -46
  311. package/dist/plugin-sdk/ollama-setup.js +8 -8
  312. package/dist/plugin-sdk/plugin-runtime.js +46 -46
  313. package/dist/plugin-sdk/provider-auth-api-key.js +46 -46
  314. package/dist/plugin-sdk/provider-auth-login.js +1 -1
  315. package/dist/plugin-sdk/provider-auth.js +46 -46
  316. package/dist/plugin-sdk/provider-models.js +5 -5
  317. package/dist/plugin-sdk/provider-onboard.js +5 -5
  318. package/dist/plugin-sdk/provider-setup.js +49 -49
  319. package/dist/plugin-sdk/provider-stream.js +46 -46
  320. package/dist/plugin-sdk/provider-usage.js +4 -4
  321. package/dist/plugin-sdk/reply-history.js +3 -3
  322. package/dist/plugin-sdk/reply-runtime.js +46 -46
  323. package/dist/plugin-sdk/routing.js +3 -3
  324. package/dist/plugin-sdk/sandbox.js +46 -46
  325. package/dist/plugin-sdk/self-hosted-provider-setup.js +48 -48
  326. package/dist/plugin-sdk/setup-runtime.js +1 -1
  327. package/dist/plugin-sdk/setup.js +1 -1
  328. package/dist/plugin-sdk/speech-runtime.js +46 -46
  329. package/dist/plugin-sdk/speech.js +46 -46
  330. package/dist/plugin-sdk/src/agents/workspace.d.ts +1 -3
  331. package/dist/plugin-sdk/src/config/types.memory.d.ts +44 -0
  332. package/dist/plugin-sdk/src/memory/backend-config.d.ts +24 -0
  333. package/dist/plugin-sdk/src/memory/index.d.ts +12 -4
  334. package/dist/plugin-sdk/src/memory/mongodb-entity-extractor.d.ts +33 -0
  335. package/dist/plugin-sdk/src/memory/mongodb-episodes.d.ts +16 -0
  336. package/dist/plugin-sdk/src/memory/mongodb-events.d.ts +9 -0
  337. package/dist/plugin-sdk/src/memory/mongodb-graph.d.ts +30 -3
  338. package/dist/plugin-sdk/src/memory/mongodb-manager.d.ts +18 -0
  339. package/dist/plugin-sdk/src/memory/mongodb-mutations.d.ts +38 -0
  340. package/dist/plugin-sdk/src/memory/mongodb-procedures.d.ts +32 -0
  341. package/dist/plugin-sdk/src/memory/mongodb-profile.d.ts +71 -0
  342. package/dist/plugin-sdk/src/memory/mongodb-query-cache.d.ts +68 -0
  343. package/dist/plugin-sdk/src/memory/mongodb-query-rewriter.d.ts +39 -0
  344. package/dist/plugin-sdk/src/memory/mongodb-reranker.d.ts +32 -0
  345. package/dist/plugin-sdk/src/memory/mongodb-schema.d.ts +3 -0
  346. package/dist/plugin-sdk/src/memory/mongodb-telemetry.d.ts +69 -0
  347. package/dist/plugin-sdk/text-runtime.js +6 -6
  348. package/dist/plugin-sdk/web-media.js +3 -3
  349. package/dist/plugin-sdk/zalo.js +47 -47
  350. package/dist/plugin-sdk/zalouser.js +47 -47
  351. package/dist/plugins/build-smoke-entry.js +46 -46
  352. package/dist/plugins/runtime/index.js +46 -46
  353. package/dist/{plugins-cli-C6wGAkD9.js → plugins-cli-BUiP4x7l.js} +46 -46
  354. package/dist/{policy-CcgojW9R.js → policy-DnUfJkOZ.js} +1 -1
  355. package/dist/{preflight-audio.runtime-Cyz9Zu89.js → preflight-audio.runtime-D3_iaSgF.js} +46 -46
  356. package/dist/{probe-auth-BmluVNJZ.js → probe-auth-BbNdYwb0.js} +1 -1
  357. package/dist/{probe-auth-DrgTJ7ki.js → probe-auth-CB9y2dLl.js} +7 -7
  358. package/dist/{program-BjkVOzbF.js → program-uHYlUP3c.js} +4 -4
  359. package/dist/{prompt-select-styled-6vDD4Gjv.js → prompt-select-styled-DoTAWghe.js} +25 -51
  360. package/dist/{provider-api-key-auth.runtime-AT16DTa8.js → provider-api-key-auth.runtime-B3H0dODg.js} +46 -46
  361. package/dist/{provider-auth-choice-UhIkLc6q.js → provider-auth-choice-HRfxXEHk.js} +6 -6
  362. package/dist/{provider-auth-choice-helpers-CXWmWOdR.js → provider-auth-choice-helpers-2jZnBKMm.js} +1 -1
  363. package/dist/{provider-auth-choice-preference-TgulgKlz.js → provider-auth-choice-preference-CqKryjBB.js} +6 -6
  364. package/dist/{provider-auth-choice.runtime-FTNgi8Yh.js → provider-auth-choice.runtime-BaFSZgQG.js} +48 -48
  365. package/dist/{provider-auth-choice.runtime-CP91b3vK.js → provider-auth-choice.runtime-DPHuj1_l.js} +2 -2
  366. package/dist/{provider-auth-choices-BfWvatIg.js → provider-auth-choices-CqFh00uK.js} +1 -1
  367. package/dist/{provider-auth-guidance-D4-q7IHl.js → provider-auth-guidance-DmdBoDfS.js} +2 -2
  368. package/dist/{provider-auth-input-DnQ-RiX5.js → provider-auth-input-FZYEJh19.js} +46 -46
  369. package/dist/{provider-auth-login-D7eLUZwy.js → provider-auth-login-B-XedaK5.js} +1 -1
  370. package/dist/{provider-auth-login.runtime-BG_qqxZk.js → provider-auth-login.runtime-f9dxfJUB.js} +49 -49
  371. package/dist/{provider-model-allowlist-CC0lIQ6w.js → provider-model-allowlist-C16pn0B8.js} +1 -1
  372. package/dist/{provider-models-DbK6xrje.js → provider-models-PaymKOme.js} +1 -1
  373. package/dist/{provider-ollama-setup-B4RWr9oj.js → provider-ollama-setup-k5ozCUi2.js} +3 -3
  374. package/dist/{provider-onboarding-config-W5sF0oD8.js → provider-onboarding-config-qCltsaVl.js} +1 -1
  375. package/dist/{provider-runtime.runtime-Cva8S4wx.js → provider-runtime.runtime-CzVe0WBb.js} +46 -46
  376. package/dist/{provider-self-hosted-setup-jAzqLaqv.js → provider-self-hosted-setup-zxYnIftX.js} +3 -3
  377. package/dist/{provider-usage-CEgSCMW4.js → provider-usage-C9KdAhuS.js} +46 -46
  378. package/dist/{provider-usage-CCIC3SdY.js → provider-usage-DexJNI_0.js} +1 -1
  379. package/dist/{provider-wizard-DQd5eYhX.js → provider-wizard-D4RbMR2D.js} +2 -2
  380. package/dist/{push-apns-DQN5pcl6.js → push-apns-BAc0-Jy5.js} +1 -1
  381. package/dist/{pw-ai-BiXz8un2.js → pw-ai-C8v0s5wH.js} +6 -6
  382. package/dist/{qr-cli-B8bBpCd2.js → qr-cli-BpqLcmYC.js} +47 -47
  383. package/dist/{qr-cli-DOuhqzho.js → qr-cli-D0zqiQMl.js} +4 -4
  384. package/dist/{reactions-BkyHqIw4.js → reactions-CjJbniYK.js} +1 -1
  385. package/dist/{read-only-account-inspect-Cfaj7PFb.js → read-only-account-inspect-CEJ1r7AW.js} +3 -3
  386. package/dist/{read-only-account-inspect.discord.runtime-kreMwVgq.js → read-only-account-inspect.discord.runtime-C1n8r_Kj.js} +46 -46
  387. package/dist/{read-only-account-inspect.slack.runtime-DgV5VZ-n.js → read-only-account-inspect.slack.runtime-DAOzA9ke.js} +46 -46
  388. package/dist/{read-only-account-inspect.telegram.runtime-BQaHHCIS.js → read-only-account-inspect.telegram.runtime-CfNlnogC.js} +46 -46
  389. package/dist/{redact-snapshot-PisBVQFW.js → redact-snapshot-qQFn3bz8.js} +3 -3
  390. package/dist/{register.agent-CXTssAWM.js → register.agent-DC5QbIE7.js} +114 -114
  391. package/dist/{register.backup-MRTb86c6.js → register.backup-BRxspFkM.js} +6 -6
  392. package/dist/{register.configure-BfE3p-3h.js → register.configure-B7zhRBla.js} +120 -120
  393. package/dist/{register.maintenance-CjOZ-w_0.js → register.maintenance-CCmppLW1.js} +65 -65
  394. package/dist/{register.message-s1z2QSP2.js → register.message-DSBPJS4x.js} +47 -47
  395. package/dist/{register.onboard-GSGJTcJk.js → register.onboard-C4D9pjf7.js} +54 -54
  396. package/dist/{register.setup-BD774nEM.js → register.setup-C4pDa0HW.js} +52 -52
  397. package/dist/{register.status-health-sessions-D-Xp8ae7.js → register.status-health-sessions-ClxLTjC5.js} +55 -55
  398. package/dist/{register.subclis-BlqPR8UO.js → register.subclis-BauDruMA.js} +30 -30
  399. package/dist/{register.subclis-CeG9qCbt.js → register.subclis-WyYRaoa-.js} +1 -1
  400. package/dist/{replies-DQwDaTBP.js → replies-CZGcXYVE.js} +1 -1
  401. package/dist/{reply-history-DVLrt4Es.js → reply-history-1yT9Tzib.js} +1 -1
  402. package/dist/{routes-CBWjQBhD.js → routes-D8CYDLDF.js} +5 -5
  403. package/dist/{rpc-O719GSVf.js → rpc-D8I_Qzen.js} +1 -1
  404. package/dist/{run-main-C4Box4Zo.js → run-main-BwEbDjI-.js} +19 -19
  405. package/dist/{runtime-COpSaRtb.js → runtime-CmSMHqwN.js} +1 -1
  406. package/dist/{runtime-PbP8BVEV.js → runtime-DQaeo-1L.js} +2 -2
  407. package/dist/{runtime-discord-ops.runtime-CmStqYK4.js → runtime-discord-ops.runtime-8w-055sR.js} +46 -46
  408. package/dist/{runtime-slack-ops.runtime-Cm1935hR.js → runtime-slack-ops.runtime-XJJrByCY.js} +48 -48
  409. package/dist/{runtime-telegram-ops.runtime-CKozoVxf.js → runtime-telegram-ops.runtime-wOdrd2eH.js} +46 -46
  410. package/dist/{sandbox-cli-BIyJ-1r-.js → sandbox-cli-CvFmY6Kq.js} +46 -46
  411. package/dist/{search-manager-BVE1EPHv.js → search-manager-ZNiamJHa.js} +6 -6
  412. package/dist/{search-manager-DMTYqpmg.js → search-manager-zaZ4tAYz.js} +5 -5
  413. package/dist/{secrets-cli-CMMtWzst.js → secrets-cli-D5a_lvAP.js} +47 -47
  414. package/dist/{security-cli-Bw4cVkTN.js → security-cli-DJovxmST.js} +47 -47
  415. package/dist/{send-CfI8y11o.js → send-C3KhjjcU.js} +1 -1
  416. package/dist/{send-C8HDmafP.js → send-CIkS5fLj.js} +2 -2
  417. package/dist/{server-0n2tu0ff.js → server-B1z10Ohi.js} +6 -6
  418. package/dist/{server-node-events-J5-mGOea.js → server-node-events-D3_b2nU-.js} +47 -47
  419. package/dist/{server-startup-matrix-migration-CMBUtdN2.js → server-startup-matrix-migration-DDRaKUPQ.js} +3 -3
  420. package/dist/{session-cost-usage-CrPCO4HN.js → session-cost-usage-BwIud0lY.js} +46 -46
  421. package/dist/{sessions-n_Z6bcbr.js → sessions-B5Pffwj6.js} +3 -3
  422. package/dist/{sessions-BK_M3Nu1.js → sessions-ClamZkvP.js} +47 -47
  423. package/dist/{setup-CjQJLNqB.js → setup-B8gsbmH4.js} +18 -18
  424. package/dist/{setup-core-BVBCTInv.js → setup-core-B6csKf5s.js} +2 -2
  425. package/dist/{setup-core-z8Q1sgUU.js → setup-core-DkgiVKzw.js} +2 -2
  426. package/dist/{setup-entry-CvuaW-4I.js → setup-entry-C8XH3da9.js} +2 -2
  427. package/dist/{setup-entry-Jf6V23s6.js → setup-entry-CMSlnfft.js} +3 -3
  428. package/dist/{setup-entry-Bo3chgoG.js → setup-entry-CZVAwPKZ.js} +2 -2
  429. package/dist/{setup-entry-Co-YP41_.js → setup-entry-Duh-ewBV.js} +3 -3
  430. package/dist/{setup-entry-BnSZlMP1.js → setup-entry-ksUWY45r.js} +2 -2
  431. package/dist/{setup-entry-BNSYJMzp.js → setup-entry-vQgAuveW.js} +2 -2
  432. package/dist/{setup-group-access-BYV3O8yu.js → setup-group-access-CTlnq-M9.js} +1 -1
  433. package/dist/{setup-surface-B6XBqyMJ.js → setup-surface-B7uYEI9F.js} +2 -2
  434. package/dist/{setup-surface-fixjWejm.js → setup-surface-CMgQr2R9.js} +5 -5
  435. package/dist/{setup-surface-CzzV3QV6.js → setup-surface-Yd-YLGfa.js} +46 -46
  436. package/dist/{setup-wizard-proxy-DFDQV7FN.js → setup-wizard-proxy-CHGAY6ob.js} +1 -1
  437. package/dist/{setup.finalize-ChczeW6V.js → setup.finalize-C2bq4D8j.js} +58 -58
  438. package/dist/{setup.gateway-config-Bp50kjo3.js → setup.gateway-config-BGgVOvQf.js} +48 -48
  439. package/dist/{shared-CyR3Ki--.js → shared-BEMZg0vb.js} +5 -5
  440. package/dist/{shared-DXzPv5D7.js → shared-BYRyVoVx.js} +5 -5
  441. package/dist/{shared-DCOVJ3QB.js → shared-Bj3fwdyM.js} +4 -4
  442. package/dist/{shared-B8_JHpU2.js → shared-CSydqOgE.js} +4 -4
  443. package/dist/{shared-C3fKAUbw.js → shared-DLAg-pKT.js} +3 -3
  444. package/dist/{signal-D16eMrBf.js → signal-Dh6z2uaT.js} +5 -5
  445. package/dist/{signal-oGrspg1k.js → signal-FEtxekyc.js} +46 -46
  446. package/dist/{skills-cli-CY6lUTRv.js → skills-cli-9NuRJd3Z.js} +5 -5
  447. package/dist/{slack-ueYeeNF7.js → slack-Ci1VArkq.js} +48 -48
  448. package/dist/{slack-B1GgT1_u.js → slack-CjslLjTc.js} +5 -5
  449. package/dist/{slash-commands.runtime-1q-llUpe.js → slash-commands.runtime-COXzcGjL.js} +46 -46
  450. package/dist/{slash-dispatch.runtime-BqJ1FZZ6.js → slash-dispatch.runtime-D5j8d7dg.js} +47 -47
  451. package/dist/{slash-skill-commands.runtime-D-BEZgQ1.js → slash-skill-commands.runtime-6U65Nany.js} +46 -46
  452. package/dist/{status-CnKcjD2h.js → status-BWUft8B5.js} +16 -16
  453. package/dist/{status-C1BR9Hft.js → status-BjV1ysoW.js} +50 -50
  454. package/dist/{status-D_1nxvoi.js → status-CM77XYRR.js} +4 -4
  455. package/dist/{status-Dp3OriYl.js → status-D7XHAzLz.js} +46 -46
  456. package/dist/{status-DoSH4nEL.js → status-DwO4xEHI.js} +54 -54
  457. package/dist/{status-json-DwNPzoCk.js → status-json-BYDBfkr3.js} +19 -19
  458. package/dist/{status-B45v-A8b.js → status-yoA_KX2O.js} +1 -1
  459. package/dist/{status.link-channel-Cz8GoHZ2.js → status.link-channel-DkISMfW8.js} +2 -2
  460. package/dist/{status.scan.deps.runtime-BQGei2B_.js → status.scan.deps.runtime-B6__B0kL.js} +14 -14
  461. package/dist/{status.scan.runtime-D4HkKTZu.js → status.scan.runtime-BAkcX3vO.js} +2 -2
  462. package/dist/{status.summary-Dxo5qDuD.js → status.summary-DNaMhaXy.js} +8 -8
  463. package/dist/{subagent-orphan-recovery-BPa7yoId.js → subagent-orphan-recovery-DtK8inah.js} +46 -46
  464. package/dist/{subagent-registry-runtime-B6homy_H.js → subagent-registry-runtime-02s7QJo3.js} +46 -46
  465. package/dist/{synology-chat-DY8xNv_g.js → synology-chat-QURTpvMf.js} +2 -2
  466. package/dist/{system-cli-CkWRbLu4.js → system-cli-BXd7evEt.js} +7 -7
  467. package/dist/{system-run-command-jY6Is_ri.js → system-run-command-CQCx0f24.js} +1 -1
  468. package/dist/telegram/audit.js +1 -1
  469. package/dist/telegram/token.js +46 -46
  470. package/dist/{telegram-uQdpyLeS.js → telegram-Btwvg0PX.js} +46 -46
  471. package/dist/{telegram-Bnigf1Qe.js → telegram-Dh5gM1mc.js} +7 -7
  472. package/dist/{tool-policy-match-BLASiL8y.js → tool-policy-match-B6J0bSfQ.js} +1 -1
  473. package/dist/{tui-Dj52JiFV.js → tui-CKGcNyM8.js} +6 -6
  474. package/dist/{tui-cli-B4SN4wzX.js → tui-cli-D3CLnnB9.js} +47 -47
  475. package/dist/{update-cli-mBB0aHxZ.js → update-cli-DQ4j_nIh.js} +69 -69
  476. package/dist/{update-offset-store-Bp1RjZK2.js → update-offset-store-RxVdgbyo.js} +46 -46
  477. package/dist/{upsert-with-lock-CFIy4b7I.js → upsert-with-lock-BqkAnFym.js} +1 -1
  478. package/dist/{web-media-BJ-azd7j.js → web-media-BM1Mg6AN.js} +1 -1
  479. package/dist/{webhook-shared-DYKTXPVw.js → webhook-shared-UDKLpQnU.js} +1 -1
  480. package/dist/{webhooks-cli-CEBJbLqS.js → webhooks-cli-Ca3PlK8h.js} +5 -5
  481. package/dist/{whatsapp-63jqHVrE.js → whatsapp-CHEvDa2g.js} +46 -46
  482. package/dist/{with-timeout-CvaBvNie.js → with-timeout-CvBH67nj.js} +2 -2
  483. package/dist/{workspace-DuH1agxz.js → workspace-uCYzunu4.js} +5 -33
  484. package/dist/{zalo-CTrI2C4i.js → zalo-Dr4ysJLW.js} +1 -1
  485. package/dist/{zalo-Sw_XHo3-.js → zalo-keqX1Wnx.js} +2 -2
  486. package/docs/concepts/agent-workspace.md +0 -5
  487. package/docs/concepts/memory.md +6 -12
  488. package/docs/plans/2026-03-22-semantic-cache-telemetry-docs-plan.md +1431 -0
  489. package/docs/plans/2026-03-22-supermemory-steals-plan.md +1679 -0
  490. package/docs/plans/2026-03-23-almost-perfect-sprint-plan.md +1080 -0
  491. package/docs/plans/2026-03-23-master-steal-list.md +224 -0
  492. package/docs/plans/2026-03-23-memory-md-deprecation-plan.md +632 -0
  493. package/docs/plans/2026-03-23-production-readiness-e2e-plan.md +659 -0
  494. package/docs/plans/2026-03-23-supermemory-audit-fixes-plan.md +1291 -0
  495. package/docs/reference/clawmongo-vs-default-memory.md +2 -2
  496. package/docs/reference/heart-brain-boundary.md +8 -10
  497. package/docs/reference/memory-config.md +3 -4
  498. package/docs/reference/mongodb-capabilities.md +246 -9
  499. package/docs/reference/templates/AGENTS.md +5 -10
  500. package/docs/research/2026-03-22-atlas-local-preview-web.md +41 -31
  501. package/docs/research/2026-03-23-agent-management-ui-github.md +482 -0
  502. package/docs/research/2026-03-23-almost-perfect-mongodb-docs.md +255 -0
  503. package/docs/research/2026-03-23-company-os-agent-ui-web.md +511 -0
  504. package/docs/research/2026-03-23-supermemory-audit-fixes-mongodb-research.md +995 -0
  505. package/docs/start/clawmongo-getting-started.md +1 -1
  506. package/package.json +1 -1
  507. /package/dist/{memory-BAVM2Jxh.js → memory-CcbELE82.js} +0 -0
@@ -0,0 +1,1679 @@
1
+ # Supermemory-Inspired Features: Profile Synthesis, Cross-Encoder Re-ranking, Query Rewriting, LLM Entity Extraction
2
+
3
+ > **For Claude:** REQUIRED: Follow this plan task-by-task using TDD.
4
+ > **Research:** 4 sub-agents (Supermemory deep-dive, ClawMongo deep-dive, architecture-fit analysis, MongoDB best-practices research).
5
+
6
+ **Goal:** Add 4 high-value features inspired by Supermemory research into ClawMongo's memory system. All validated as native fits with zero conflicts, zero new collections, zero breaking changes.
7
+
8
+ **Architecture:** All features integrate at different stages of the existing pipeline — profile is read-only aggregation, reranking is post-search, query rewriting is pre-search, entity extraction is write-side. No feature touches another's stage.
9
+
10
+ **Tech Stack:** MongoDB Community + mongot, TypeScript ESM, Vitest, Voyage AI (autoEmbed + rerank-2.5 API), fire-and-forget telemetry.
11
+
12
+ **Prerequisites:** All v2 base + enhancements + consolidation + cache + telemetry COMPLETE. 22 collections, 58 standard indexes, 9 search indexes. Published @romiluz/clawmongo@2026.3.22.
13
+
14
+ **Plan Mode:** execution_plan
15
+ **Verification Rigor:** standard
16
+
17
+ ---
18
+
19
+ ## Relevant Codebase Files
20
+
21
+ ### Files to Modify
22
+
23
+ - `src/memory/mongodb-manager.ts` — searchV2() hook points for rewriting + reranking, synthesizeProfile() delegation
24
+ - `src/memory/mongodb-graph.ts` — extractAndUpsertEntities() gets optional extractor parameter
25
+ - `src/memory/mongodb-telemetry.ts` — add new TelemetryOperation values
26
+ - `src/config/types.memory.ts` — add queryRewriting, reranking, graph.entityExtraction config sections
27
+ - `src/memory/backend-config.ts` — resolve new config sections with defaults
28
+ - `src/memory/index.ts` — barrel exports for new modules
29
+
30
+ ### New Files to Create
31
+
32
+ - `src/memory/mongodb-profile.ts` — profile synthesis
33
+ - `src/memory/mongodb-profile.test.ts` — tests
34
+ - `src/memory/mongodb-reranker.ts` — cross-encoder reranking
35
+ - `src/memory/mongodb-reranker.test.ts` — tests
36
+ - `src/memory/mongodb-query-rewriter.ts` — query expansion
37
+ - `src/memory/mongodb-query-rewriter.test.ts` — tests
38
+ - `src/memory/mongodb-entity-extractor.ts` — pluggable extraction interface
39
+ - `src/memory/mongodb-entity-extractor.test.ts` — tests
40
+
41
+ ### Patterns to Follow
42
+
43
+ - `src/memory/mongodb-ops.ts` — standalone function pattern (db, prefix, ...)
44
+ - `src/memory/mongodb-query-cache.ts` — fire-and-forget writes, telemetry emission
45
+ - `src/memory/mongodb-structured-memory.ts` — scope-aware queries, revision pattern
46
+ - `src/memory/mongodb-graph.ts` — entity CRUD, $graphLookup, extractAndUpsertEntities
47
+ - `src/memory/mongodb-search.ts` — buildVectorSearchStage, fusion methods
48
+ - `src/memory/mongodb-hybrid.ts` — score normalization, RRF merge
49
+ - `src/memory/mongodb-retrieval-planner.ts` — pure-function retrieval path planner
50
+ - `src/memory/mongodb-telemetry.ts` — emitTelemetry fire-and-forget pattern
51
+
52
+ ### Validated MongoDB Syntax (from research)
53
+
54
+ **$facet for multi-collection profile synthesis:**
55
+
56
+ ```typescript
57
+ // $facet sub-pipelines run sequentially (NOT parallel)
58
+ // Pre-filter aggressively with $match BEFORE $facet to stay under 100MB RAM limit
59
+ // Use correlated $lookup with pipeline + $limit for bounded joins
60
+ const pipeline = [
61
+ { $match: { agentId, scope, scopeRef, state: "active" } },
62
+ {
63
+ $facet: {
64
+ preferences: [{ $match: { type: "preference" } }, { $limit: 20 }],
65
+ decisions: [{ $match: { type: "decision" } }, { $limit: 20 }],
66
+ facts: [{ $match: { type: "fact" } }, { $limit: 20 }],
67
+ todos: [{ $match: { type: "todo", state: "active" } }, { $limit: 10 }],
68
+ },
69
+ },
70
+ ];
71
+ ```
72
+
73
+ **Voyage rerank-2.5 API call:**
74
+
75
+ ```typescript
76
+ const response = await fetch("https://api.voyageai.com/v1/rerank", {
77
+ method: "POST",
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ Authorization: `Bearer ${voyageApiKey}`,
81
+ },
82
+ body: JSON.stringify({
83
+ model: "rerank-2.5",
84
+ query: queryText,
85
+ documents: candidateTexts,
86
+ top_k: topK,
87
+ }),
88
+ });
89
+ // Response: { object: "list", data: [{ index: number, relevance_score: number }], model: "..." }
90
+ ```
91
+
92
+ **EntityExtractor interface pattern:**
93
+
94
+ ```typescript
95
+ export interface EntityExtractor {
96
+ extract(content: string, context?: EntityExtractionContext): Promise<ExtractedEntity[]>;
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Open Decisions
103
+
104
+ None — all decisions pre-answered by research.
105
+
106
+ ## Differences from Agreement
107
+
108
+ - Previous decision (activeContext.md ## Decisions) rejected cross-encoder reranking and LLM entity extraction. User explicitly REVERSED this after Supermemory deep-dive research.
109
+ - Previous deferred item "reranked scores not exposed in search results metadata" — this plan addresses it via the reranker.
110
+
111
+ ---
112
+
113
+ ## Phase 1: Config Foundation + Telemetry Operations
114
+
115
+ > **Exit Criteria:** New config sections for queryRewriting, reranking, graph.entityExtraction added to types and resolved with defaults. New TelemetryOperation values added. 15+ tests pass.
116
+
117
+ ### Task 1.1: Add queryRewriting config to MemoryMongoDBConfig
118
+
119
+ **Files:**
120
+
121
+ - Modify: `src/config/types.memory.ts` (inside MemoryMongoDBConfig type, after `cache` section)
122
+
123
+ ```typescript
124
+ /** Query rewriting configuration */
125
+ queryRewriting?: {
126
+ /** Enable query rewriting before search. Default: false */
127
+ enabled?: boolean;
128
+ /** Rewriting strategy. Default: "synonym-expansion" */
129
+ method?: "synonym-expansion" | "llm" | "hyde";
130
+ /** Maximum rewritten query length in tokens. Default: 128 */
131
+ maxTokens?: number;
132
+ };
133
+ ```
134
+
135
+ ### Task 1.2: Add reranking config to MemoryMongoDBConfig
136
+
137
+ **Files:**
138
+
139
+ - Modify: `src/config/types.memory.ts` (after queryRewriting section)
140
+
141
+ ```typescript
142
+ /** Cross-encoder re-ranking configuration */
143
+ reranking?: {
144
+ /** Enable cross-encoder re-ranking. Default: false */
145
+ enabled?: boolean;
146
+ /** Re-ranking model. Default: "rerank-2.5" */
147
+ model?: "rerank-2.5" | "rerank-2.5-lite";
148
+ /** Maximum documents to send to reranker. Default: 20 */
149
+ topN?: number;
150
+ /** Minimum retrieval score to be eligible for re-ranking. Default: 0.1 */
151
+ minScore?: number;
152
+ /** Voyage API key. Env fallback: VOYAGE_API_KEY */
153
+ voyageApiKey?: string;
154
+ /** Optional instruction prepended to query for rerank-2.5 instruction-following (8-11% accuracy boost). */
155
+ instruction?: string;
156
+ };
157
+ ```
158
+
159
+ ### Task 1.3: Add entityExtraction config to graph section
160
+
161
+ **Files:**
162
+
163
+ - Modify: `src/config/types.memory.ts` (expand existing `graph` section)
164
+
165
+ ```typescript
166
+ /** Graph projection config */
167
+ graph?: {
168
+ /** Enable graph projection. Default: true */
169
+ enabled?: boolean;
170
+ /** Max depth for $graphLookup. Default: 2 */
171
+ maxGraphDepth?: number;
172
+ /** Entity extraction configuration */
173
+ entityExtraction?: {
174
+ /** Extraction strategy. Default: "regex" */
175
+ method?: "regex" | "llm";
176
+ /** LLM model for extraction (when method="llm"). Uses agent default if omitted */
177
+ model?: string;
178
+ /** Timeout for LLM extraction in ms. Default: 5000 */
179
+ timeoutMs?: number;
180
+ };
181
+ };
182
+ ```
183
+
184
+ ### Task 1.4: Add resolved config sections to ResolvedMongoDBConfig
185
+
186
+ **Files:**
187
+
188
+ - Modify: `src/memory/backend-config.ts` (add to ResolvedMongoDBConfig type)
189
+
190
+ ```typescript
191
+ queryRewriting: {
192
+ enabled: boolean;
193
+ method: "synonym-expansion" | "llm" | "hyde";
194
+ maxTokens: number;
195
+ };
196
+ reranking: {
197
+ enabled: boolean;
198
+ model: "rerank-2.5" | "rerank-2.5-lite";
199
+ topN: number;
200
+ minScore: number;
201
+ voyageApiKey: string;
202
+ };
203
+ // Expand existing graph section:
204
+ graph: {
205
+ enabled: boolean;
206
+ maxGraphDepth: number;
207
+ entityExtraction: {
208
+ method: "regex" | "llm";
209
+ model?: string;
210
+ timeoutMs: number;
211
+ };
212
+ };
213
+ ```
214
+
215
+ ### Task 1.5: Resolve new config sections with defaults
216
+
217
+ **Files:**
218
+
219
+ - Modify: `src/memory/backend-config.ts` (in resolveMemoryBackendConfig, after `cache` resolution)
220
+
221
+ ```typescript
222
+ queryRewriting: {
223
+ enabled: mongoCfg?.queryRewriting?.enabled === true, // disabled by default
224
+ method: mongoCfg?.queryRewriting?.method ?? "synonym-expansion",
225
+ maxTokens: mongoCfg?.queryRewriting?.maxTokens ?? 128,
226
+ },
227
+ reranking: {
228
+ enabled: mongoCfg?.reranking?.enabled === true, // disabled by default
229
+ model: mongoCfg?.reranking?.model ?? "rerank-2.5",
230
+ topN: mongoCfg?.reranking?.topN ?? 20,
231
+ minScore: mongoCfg?.reranking?.minScore ?? 0.1,
232
+ voyageApiKey: mongoCfg?.reranking?.voyageApiKey ?? process.env.VOYAGE_API_KEY ?? "",
233
+ },
234
+ // Expand existing graph resolution:
235
+ graph: {
236
+ enabled: mongoCfg?.graph?.enabled !== false,
237
+ maxGraphDepth: mongoCfg?.graph?.maxGraphDepth ?? 2,
238
+ entityExtraction: {
239
+ method: mongoCfg?.graph?.entityExtraction?.method ?? "regex",
240
+ model: mongoCfg?.graph?.entityExtraction?.model,
241
+ timeoutMs: mongoCfg?.graph?.entityExtraction?.timeoutMs ?? 5000,
242
+ },
243
+ },
244
+ ```
245
+
246
+ **Note:** `queryRewriting` and `reranking` use `=== true` (disabled by default), unlike `cache`/`graph`/`episodes` which use `!== false` (enabled by default). This is intentional — these features add latency and cost.
247
+
248
+ ### Task 1.6: Add new TelemetryOperation values
249
+
250
+ **Files:**
251
+
252
+ - Modify: `src/memory/mongodb-telemetry.ts` (expand TelemetryOperation union)
253
+
254
+ ```typescript
255
+ export type TelemetryOperation =
256
+ | "search"
257
+ | "event-write"
258
+ | "projection-run"
259
+ | "cache-check"
260
+ | "graph-expansion"
261
+ | "profile-synthesis"
262
+ | "rerank"
263
+ | "query-rewrite"
264
+ | "entity-extraction";
265
+ ```
266
+
267
+ Add optional fields to TelemetryDocument:
268
+
269
+ ```typescript
270
+ export type TelemetryDocument = {
271
+ // ... existing fields ...
272
+ rerankModel?: string;
273
+ rerankLatencyMs?: number;
274
+ queryRewritten?: boolean;
275
+ rewriteMethod?: string;
276
+ extractionMethod?: string;
277
+ entitiesExtracted?: number;
278
+ };
279
+ ```
280
+
281
+ ### Task 1.7: Write config tests
282
+
283
+ **Files:**
284
+
285
+ - Modify: `src/memory/backend-config.test.ts`
286
+
287
+ **Tests:**
288
+
289
+ 1. `resolves queryRewriting defaults (disabled, synonym-expansion, 128)`
290
+ 2. `resolves queryRewriting with explicit values`
291
+ 3. `resolves reranking defaults (disabled, rerank-2.5, topN=20, minScore=0.1)`
292
+ 4. `resolves reranking with explicit values`
293
+ 5. `resolves reranking.voyageApiKey from env fallback`
294
+ 6. `resolves graph.entityExtraction defaults (regex, timeoutMs=5000)`
295
+ 7. `resolves graph.entityExtraction with llm method`
296
+ 8. `preserves existing graph.enabled and maxGraphDepth behavior`
297
+
298
+ ```bash
299
+ pnpm test -- src/memory/backend-config.test.ts
300
+ ```
301
+
302
+ **Commit after Phase 1:**
303
+
304
+ ```
305
+ Feat: add config sections for query rewriting, cross-encoder reranking, and LLM entity extraction
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Phase 2: Profile Synthesis
311
+
312
+ > **Exit Criteria:** `mongodb-profile.ts` module with synthesizeProfile() function. Reads structured_mem, entities, relations, episodes, events. Returns ProfileSynthesis object. Telemetry emitted. 18+ tests pass.
313
+
314
+ ### Task 2.1: Create mongodb-profile.ts with types
315
+
316
+ **Files:**
317
+
318
+ - Create: `src/memory/mongodb-profile.ts`
319
+
320
+ ```typescript
321
+ import type { Db, Document } from "mongodb";
322
+ import { createSubsystemLogger } from "../logging/subsystem.js";
323
+ import type { MemoryScope } from "../config/types.memory.js";
324
+ import {
325
+ structuredMemCollection,
326
+ entitiesCollection,
327
+ relationsCollection,
328
+ episodesCollection,
329
+ eventsCollection,
330
+ } from "./mongodb-schema.js";
331
+ import { emitTelemetry } from "./mongodb-telemetry.js";
332
+
333
+ const log = createSubsystemLogger("memory:mongodb:profile");
334
+
335
+ // ---------------------------------------------------------------------------
336
+ // Types
337
+ // ---------------------------------------------------------------------------
338
+
339
+ export type ProfileSynthesis = {
340
+ agentId: string;
341
+ scope: MemoryScope;
342
+ scopeRef: string;
343
+ /** Structured memory grouped by type */
344
+ preferences: ProfileMemoryItem[];
345
+ decisions: ProfileMemoryItem[];
346
+ facts: ProfileMemoryItem[];
347
+ todos: ProfileMemoryItem[];
348
+ /** Top entities by relation count */
349
+ topEntities: ProfileEntity[];
350
+ /** Most recent episode summaries */
351
+ recentEpisodes: ProfileEpisode[];
352
+ /** Activity patterns derived from events */
353
+ activityPatterns: ActivityPatterns;
354
+ /** Synthesis timestamp */
355
+ synthesizedAt: Date;
356
+ };
357
+
358
+ export type ProfileMemoryItem = {
359
+ key: string;
360
+ value: string;
361
+ salience: string;
362
+ updatedAt: Date;
363
+ };
364
+
365
+ export type ProfileEntity = {
366
+ name: string;
367
+ type: string;
368
+ relationCount: number;
369
+ };
370
+
371
+ export type ProfileEpisode = {
372
+ title: string;
373
+ summary: string;
374
+ type: string;
375
+ timeRange: { start: Date; end: Date };
376
+ };
377
+
378
+ export type ActivityPatterns = {
379
+ /** Distribution of events by role (user, assistant, system, tool) */
380
+ roleDistribution: Record<string, number>;
381
+ /** Total event count in the analysis window */
382
+ totalEvents: number;
383
+ /** Most recent event timestamp */
384
+ lastActive: Date | null;
385
+ };
386
+ ```
387
+
388
+ ### Task 2.2: Implement synthesizeProfile()
389
+
390
+ **Files:**
391
+
392
+ - Modify: `src/memory/mongodb-profile.ts`
393
+
394
+ **Implementation approach:**
395
+
396
+ 1. Query structured_mem with $facet for 4 types (preferences, decisions, facts, todos) — pre-filtered by {agentId, scope, scopeRef, state: "active"}, each sub-pipeline limited to 20 items, sorted by salience priority then updatedAt desc
397
+ 2. Query entities with $lookup on relations to get relation count — find top 10 entities by relation count for this agent/scope
398
+ 3. Query episodes — find most recent 10 episodes sorted by timeRange.start desc
399
+ 4. Query events with $group — aggregate roleDistribution and totalEvents for activity patterns (last 30 days window)
400
+ 5. Assemble ProfileSynthesis object
401
+ 6. Emit telemetry (profile-synthesis operation)
402
+
403
+ **Salience sort order:** critical > high > normal > low (use a priority map: { critical: 0, high: 1, normal: 2, low: 3 })
404
+
405
+ **Key patterns:**
406
+
407
+ - All queries filter by `{ agentId, scope, scopeRef }`
408
+ - Use existing collection accessors from mongodb-schema.ts
409
+ - $facet on structured_mem for the 4 types (most efficient — single pass)
410
+ - $lookup + $group on entities → relations for relation count
411
+ - Simple find + sort + limit for episodes
412
+ - $group on events for activity patterns
413
+ - Pre-filter aggressively before $facet to stay under 100MB RAM limit
414
+
415
+ ```typescript
416
+ export async function synthesizeProfile(params: {
417
+ db: Db;
418
+ prefix: string;
419
+ agentId: string;
420
+ scope: MemoryScope;
421
+ scopeRef: string;
422
+ /** Max items per structured memory type. Default: 20 */
423
+ maxPerType?: number;
424
+ /** Max entities to return. Default: 10 */
425
+ maxEntities?: number;
426
+ /** Max episodes to return. Default: 10 */
427
+ maxEpisodes?: number;
428
+ /** Activity window in ms. Default: 30 days */
429
+ activityWindowMs?: number;
430
+ }): Promise<ProfileSynthesis> {
431
+ const profileStart = Date.now();
432
+ const {
433
+ db,
434
+ prefix,
435
+ agentId,
436
+ scope,
437
+ scopeRef,
438
+ maxPerType = 20,
439
+ maxEntities = 10,
440
+ maxEpisodes = 10,
441
+ activityWindowMs = 30 * 24 * 60 * 60 * 1000,
442
+ } = params;
443
+
444
+ const scopeFilter = { agentId, scope, scopeRef };
445
+
446
+ // 1. Structured memory via $facet (single pass over collection)
447
+ const structuredResults = await structuredMemCollection(db, prefix)
448
+ .aggregate([
449
+ { $match: { ...scopeFilter, state: "active" } },
450
+ {
451
+ $facet: {
452
+ preferences: [
453
+ { $match: { type: "preference" } },
454
+ { $sort: { updatedAt: -1 } },
455
+ { $limit: maxPerType },
456
+ { $project: { key: 1, value: 1, salience: 1, updatedAt: 1 } },
457
+ ],
458
+ decisions: [
459
+ { $match: { type: "decision" } },
460
+ { $sort: { updatedAt: -1 } },
461
+ { $limit: maxPerType },
462
+ { $project: { key: 1, value: 1, salience: 1, updatedAt: 1 } },
463
+ ],
464
+ facts: [
465
+ { $match: { type: "fact" } },
466
+ { $sort: { updatedAt: -1 } },
467
+ { $limit: maxPerType },
468
+ { $project: { key: 1, value: 1, salience: 1, updatedAt: 1 } },
469
+ ],
470
+ todos: [
471
+ { $match: { type: "todo" } },
472
+ { $sort: { updatedAt: -1 } },
473
+ { $limit: maxPerType },
474
+ { $project: { key: 1, value: 1, salience: 1, updatedAt: 1 } },
475
+ ],
476
+ },
477
+ },
478
+ ])
479
+ .toArray();
480
+
481
+ const structured = structuredResults[0] ?? {
482
+ preferences: [],
483
+ decisions: [],
484
+ facts: [],
485
+ todos: [],
486
+ };
487
+
488
+ // 2. Top entities by relation count
489
+ const entityResults = await entitiesCollection(db, prefix)
490
+ .aggregate([
491
+ { $match: scopeFilter },
492
+ {
493
+ $lookup: {
494
+ from: `${prefix}relations`,
495
+ let: { eid: "$entityId" },
496
+ pipeline: [
497
+ {
498
+ $match: {
499
+ $expr: {
500
+ $or: [{ $eq: ["$fromEntityId", "$$eid"] }, { $eq: ["$toEntityId", "$$eid"] }],
501
+ },
502
+ ...scopeFilter,
503
+ },
504
+ },
505
+ { $count: "cnt" },
506
+ ],
507
+ as: "rels",
508
+ },
509
+ },
510
+ {
511
+ $addFields: {
512
+ relationCount: { $ifNull: [{ $arrayElemAt: ["$rels.cnt", 0] }, 0] },
513
+ },
514
+ },
515
+ { $sort: { relationCount: -1 } },
516
+ { $limit: maxEntities },
517
+ { $project: { name: 1, type: 1, relationCount: 1 } },
518
+ ])
519
+ .toArray();
520
+
521
+ // 3. Recent episodes
522
+ const episodeResults = await episodesCollection(db, prefix)
523
+ .find(scopeFilter)
524
+ .sort({ "timeRange.start": -1 })
525
+ .limit(maxEpisodes)
526
+ .project({ title: 1, summary: 1, type: 1, timeRange: 1 })
527
+ .toArray();
528
+
529
+ // 4. Activity patterns from events (last N days)
530
+ const activitySince = new Date(Date.now() - activityWindowMs);
531
+ const activityResults = await eventsCollection(db, prefix)
532
+ .aggregate([
533
+ { $match: { ...scopeFilter, timestamp: { $gte: activitySince } } },
534
+ {
535
+ $group: {
536
+ _id: "$role",
537
+ count: { $sum: 1 },
538
+ lastTs: { $max: "$timestamp" },
539
+ },
540
+ },
541
+ ])
542
+ .toArray();
543
+
544
+ const roleDistribution: Record<string, number> = {};
545
+ let totalEvents = 0;
546
+ let lastActive: Date | null = null;
547
+ for (const r of activityResults) {
548
+ roleDistribution[r._id as string] = r.count as number;
549
+ totalEvents += r.count as number;
550
+ const ts = r.lastTs as Date;
551
+ if (!lastActive || ts > lastActive) lastActive = ts;
552
+ }
553
+
554
+ const durationMs = Date.now() - profileStart;
555
+ emitTelemetry(db, prefix, {
556
+ meta: { agentId, operation: "profile-synthesis" },
557
+ durationMs,
558
+ ok: true,
559
+ resultCount: totalEvents,
560
+ });
561
+
562
+ return {
563
+ agentId,
564
+ scope,
565
+ scopeRef,
566
+ preferences: mapMemoryItems(structured.preferences),
567
+ decisions: mapMemoryItems(structured.decisions),
568
+ facts: mapMemoryItems(structured.facts),
569
+ todos: mapMemoryItems(structured.todos),
570
+ topEntities: entityResults.map((e) => ({
571
+ name: e.name as string,
572
+ type: e.type as string,
573
+ relationCount: e.relationCount as number,
574
+ })),
575
+ recentEpisodes: episodeResults.map((e) => ({
576
+ title: e.title as string,
577
+ summary: e.summary as string,
578
+ type: e.type as string,
579
+ timeRange: e.timeRange as { start: Date; end: Date },
580
+ })),
581
+ activityPatterns: { roleDistribution, totalEvents, lastActive },
582
+ synthesizedAt: new Date(),
583
+ };
584
+ }
585
+
586
+ function mapMemoryItems(items: Document[]): ProfileMemoryItem[] {
587
+ return items.map((i) => ({
588
+ key: i.key as string,
589
+ value: i.value as string,
590
+ salience: (i.salience as string) ?? "normal",
591
+ updatedAt: i.updatedAt as Date,
592
+ }));
593
+ }
594
+ ```
595
+
596
+ ### Task 2.3: Write tests for mongodb-profile.ts
597
+
598
+ **Files:**
599
+
600
+ - Create: `src/memory/mongodb-profile.test.ts`
601
+
602
+ **Tests (18+):**
603
+
604
+ 1. `synthesizeProfile returns empty profile when no data exists`
605
+ 2. `synthesizeProfile groups structured memory by type via $facet`
606
+ 3. `synthesizeProfile limits items per type to maxPerType`
607
+ 4. `synthesizeProfile sorts structured memory by updatedAt desc`
608
+ 5. `synthesizeProfile filters by state: active only`
609
+ 6. `synthesizeProfile returns top entities by relation count`
610
+ 7. `synthesizeProfile limits entities to maxEntities`
611
+ 8. `synthesizeProfile returns recent episodes sorted by timeRange.start desc`
612
+ 9. `synthesizeProfile limits episodes to maxEpisodes`
613
+ 10. `synthesizeProfile calculates activity patterns from events`
614
+ 11. `synthesizeProfile uses activityWindowMs for event filter`
615
+ 12. `synthesizeProfile returns null lastActive when no events`
616
+ 13. `synthesizeProfile filters all queries by agentId, scope, scopeRef`
617
+ 14. `synthesizeProfile emits profile-synthesis telemetry`
618
+ 15. `synthesizeProfile handles empty structured_mem collection`
619
+ 16. `synthesizeProfile handles empty entities collection`
620
+ 17. `synthesizeProfile handles empty episodes collection`
621
+ 18. `synthesizeProfile handles empty events collection`
622
+
623
+ **Mock pattern:** Mock all 5 collection accessors (structuredMemCollection, entitiesCollection, relationsCollection, episodesCollection, eventsCollection) with vi.fn() returning mock aggregate/find chains.
624
+
625
+ ```bash
626
+ pnpm test -- src/memory/mongodb-profile.test.ts
627
+ ```
628
+
629
+ ### Task 2.4: Export from barrel and verify build
630
+
631
+ **Files:**
632
+
633
+ - Modify: `src/memory/index.ts`
634
+
635
+ ```typescript
636
+ export {
637
+ synthesizeProfile,
638
+ type ProfileSynthesis,
639
+ type ProfileMemoryItem,
640
+ type ProfileEntity,
641
+ type ProfileEpisode,
642
+ type ActivityPatterns,
643
+ } from "./mongodb-profile.js";
644
+ ```
645
+
646
+ ```bash
647
+ pnpm build
648
+ ```
649
+
650
+ **Commit after Phase 2:**
651
+
652
+ ```
653
+ Feat: add profile synthesis from structured memory, entities, episodes, and events
654
+ ```
655
+
656
+ ---
657
+
658
+ ## Phase 3: Cross-Encoder Re-ranking
659
+
660
+ > **Exit Criteria:** `mongodb-reranker.ts` module with crossEncoderRerank() function. Calls Voyage rerank-2.5 API. Falls back to input order on failure. Wired into searchV2() after heuristic reranking. 15+ tests pass.
661
+
662
+ ### Task 3.1: Create mongodb-reranker.ts with types
663
+
664
+ **Files:**
665
+
666
+ - Create: `src/memory/mongodb-reranker.ts`
667
+
668
+ ```typescript
669
+ import { createSubsystemLogger } from "../logging/subsystem.js";
670
+ import type { Db } from "mongodb";
671
+ import { emitTelemetry } from "./mongodb-telemetry.js";
672
+ import type { MemorySearchResult } from "./types.js";
673
+
674
+ const log = createSubsystemLogger("memory:mongodb:reranker");
675
+
676
+ export type RerankConfig = {
677
+ enabled: boolean;
678
+ model: "rerank-2.5" | "rerank-2.5-lite";
679
+ topN: number;
680
+ minScore: number;
681
+ voyageApiKey: string;
682
+ /** Optional instruction prepended to query for rerank-2.5 instruction-following. */
683
+ instruction?: string;
684
+ };
685
+
686
+ export type RerankResult = {
687
+ results: MemorySearchResult[];
688
+ reranked: boolean;
689
+ latencyMs: number;
690
+ };
691
+ ```
692
+
693
+ ### Task 3.2: Implement crossEncoderRerank()
694
+
695
+ **Files:**
696
+
697
+ - Modify: `src/memory/mongodb-reranker.ts`
698
+
699
+ **Implementation:**
700
+
701
+ 1. If config.enabled is false or no results, return input unchanged
702
+ 2. Filter results above config.minScore
703
+ 3. Slice to config.topN candidates
704
+ 4. Extract snippet text from each candidate
705
+ 5. Call Voyage rerank API: POST https://api.voyageai.com/v1/rerank
706
+ 6. Map Voyage response scores back onto MemorySearchResult objects (update .score field)
707
+ 7. Re-sort by new score descending
708
+ 8. Append any results that were below minScore (not sent to reranker) at the end
709
+ 9. On ANY error: log.warn, return input unchanged (never crash search)
710
+ 10. Emit rerank telemetry
711
+
712
+ ```typescript
713
+ const VOYAGE_RERANK_URL = "https://api.voyageai.com/v1/rerank";
714
+
715
+ export async function crossEncoderRerank(params: {
716
+ db: Db;
717
+ prefix: string;
718
+ agentId: string;
719
+ query: string;
720
+ results: MemorySearchResult[];
721
+ config: RerankConfig;
722
+ }): Promise<RerankResult> {
723
+ const { db, prefix, agentId, query, results, config } = params;
724
+ const rerankStart = Date.now();
725
+
726
+ if (!config.enabled || results.length === 0 || !config.voyageApiKey) {
727
+ return { results, reranked: false, latencyMs: 0 };
728
+ }
729
+
730
+ // Split into candidates (above minScore) and remainder
731
+ const candidates = results.filter((r) => r.score >= config.minScore).slice(0, config.topN);
732
+ const remainder = results.filter((r) => r.score < config.minScore);
733
+
734
+ if (candidates.length <= 1) {
735
+ return { results, reranked: false, latencyMs: 0 };
736
+ }
737
+
738
+ try {
739
+ const documents = candidates.map((r) => r.snippet);
740
+ const response = await fetch(VOYAGE_RERANK_URL, {
741
+ method: "POST",
742
+ headers: {
743
+ "Content-Type": "application/json",
744
+ Authorization: `Bearer ${config.voyageApiKey}`,
745
+ },
746
+ body: JSON.stringify({
747
+ model: config.model,
748
+ // rerank-2.5 supports instruction-following: prepend instruction to query for 8-11% accuracy boost
749
+ // Example instruction: "This is agent conversation memory. Prioritize recent and contextually relevant results."
750
+ query: config.instruction ? `${config.instruction}\n${query}` : query,
751
+ documents,
752
+ top_k: candidates.length,
753
+ }),
754
+ });
755
+
756
+ if (!response.ok) {
757
+ log.warn("rerank API returned non-OK status", { status: response.status });
758
+ return { results, reranked: false, latencyMs: Date.now() - rerankStart };
759
+ }
760
+
761
+ const body = (await response.json()) as {
762
+ data: Array<{ index: number; relevance_score: number }>;
763
+ };
764
+
765
+ if (!body.data || !Array.isArray(body.data)) {
766
+ log.warn("rerank API returned unexpected response shape");
767
+ return { results, reranked: false, latencyMs: Date.now() - rerankStart };
768
+ }
769
+
770
+ // Map scores back onto candidate results (clamp to [0,1] — docs don't guarantee range)
771
+ const reranked = body.data
772
+ .sort((a, b) => b.relevance_score - a.relevance_score)
773
+ .map((r) => {
774
+ const original = candidates[r.index];
775
+ return { ...original, score: Math.min(1, Math.max(0, r.relevance_score)) };
776
+ });
777
+
778
+ const latencyMs = Date.now() - rerankStart;
779
+ emitTelemetry(db, prefix, {
780
+ meta: { agentId, operation: "rerank" },
781
+ durationMs: latencyMs,
782
+ ok: true,
783
+ resultCount: reranked.length,
784
+ rerankModel: config.model,
785
+ rerankLatencyMs: latencyMs,
786
+ });
787
+
788
+ return {
789
+ results: [...reranked, ...remainder],
790
+ reranked: true,
791
+ latencyMs,
792
+ };
793
+ } catch (err) {
794
+ log.warn("rerank failed, falling back to input order", { error: err });
795
+ return { results, reranked: false, latencyMs: Date.now() - rerankStart };
796
+ }
797
+ }
798
+ ```
799
+
800
+ ### Task 3.3: Add rerankConfig + queryRewriteConfig to searchV2 context and V2SearchMetadata
801
+
802
+ **Files:**
803
+
804
+ - Modify: `src/memory/mongodb-manager.ts`
805
+
806
+ **CRITICAL: searchV2() is a standalone function with NO access to resolvedConfig.** Config must be passed via the existing `context.searchOptions` parameter.
807
+
808
+ **Step 1:** Add to V2SearchMetadata type (line ~2467):
809
+
810
+ ```typescript
811
+ export type V2SearchMetadata = {
812
+ plan: RetrievalPlan;
813
+ pathsExecuted: RetrievalPath[];
814
+ resultsByPath: Record<string, number>;
815
+ reranked?: boolean; // NEW
816
+ queryRewritten?: boolean; // NEW
817
+ };
818
+ ```
819
+
820
+ **Step 2:** Add to searchV2's `context.searchOptions` type:
821
+
822
+ ```typescript
823
+ // Inside the context parameter of searchV2():
824
+ searchOptions?: {
825
+ // ... existing fields (numCandidates, capabilities, fusionMethod, etc.) ...
826
+ rerankConfig?: import("./mongodb-reranker.js").RerankConfig;
827
+ queryRewriteConfig?: import("./mongodb-query-rewriter.js").QueryRewriteConfig;
828
+ };
829
+ ```
830
+
831
+ **Step 3:** Pass config from the caller in MongoDBMemoryManager.search() (line ~770):
832
+
833
+ ```typescript
834
+ // In MongoDBMemoryManager.search(), where context is constructed:
835
+ const v2 = await searchV2(this.db, this.prefix, cleaned, this.agentId, {
836
+ // ... existing context fields ...
837
+ searchOptions: {
838
+ // ... existing searchOptions ...
839
+ rerankConfig: mongoCfg.reranking,
840
+ queryRewriteConfig: mongoCfg.queryRewriting,
841
+ },
842
+ });
843
+ ```
844
+
845
+ ### Task 3.4: Wire crossEncoderRerank into searchV2()
846
+
847
+ **Files:**
848
+
849
+ - Modify: `src/memory/mongodb-manager.ts`
850
+
851
+ **Hook location:** In searchV2(), AFTER `const reranked = rerankResults(deduped, query)` (line ~2966) and BEFORE the return.
852
+
853
+ ```typescript
854
+ import { crossEncoderRerank } from "./mongodb-reranker.js";
855
+
856
+ // After heuristic reranking, before final slice:
857
+ const rerankCfg = context.searchOptions?.rerankConfig;
858
+ let finalResults = reranked;
859
+ let wasReranked = false;
860
+ if (rerankCfg?.enabled) {
861
+ const rerankResult = await crossEncoderRerank({
862
+ db,
863
+ prefix,
864
+ agentId,
865
+ query,
866
+ results: reranked,
867
+ config: rerankCfg,
868
+ });
869
+ if (rerankResult.reranked) {
870
+ finalResults = rerankResult.results;
871
+ wasReranked = true;
872
+ }
873
+ }
874
+ return {
875
+ results: finalResults.slice(0, maxResults),
876
+ metadata: { ...metadata, reranked: wasReranked },
877
+ };
878
+ ```
879
+
880
+ ### Task 3.4: Write tests for mongodb-reranker.ts
881
+
882
+ **Files:**
883
+
884
+ - Create: `src/memory/mongodb-reranker.test.ts`
885
+
886
+ **Tests (15+):**
887
+
888
+ 1. `crossEncoderRerank returns input unchanged when disabled`
889
+ 2. `crossEncoderRerank returns input unchanged when no results`
890
+ 3. `crossEncoderRerank returns input unchanged when no API key`
891
+ 4. `crossEncoderRerank returns input unchanged when single result`
892
+ 5. `crossEncoderRerank calls Voyage API with correct payload`
893
+ 6. `crossEncoderRerank maps scores back onto correct results`
894
+ 7. `crossEncoderRerank re-sorts by relevance_score descending`
895
+ 8. `crossEncoderRerank appends below-minScore results at end`
896
+ 9. `crossEncoderRerank slices candidates to topN`
897
+ 10. `crossEncoderRerank falls back on API error (non-OK status)`
898
+ 11. `crossEncoderRerank falls back on network error`
899
+ 12. `crossEncoderRerank falls back on JSON parse error`
900
+ 13. `crossEncoderRerank emits rerank telemetry on success`
901
+ 14. `crossEncoderRerank reports reranked:false on fallback`
902
+ 15. `crossEncoderRerank uses correct model from config`
903
+
904
+ **Mock pattern:** Mock global fetch with vi.fn(). Mock emitTelemetry.
905
+
906
+ ```bash
907
+ pnpm test -- src/memory/mongodb-reranker.test.ts
908
+ ```
909
+
910
+ ### Task 3.5: Export from barrel and verify build
911
+
912
+ **Files:**
913
+
914
+ - Modify: `src/memory/index.ts`
915
+
916
+ ```typescript
917
+ export { crossEncoderRerank, type RerankConfig, type RerankResult } from "./mongodb-reranker.js";
918
+ ```
919
+
920
+ ```bash
921
+ pnpm build
922
+ ```
923
+
924
+ **Commit after Phase 3:**
925
+
926
+ ```
927
+ Feat: add cross-encoder re-ranking via Voyage rerank-2.5 with fallback
928
+ ```
929
+
930
+ ---
931
+
932
+ ## Phase 4: Query Rewriting
933
+
934
+ > **Exit Criteria:** `mongodb-query-rewriter.ts` module with rewriteQuery() function. Synonym-expansion tier is deterministic (zero latency). Wired into searchV2() AFTER planRetrieval() but BEFORE path execution. Cache key uses original query. 16+ tests pass.
935
+
936
+ ### Task 4.1: Create mongodb-query-rewriter.ts with types and synonym map
937
+
938
+ **Files:**
939
+
940
+ - Create: `src/memory/mongodb-query-rewriter.ts`
941
+
942
+ ```typescript
943
+ import { createSubsystemLogger } from "../logging/subsystem.js";
944
+ import type { Db } from "mongodb";
945
+ import { emitTelemetry } from "./mongodb-telemetry.js";
946
+
947
+ const log = createSubsystemLogger("memory:mongodb:query-rewriter");
948
+
949
+ export type QueryRewriteConfig = {
950
+ enabled: boolean;
951
+ method: "synonym-expansion" | "llm" | "hyde";
952
+ maxTokens: number;
953
+ };
954
+
955
+ export type QueryRewriteResult = {
956
+ originalQuery: string;
957
+ rewrittenQuery: string;
958
+ rewritten: boolean;
959
+ method: string;
960
+ };
961
+
962
+ /**
963
+ * Domain-specific synonym map for agent memory queries.
964
+ * Bidirectional: each key expands to its values.
965
+ */
966
+ const SYNONYM_MAP: Record<string, string[]> = {
967
+ auth: ["authentication", "login", "oauth"],
968
+ db: ["database", "mongodb", "collection"],
969
+ api: ["endpoint", "route", "rest"],
970
+ ui: ["interface", "frontend", "component"],
971
+ bug: ["issue", "error", "defect"],
972
+ perf: ["performance", "latency", "speed"],
973
+ config: ["configuration", "settings", "options"],
974
+ deps: ["dependencies", "packages", "modules"],
975
+ deploy: ["deployment", "release", "publish"],
976
+ docs: ["documentation", "readme", "guide"],
977
+ test: ["testing", "tests", "spec"],
978
+ refactor: ["restructure", "reorganize", "cleanup"],
979
+ };
980
+
981
+ /** Abbreviation expansions (unidirectional: abbreviation -> full form) */
982
+ const ABBREVIATION_MAP: Record<string, string> = {
983
+ ts: "typescript",
984
+ js: "javascript",
985
+ py: "python",
986
+ env: "environment",
987
+ var: "variable",
988
+ fn: "function",
989
+ cb: "callback",
990
+ req: "request",
991
+ res: "response",
992
+ err: "error",
993
+ msg: "message",
994
+ ctx: "context",
995
+ impl: "implementation",
996
+ repo: "repository",
997
+ };
998
+ ```
999
+
1000
+ ### Task 4.2: Implement rewriteQuery() with synonym-expansion tier
1001
+
1002
+ **Files:**
1003
+
1004
+ - Modify: `src/memory/mongodb-query-rewriter.ts`
1005
+
1006
+ ```typescript
1007
+ /**
1008
+ * Rewrite a query for improved vector search recall.
1009
+ *
1010
+ * CRITICAL: The retrieval planner must ALWAYS see the ORIGINAL query.
1011
+ * This function is called AFTER planRetrieval() and BEFORE search execution.
1012
+ * The cache key must also use the ORIGINAL query.
1013
+ *
1014
+ * Tier 1 (synonym-expansion): Deterministic, zero latency.
1015
+ * - Expand known abbreviations
1016
+ * - Add synonyms for recognized terms
1017
+ * - Preserve original terms (expansion, not replacement)
1018
+ */
1019
+ export async function rewriteQuery(params: {
1020
+ db: Db;
1021
+ prefix: string;
1022
+ agentId: string;
1023
+ query: string;
1024
+ config: QueryRewriteConfig;
1025
+ }): Promise<QueryRewriteResult> {
1026
+ const { db, prefix, agentId, query, config } = params;
1027
+ const rewriteStart = Date.now();
1028
+
1029
+ if (!config.enabled || !query.trim()) {
1030
+ return { originalQuery: query, rewrittenQuery: query, rewritten: false, method: "none" };
1031
+ }
1032
+
1033
+ let rewritten: string;
1034
+ let method: string;
1035
+
1036
+ switch (config.method) {
1037
+ case "synonym-expansion":
1038
+ rewritten = expandSynonyms(query);
1039
+ method = "synonym-expansion";
1040
+ break;
1041
+ case "llm":
1042
+ case "hyde":
1043
+ // LLM and HyDE tiers are future work — fall back to synonym expansion
1044
+ log.warn(
1045
+ `query rewrite method "${config.method}" not yet implemented, falling back to synonym-expansion`,
1046
+ );
1047
+ rewritten = expandSynonyms(query);
1048
+ method = "synonym-expansion-fallback";
1049
+ break;
1050
+ default:
1051
+ rewritten = query;
1052
+ method = "none";
1053
+ }
1054
+
1055
+ const wasRewritten = rewritten !== query;
1056
+ if (wasRewritten) {
1057
+ // Truncate to maxTokens (rough approximation: 1 token ≈ 4 chars)
1058
+ const maxChars = config.maxTokens * 4;
1059
+ if (rewritten.length > maxChars) {
1060
+ rewritten = rewritten.slice(0, maxChars).trimEnd();
1061
+ }
1062
+ }
1063
+
1064
+ emitTelemetry(db, prefix, {
1065
+ meta: { agentId, operation: "query-rewrite" },
1066
+ durationMs: Date.now() - rewriteStart,
1067
+ ok: true,
1068
+ queryRewritten: wasRewritten,
1069
+ rewriteMethod: method,
1070
+ });
1071
+
1072
+ return { originalQuery: query, rewrittenQuery: rewritten, rewritten: wasRewritten, method };
1073
+ }
1074
+
1075
+ /**
1076
+ * Deterministic synonym expansion.
1077
+ * For each word in the query:
1078
+ * 1. Check if it's an abbreviation → add full form
1079
+ * 2. Check if it matches a synonym group → add all synonyms
1080
+ * Original words are always preserved.
1081
+ */
1082
+ export function expandSynonyms(query: string): string {
1083
+ const words = query.toLowerCase().split(/\s+/).filter(Boolean);
1084
+ const expanded = new Set(words);
1085
+
1086
+ for (const word of words) {
1087
+ // Abbreviation expansion
1088
+ if (ABBREVIATION_MAP[word]) {
1089
+ expanded.add(ABBREVIATION_MAP[word]);
1090
+ }
1091
+ // Synonym expansion
1092
+ if (SYNONYM_MAP[word]) {
1093
+ for (const syn of SYNONYM_MAP[word]) {
1094
+ expanded.add(syn);
1095
+ }
1096
+ }
1097
+ }
1098
+
1099
+ return [...expanded].join(" ");
1100
+ }
1101
+ ```
1102
+
1103
+ ### Task 4.3: Wire rewriteQuery into searchV2()
1104
+
1105
+ **Files:**
1106
+
1107
+ - Modify: `src/memory/mongodb-manager.ts`
1108
+
1109
+ **Hook location:** In searchV2(), AFTER `const plan = planRetrieval(query, ...)` (line ~2625) and BEFORE the path execution `for` loop (line ~2669).
1110
+
1111
+ **Note:** searchV2 receives queryRewriteConfig via `context.searchOptions.queryRewriteConfig` (added in Phase 3 Task 3.3).
1112
+
1113
+ ```typescript
1114
+ import { rewriteQuery } from "./mongodb-query-rewriter.js";
1115
+
1116
+ // After planRetrieval (planner sees ORIGINAL query):
1117
+ const plan = planRetrieval(query, { entities: knownEntityNames });
1118
+
1119
+ // Rewrite query for search execution (NOT for planner or cache key):
1120
+ const qrConfig = context.searchOptions?.queryRewriteConfig;
1121
+ let searchQuery = query;
1122
+ let wasRewritten = false;
1123
+ if (qrConfig?.enabled) {
1124
+ const rewriteResult = await rewriteQuery({
1125
+ db,
1126
+ prefix,
1127
+ agentId,
1128
+ query,
1129
+ config: qrConfig,
1130
+ });
1131
+ if (rewriteResult.rewritten) {
1132
+ searchQuery = rewriteResult.rewrittenQuery;
1133
+ wasRewritten = true;
1134
+ }
1135
+ }
1136
+ ```
1137
+
1138
+ **CRITICAL: Two variables, two purposes:**
1139
+
1140
+ - `query` (original) → used for: `planRetrieval()` (already called above), `checkCache()`, `writeCache()`
1141
+ - `searchQuery` (rewritten) → used for: all path search calls
1142
+
1143
+ **Step 2: Replace `query` with `searchQuery` in EVERY path execution call (6 locations):**
1144
+
1145
+ - Line ~2677: `searchStructuredMemory(db, prefix, searchQuery, ...)` (active-critical path)
1146
+ - Line ~2697: `searchStructuredMemory(db, prefix, searchQuery, ...)` (structured path)
1147
+ - Line ~2790: `searchEpisodes(db, prefix, searchQuery, ...)` (episodic path)
1148
+ - Line ~2835: `mongoSearch({ ..., query: searchQuery, ... })` (hybrid path)
1149
+ - Line ~2879: `searchKB({ ..., query: searchQuery, ... })` (kb path)
1150
+ - Line ~2948: `mongoSearch({ ..., query: searchQuery, ... })` (hybrid BACKSTOP recursive call — don't miss this one!)
1151
+
1152
+ **Step 3: Add to metadata return:**
1153
+
1154
+ ```typescript
1155
+ metadata: { ...metadata, reranked: wasReranked, queryRewritten: wasRewritten },
1156
+ ```
1157
+
1158
+ ### Task 4.4: Write tests for mongodb-query-rewriter.ts
1159
+
1160
+ **Files:**
1161
+
1162
+ - Create: `src/memory/mongodb-query-rewriter.test.ts`
1163
+
1164
+ **Tests (16+):**
1165
+
1166
+ 1. `rewriteQuery returns original when disabled`
1167
+ 2. `rewriteQuery returns original for empty query`
1168
+ 3. `expandSynonyms expands known abbreviations`
1169
+ 4. `expandSynonyms adds synonyms for recognized terms`
1170
+ 5. `expandSynonyms preserves original words`
1171
+ 6. `expandSynonyms handles multiple words`
1172
+ 7. `expandSynonyms is case-insensitive`
1173
+ 8. `expandSynonyms returns unchanged query when no matches`
1174
+ 9. `expandSynonyms deduplicates expanded terms`
1175
+ 10. `rewriteQuery truncates to maxTokens`
1176
+ 11. `rewriteQuery emits query-rewrite telemetry`
1177
+ 12. `rewriteQuery reports rewritten:false when no expansion`
1178
+ 13. `rewriteQuery falls back to synonym-expansion for llm method`
1179
+ 14. `rewriteQuery falls back to synonym-expansion for hyde method`
1180
+ 15. `rewriteQuery handles single-word query`
1181
+ 16. `rewriteQuery handles query with all known abbreviations`
1182
+
1183
+ ```bash
1184
+ pnpm test -- src/memory/mongodb-query-rewriter.test.ts
1185
+ ```
1186
+
1187
+ ### Task 4.5: Export from barrel and verify build
1188
+
1189
+ **Files:**
1190
+
1191
+ - Modify: `src/memory/index.ts`
1192
+
1193
+ ```typescript
1194
+ export {
1195
+ rewriteQuery,
1196
+ expandSynonyms,
1197
+ type QueryRewriteConfig,
1198
+ type QueryRewriteResult,
1199
+ } from "./mongodb-query-rewriter.js";
1200
+ ```
1201
+
1202
+ ```bash
1203
+ pnpm build
1204
+ ```
1205
+
1206
+ **Commit after Phase 4:**
1207
+
1208
+ ```
1209
+ Feat: add query rewriting with synonym expansion for improved search recall
1210
+ ```
1211
+
1212
+ ---
1213
+
1214
+ ## Phase 5: LLM Entity Extraction
1215
+
1216
+ > **Exit Criteria:** `mongodb-entity-extractor.ts` module with EntityExtractor interface, RegexEntityExtractor (extracted from mongodb-graph.ts), and LLMEntityExtractor stub. extractAndUpsertEntities() accepts optional extractor param. 14+ tests pass.
1217
+
1218
+ ### Task 5.1: Create mongodb-entity-extractor.ts with interface and regex implementation
1219
+
1220
+ **Files:**
1221
+
1222
+ - Create: `src/memory/mongodb-entity-extractor.ts`
1223
+
1224
+ **Implementation:**
1225
+
1226
+ 1. Define `EntityExtractor` interface with `extract(content, context?)` method
1227
+ 2. Define `EntityExtractionContext` type (agentId, scope, scopeRef, existingEntities?)
1228
+ 3. Define `ExtractedEntity` type (matches existing shape in mongodb-graph.ts)
1229
+ 4. Extract `RegexEntityExtractor` from the existing regex logic in mongodb-graph.ts (lines 867-871: MENTION_REGEX, TAG_REGEX, URL_REGEX, FILE_PATH_REGEX, QUOTED_NAME_REGEX)
1230
+ 5. Create `LLMEntityExtractor` stub that accepts a callable LLM function, with timeout and fallback to regex
1231
+
1232
+ ```typescript
1233
+ import { createSubsystemLogger } from "../logging/subsystem.js";
1234
+
1235
+ const log = createSubsystemLogger("memory:mongodb:entity-extractor");
1236
+
1237
+ // Import the canonical EntityType from mongodb-graph.ts — do NOT redefine it
1238
+ import type { EntityType } from "./mongodb-graph.js";
1239
+
1240
+ // Extended types for LLM extraction (beyond the base EntityType union)
1241
+ // These are accepted by MongoDB since ENTITIES_SCHEMA validates type as bsonType:"string" (not enum)
1242
+ // The TypeScript EntityType union in mongodb-graph.ts should be expanded to include these
1243
+ export type ExtendedEntityType = EntityType | "location" | "system" | "concept";
1244
+
1245
+ export type ExtractedEntity = {
1246
+ name: string;
1247
+ type: string; // string (not EntityType) to allow LLM-extracted extended types
1248
+ confidence?: number;
1249
+ extractionMethod: "regex" | "llm";
1250
+ };
1251
+
1252
+ export type EntityExtractionContext = {
1253
+ agentId: string;
1254
+ scope: string;
1255
+ scopeRef: string;
1256
+ existingEntityNames?: string[];
1257
+ };
1258
+
1259
+ export interface EntityExtractor {
1260
+ extract(content: string, context?: EntityExtractionContext): Promise<ExtractedEntity[]>;
1261
+ }
1262
+
1263
+ // Regex patterns (extracted from mongodb-graph.ts)
1264
+ const MENTION_REGEX = /@(\w{3,})/g;
1265
+ const TAG_REGEX = /#(\w{3,})/g;
1266
+ const URL_REGEX = /https?:\/\/[^\s)]+/g; // Excludes ) — matches actual mongodb-graph.ts
1267
+ const FILE_PATH_REGEX = /(?:^|\s)((?:[\w.-]+\/)+[\w.-]+\.\w+)/g; // + quantifier — matches actual
1268
+ const QUOTED_NAME_REGEX = /"([^"]{3,})"/g;
1269
+
1270
+ // STOP_WORDS: MUST be copied VERBATIM from mongodb-graph.ts (lines 803-864) at build time.
1271
+ // DO NOT hardcode a different list here — the original source is the single source of truth.
1272
+ // At implementation time: read the exact STOP_WORDS set from mongodb-graph.ts and paste it here.
1273
+ // This ensures RegexEntityExtractor filters identically to the original inline extraction.
1274
+ import { STOP_WORDS } from "./mongodb-graph.js";
1275
+ // NOTE: STOP_WORDS must be exported from mongodb-graph.ts first (it's currently module-private).
1276
+ // Add `export` to the existing `const STOP_WORDS = new Set([...])` in mongodb-graph.ts.
1277
+
1278
+ export class RegexEntityExtractor implements EntityExtractor {
1279
+ async extract(content: string): Promise<ExtractedEntity[]> {
1280
+ const entities: ExtractedEntity[] = [];
1281
+ const seen = new Set<string>();
1282
+
1283
+ const addEntity = (name: string, type: string) => {
1284
+ // Apply stop-word filter for non-URL/non-path entities (matches original behavior)
1285
+ if (type !== "document" && STOP_WORDS.has(name.toLowerCase())) return;
1286
+ const key = `${name.toLowerCase()}:${type}`;
1287
+ if (!seen.has(key)) {
1288
+ seen.add(key);
1289
+ entities.push({ name, type, confidence: 0.5, extractionMethod: "regex" });
1290
+ }
1291
+ };
1292
+
1293
+ for (const match of content.matchAll(MENTION_REGEX)) {
1294
+ addEntity(match[1], "person");
1295
+ }
1296
+ for (const match of content.matchAll(TAG_REGEX)) {
1297
+ addEntity(match[1], "topic");
1298
+ }
1299
+ for (const match of content.matchAll(URL_REGEX)) {
1300
+ addEntity(match[0], "document");
1301
+ }
1302
+ for (const match of content.matchAll(FILE_PATH_REGEX)) {
1303
+ addEntity(match[1], "document");
1304
+ }
1305
+ for (const match of content.matchAll(QUOTED_NAME_REGEX)) {
1306
+ addEntity(match[1], "person");
1307
+ }
1308
+
1309
+ return entities;
1310
+ }
1311
+ }
1312
+
1313
+ export type LLMFunction = (prompt: string) => Promise<string>;
1314
+
1315
+ export class LLMEntityExtractor implements EntityExtractor {
1316
+ private llmFn: LLMFunction;
1317
+ private timeoutMs: number;
1318
+ private fallback: RegexEntityExtractor;
1319
+
1320
+ constructor(llmFn: LLMFunction, timeoutMs = 5000) {
1321
+ this.llmFn = llmFn;
1322
+ this.timeoutMs = timeoutMs;
1323
+ this.fallback = new RegexEntityExtractor();
1324
+ }
1325
+
1326
+ async extract(content: string, context?: EntityExtractionContext): Promise<ExtractedEntity[]> {
1327
+ try {
1328
+ const result = await Promise.race([
1329
+ this.extractWithLLM(content, context),
1330
+ new Promise<never>((_, reject) =>
1331
+ setTimeout(() => reject(new Error("LLM extraction timeout")), this.timeoutMs),
1332
+ ),
1333
+ ]);
1334
+ return result;
1335
+ } catch (err) {
1336
+ log.warn("LLM entity extraction failed, falling back to regex", { error: err });
1337
+ return this.fallback.extract(content, context);
1338
+ }
1339
+ }
1340
+
1341
+ private async extractWithLLM(
1342
+ content: string,
1343
+ context?: EntityExtractionContext,
1344
+ ): Promise<ExtractedEntity[]> {
1345
+ const prompt = buildExtractionPrompt(content, context);
1346
+ const response = await this.llmFn(prompt);
1347
+ return parseExtractionResponse(response);
1348
+ }
1349
+ }
1350
+
1351
+ export function buildExtractionPrompt(content: string, context?: EntityExtractionContext): string {
1352
+ const existingHint = context?.existingEntityNames?.length
1353
+ ? `\nKnown entities in this context: ${context.existingEntityNames.join(", ")}`
1354
+ : "";
1355
+
1356
+ return `Extract named entities from the following text. Return a JSON array of objects with "name", "type", and "confidence" fields.
1357
+
1358
+ Valid types: person, org, project, topic, feature, issue, document, location, system, concept
1359
+
1360
+ Rules:
1361
+ - Only extract entities explicitly mentioned in the text
1362
+ - Do not invent entities that are not present
1363
+ - Confidence should be 0.0-1.0 based on how certain you are
1364
+ - Normalize names (capitalize properly, no leading/trailing whitespace)
1365
+ ${existingHint}
1366
+
1367
+ Text:
1368
+ ${content}
1369
+
1370
+ Response (JSON array only):`;
1371
+ }
1372
+
1373
+ export function parseExtractionResponse(response: string): ExtractedEntity[] {
1374
+ try {
1375
+ // Find JSON array in response (may be wrapped in markdown code block)
1376
+ const jsonMatch = response.match(/\[[\s\S]*\]/);
1377
+ if (!jsonMatch) return [];
1378
+
1379
+ const parsed = JSON.parse(jsonMatch[0]) as Array<{
1380
+ name?: string;
1381
+ type?: string;
1382
+ confidence?: number;
1383
+ }>;
1384
+
1385
+ if (!Array.isArray(parsed)) return [];
1386
+
1387
+ return parsed
1388
+ .filter((e) => e.name && typeof e.name === "string" && e.name.trim().length >= 2)
1389
+ .map((e) => ({
1390
+ name: e.name!.trim(),
1391
+ type: (e.type as EntityType) ?? "custom",
1392
+ confidence: typeof e.confidence === "number" ? Math.min(1, Math.max(0, e.confidence)) : 0.7,
1393
+ extractionMethod: "llm" as const,
1394
+ }));
1395
+ } catch {
1396
+ log.warn("failed to parse LLM extraction response");
1397
+ return [];
1398
+ }
1399
+ }
1400
+ ```
1401
+
1402
+ ### Task 5.2: Modify extractAndUpsertEntities() to accept optional extractor
1403
+
1404
+ **Files:**
1405
+
1406
+ - Modify: `src/memory/mongodb-graph.ts`
1407
+
1408
+ **CRITICAL: The extractor returns `{name, type}` but the existing code needs `{entityId, name, type}`.** The `entityId` is computed by `makeEntityId()` INSIDE `extractAndUpsertEntities()`, NOT by the extractor. The bridge pattern:
1409
+
1410
+ 1. Extractor returns: `{ name, type, confidence?, extractionMethod }`
1411
+ 2. `extractAndUpsertEntities()` calls extractor, then computes entityId for each result via existing `makeEntityId()` logic
1412
+ 3. Everything downstream (upsertEntity, upsertRelation, upsertEntityLink) is unchanged
1413
+
1414
+ **Change the function signature:**
1415
+
1416
+ ```typescript
1417
+ import {
1418
+ type EntityExtractor,
1419
+ RegexEntityExtractor,
1420
+ type ExtractedEntity as ExtractorResult,
1421
+ } from "./mongodb-entity-extractor.js";
1422
+
1423
+ const defaultExtractor = new RegexEntityExtractor();
1424
+
1425
+ export async function extractAndUpsertEntities(params: {
1426
+ db: Db;
1427
+ prefix: string;
1428
+ agentId: string;
1429
+ eventContent: string;
1430
+ scope: MemoryScope;
1431
+ scopeRef?: string;
1432
+ sourceEventId?: string;
1433
+ extractor?: EntityExtractor; // NEW optional param
1434
+ }): Promise<{ entities: ExtractedEntity[]; relationsCreated: number }> {
1435
+ const extractor = params.extractor ?? defaultExtractor;
1436
+
1437
+ // Replace the existing inline regex extraction with:
1438
+ const extractorResults = await extractor.extract(params.eventContent);
1439
+
1440
+ // Bridge: compute entityId for each extracted entity (existing makeEntityId logic)
1441
+ const entities: ExtractedEntity[] = extractorResults.map((r) => ({
1442
+ entityId: makeEntityId(r.name, r.type, params.agentId, params.scope, params.scopeRef ?? ""),
1443
+ name: r.name,
1444
+ type: r.type as EntityType,
1445
+ }));
1446
+
1447
+ // ... rest of the function unchanged (upsertEntity, upsertRelation, upsertEntityLink) ...
1448
+ }
1449
+ ```
1450
+
1451
+ **Note:** Remove the existing inline regex patterns (MENTION_REGEX, TAG_REGEX, URL_REGEX, FILE_PATH_REGEX, QUOTED_NAME_REGEX) from mongodb-graph.ts — they now live in RegexEntityExtractor. Keep `makeEntityId()` in mongodb-graph.ts since it's used for the bridge.
1452
+
1453
+ **IMPORTANT: Use the EXACT regex from mongodb-graph.ts in RegexEntityExtractor:**
1454
+
1455
+ ```typescript
1456
+ // Copy these EXACTLY from mongodb-graph.ts lines 867-871:
1457
+ const MENTION_REGEX = /@(\w{3,})/g;
1458
+ const TAG_REGEX = /#(\w{3,})/g;
1459
+ const URL_REGEX = /https?:\/\/[^\s)]+/g; // Note: excludes ) — matches actual code
1460
+ const FILE_PATH_REGEX = /(?:^|\s)((?:[\w.-]+\/)+[\w.-]+\.\w+)/g;
1461
+ const QUOTED_NAME_REGEX = /"([^"]{3,})"/g;
1462
+ ```
1463
+
1464
+ ### Task 5.3: Wire extractor into writeEventAndProject()
1465
+
1466
+ **Files:**
1467
+
1468
+ - Modify: `src/memory/mongodb-manager.ts`
1469
+
1470
+ **CRITICAL: writeEventAndProject() is a standalone function with NO access to resolvedConfig.** The extractor instance must be passed as a new optional parameter.
1471
+
1472
+ **Step 1:** Add optional `extractor` parameter to writeEventAndProject:
1473
+
1474
+ ```typescript
1475
+ export async function writeEventAndProject(
1476
+ db: Db, prefix: string, event: CanonicalEventInput,
1477
+ options?: { extractor?: EntityExtractor }, // NEW
1478
+ ): Promise<...> {
1479
+ ```
1480
+
1481
+ **Step 2:** Pass it through to extractAndUpsertEntities:
1482
+
1483
+ ```typescript
1484
+ await extractAndUpsertEntities({
1485
+ db, prefix,
1486
+ agentId: event.agentId,
1487
+ eventContent: event.body,
1488
+ scope: event.scope as MemoryScope,
1489
+ scopeRef: written.scopeRef,
1490
+ sourceEventId: written.eventId,
1491
+ extractor: options?.extractor, // NEW — passes through, defaults to regex inside
1492
+ }).catch((projErr) => { ... });
1493
+ ```
1494
+
1495
+ **Step 3:** The MongoDBMemoryManager class creates the extractor once during initialization and passes it through calls:
1496
+
1497
+ ```typescript
1498
+ // In MongoDBMemoryManager constructor or create():
1499
+ import { RegexEntityExtractor, LLMEntityExtractor } from "./mongodb-entity-extractor.js";
1500
+
1501
+ // NOTE: LLMEntityExtractor requires an LLMFunction (prompt: string) => Promise<string>.
1502
+ // For now, the LLM path is a stub — the manager does not currently have an LLM callable.
1503
+ // When method="llm" is configured but no LLM function is available, fall back to regex.
1504
+ // The LLM function injection point will be wired when the agent runtime's LLM interface
1505
+ // is formalized (deferred — regex is the working default).
1506
+ const extractorInstance =
1507
+ mongoCfg.graph.entityExtraction.method === "llm"
1508
+ ? new RegexEntityExtractor() // TODO: wire LLM function from agent runtime when available
1509
+ : new RegexEntityExtractor();
1510
+
1511
+ // In any call to writeEventAndProject:
1512
+ await writeEventAndProject(this.db, this.prefix, event, {
1513
+ extractor: this.extractorInstance,
1514
+ });
1515
+ ```
1516
+
1517
+ ### Task 5.4: Write tests for mongodb-entity-extractor.ts
1518
+
1519
+ **Files:**
1520
+
1521
+ - Create: `src/memory/mongodb-entity-extractor.test.ts`
1522
+
1523
+ **Tests (14+):**
1524
+
1525
+ 1. `RegexEntityExtractor extracts @mentions as person`
1526
+ 2. `RegexEntityExtractor extracts #tags as topic`
1527
+ 3. `RegexEntityExtractor extracts URLs as document`
1528
+ 4. `RegexEntityExtractor extracts file paths as document`
1529
+ 5. `RegexEntityExtractor extracts quoted names as person`
1530
+ 6. `RegexEntityExtractor deduplicates entities`
1531
+ 7. `RegexEntityExtractor returns empty array for no matches`
1532
+ 8. `RegexEntityExtractor sets extractionMethod to regex`
1533
+ 9. `LLMEntityExtractor calls LLM function with extraction prompt`
1534
+ 10. `LLMEntityExtractor parses JSON array response`
1535
+ 11. `LLMEntityExtractor falls back to regex on LLM error`
1536
+ 12. `LLMEntityExtractor falls back to regex on timeout`
1537
+ 13. `LLMEntityExtractor handles markdown-wrapped JSON`
1538
+ 14. `parseExtractionResponse filters invalid entries`
1539
+ 15. `parseExtractionResponse clamps confidence to [0,1]`
1540
+ 16. `buildExtractionPrompt includes existing entity names`
1541
+
1542
+ ```bash
1543
+ pnpm test -- src/memory/mongodb-entity-extractor.test.ts
1544
+ ```
1545
+
1546
+ ### Task 5.5: Export from barrel and verify build
1547
+
1548
+ **Files:**
1549
+
1550
+ - Modify: `src/memory/index.ts`
1551
+
1552
+ ```typescript
1553
+ export {
1554
+ type EntityExtractor,
1555
+ type ExtractedEntity as ExtractedEntityV2,
1556
+ type EntityExtractionContext,
1557
+ type LLMFunction,
1558
+ RegexEntityExtractor,
1559
+ LLMEntityExtractor,
1560
+ buildExtractionPrompt,
1561
+ parseExtractionResponse,
1562
+ } from "./mongodb-entity-extractor.js";
1563
+ ```
1564
+
1565
+ ```bash
1566
+ pnpm build
1567
+ ```
1568
+
1569
+ **Commit after Phase 5:**
1570
+
1571
+ ```
1572
+ Feat: add pluggable entity extraction with regex default and LLM upgrade path
1573
+ ```
1574
+
1575
+ ---
1576
+
1577
+ ## Phase 6: Final Integration + Validation
1578
+
1579
+ > **Exit Criteria:** All 4 features integrated, all tests pass, build clean. README updated. Barrel exports complete.
1580
+
1581
+ ### Task 6.1: Update README.md capabilities table
1582
+
1583
+ **Files:**
1584
+
1585
+ - Modify: `README.md`
1586
+
1587
+ Add 4 new rows to the capabilities table:
1588
+
1589
+ ```markdown
1590
+ | 15 | **Profile Synthesis** | Dynamic agent profile from structured memory, entities, episodes, and events | $facet + $lookup aggregation across 5 collections, ~5-50ms |
1591
+ | 16 | **Cross-Encoder Re-ranking** | Voyage rerank-2.5 precision pass on search results | Two-stage: $vectorSearch recall → rerank-2.5 precision, 13.89% accuracy improvement |
1592
+ | 17 | **Query Rewriting** | Synonym expansion for improved vector search recall | Deterministic abbreviation + synonym expansion before embedding |
1593
+ | 18 | **Pluggable Entity Extraction** | Regex default with LLM upgrade path for richer knowledge graphs | EntityExtractor interface, RegexEntityExtractor + LLMEntityExtractor |
1594
+ ```
1595
+
1596
+ Update capability count from 14 to 18.
1597
+
1598
+ ### Task 6.2: Run full validation
1599
+
1600
+ ```bash
1601
+ # All new test files pass
1602
+ pnpm test -- src/memory/mongodb-profile.test.ts src/memory/mongodb-reranker.test.ts src/memory/mongodb-query-rewriter.test.ts src/memory/mongodb-entity-extractor.test.ts
1603
+
1604
+ # Backend config tests pass with new sections
1605
+ pnpm test -- src/memory/backend-config.test.ts
1606
+
1607
+ # Existing tests not regressed
1608
+ pnpm test -- src/memory/mongodb-manager.test.ts src/memory/mongodb-graph.test.ts
1609
+
1610
+ # Build clean
1611
+ pnpm build
1612
+
1613
+ # Full test suite
1614
+ pnpm test
1615
+ ```
1616
+
1617
+ **Commit after Phase 6:**
1618
+
1619
+ ```
1620
+ Docs: update README with 18 capabilities including profile, reranking, query rewriting, entity extraction
1621
+ ```
1622
+
1623
+ ---
1624
+
1625
+ ## Risks
1626
+
1627
+ | Risk | P (1-5) | I (1-5) | Score | Mitigation |
1628
+ | --------------------------------------------- | ------- | ------- | ----- | -------------------------------------------------------------------- |
1629
+ | Voyage rerank API unavailable/slow | 3 | 2 | 6 | Fallback to heuristic order on any error |
1630
+ | LLM entity extraction hallucination | 3 | 3 | 9 | Validate extracted entities, confidence threshold, fallback to regex |
1631
+ | Query rewriting false expansions | 2 | 2 | 4 | Planner never sees rewritten query, cache key uses original |
1632
+ | $facet 100MB RAM limit on profile | 1 | 3 | 3 | Pre-filter with $match, limit each sub-pipeline to 20 items |
1633
+ | LLM extraction timeout on slow models | 3 | 2 | 6 | Configurable timeout (default 5s), fallback to regex |
1634
+ | Existing extractAndUpsertEntities tests break | 3 | 2 | 6 | RegexEntityExtractor preserves exact same behavior as default |
1635
+ | Score semantics confusion (rerank vs vector) | 2 | 2 | 4 | Rerank scores replace .score field, both [0,1] range |
1636
+
1637
+ ---
1638
+
1639
+ ## Success Criteria
1640
+
1641
+ - [ ] Profile synthesis returns ProfileSynthesis from 5 collections via $facet + $lookup
1642
+ - [ ] Cross-encoder reranking calls Voyage rerank-2.5 and improves precision
1643
+ - [ ] Cross-encoder falls back gracefully on any error
1644
+ - [ ] Query rewriting expands abbreviations and synonyms before search
1645
+ - [ ] Query rewriting never affects retrieval planner or cache key
1646
+ - [ ] Pluggable EntityExtractor interface with regex default
1647
+ - [ ] LLMEntityExtractor with timeout and regex fallback
1648
+ - [ ] All 4 features disabled-by-default (except profile which is on-demand)
1649
+ - [ ] Config sections added with sensible defaults
1650
+ - [ ] Telemetry emitted for all 4 operations
1651
+ - [ ] 60+ new tests pass
1652
+ - [ ] `pnpm build` exit 0
1653
+ - [ ] `pnpm test` — no regressions
1654
+ - [ ] Barrel exports complete in index.ts
1655
+
1656
+ ---
1657
+
1658
+ ## Acceptance Checks
1659
+
1660
+ ```bash
1661
+ # Phase 1: Config tests
1662
+ pnpm test -- src/memory/backend-config.test.ts
1663
+
1664
+ # Phase 2: Profile synthesis tests
1665
+ pnpm test -- src/memory/mongodb-profile.test.ts
1666
+
1667
+ # Phase 3: Reranker tests
1668
+ pnpm test -- src/memory/mongodb-reranker.test.ts
1669
+
1670
+ # Phase 4: Query rewriter tests
1671
+ pnpm test -- src/memory/mongodb-query-rewriter.test.ts
1672
+
1673
+ # Phase 5: Entity extractor tests
1674
+ pnpm test -- src/memory/mongodb-entity-extractor.test.ts
1675
+
1676
+ # Phase 6: Full validation
1677
+ pnpm build
1678
+ pnpm test
1679
+ ```