@poolzin/pool-bot 2026.1.39 → 2026.2.1

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 (511) hide show
  1. package/assets/chrome-extension/README.md +3 -3
  2. package/assets/chrome-extension/background.js +5 -5
  3. package/assets/chrome-extension/manifest.json +3 -3
  4. package/assets/chrome-extension/options.html +4 -4
  5. package/assets/chrome-extension/options.js +1 -1
  6. package/dist/acp/client.js +3 -3
  7. package/dist/acp/types.js +1 -1
  8. package/dist/agents/agent-paths.js +3 -3
  9. package/dist/agents/auth-profiles/paths.js +3 -3
  10. package/dist/agents/bash-tools.exec.js +76 -25
  11. package/dist/agents/cli-runner/helpers.js +10 -12
  12. package/dist/agents/cli-runner.js +2 -2
  13. package/dist/agents/cloudflare-ai-gateway.js +31 -0
  14. package/dist/agents/compaction.js +16 -2
  15. package/dist/agents/context-window-guard.js +13 -10
  16. package/dist/agents/context.js +4 -4
  17. package/dist/agents/docs-path.js +1 -1
  18. package/dist/agents/identity.js +47 -7
  19. package/dist/agents/memory-search.js +25 -8
  20. package/dist/agents/minimax-vlm.js +1 -1
  21. package/dist/agents/model-auth.js +12 -1
  22. package/dist/agents/model-catalog.js +4 -4
  23. package/dist/agents/model-selection.js +31 -4
  24. package/dist/agents/models-config.js +3 -3
  25. package/dist/agents/models-config.providers.js +147 -39
  26. package/dist/agents/pi-embedded-block-chunker.js +117 -42
  27. package/dist/agents/pi-embedded-helpers/errors.js +183 -78
  28. package/dist/agents/pi-embedded-helpers/openai.js +1 -1
  29. package/dist/agents/pi-embedded-helpers.js +1 -1
  30. package/dist/agents/pi-embedded-runner/compact.js +9 -8
  31. package/dist/agents/pi-embedded-runner/model.js +63 -4
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
  33. package/dist/agents/pi-embedded-runner/run.js +203 -50
  34. package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
  35. package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
  36. package/dist/agents/pi-embedded-runner/utils.js +1 -1
  37. package/dist/agents/pi-embedded-subscribe.js +118 -29
  38. package/dist/agents/pi-model-discovery.js +10 -0
  39. package/dist/agents/pi-tool-definition-adapter.js +50 -9
  40. package/dist/agents/pi-tools.before-tool-call.js +67 -0
  41. package/dist/agents/pi-tools.js +20 -10
  42. package/dist/agents/pi-tools.read.js +2 -2
  43. package/dist/agents/poolbot-tools.js +15 -10
  44. package/dist/agents/sandbox-paths.js +31 -0
  45. package/dist/agents/session-file-repair.js +83 -0
  46. package/dist/agents/session-tool-result-guard.js +94 -15
  47. package/dist/agents/session-transcript-repair.js +68 -0
  48. package/dist/agents/shell-utils.js +51 -0
  49. package/dist/agents/skills/bundled-context.js +23 -0
  50. package/dist/agents/skills/bundled-dir.js +41 -7
  51. package/dist/agents/skills/frontmatter.js +1 -1
  52. package/dist/agents/skills/workspace.js +2 -2
  53. package/dist/agents/skills-install.js +60 -23
  54. package/dist/agents/subagent-announce.js +79 -34
  55. package/dist/agents/system-prompt.js +28 -4
  56. package/dist/agents/together-models.js +127 -0
  57. package/dist/agents/tool-images.js +1 -1
  58. package/dist/agents/tool-policy.conformance.js +14 -0
  59. package/dist/agents/tool-policy.js +25 -1
  60. package/dist/agents/tools/browser-tool.js +3 -3
  61. package/dist/agents/tools/cron-tool.js +166 -19
  62. package/dist/agents/tools/discord-actions-presence.js +78 -0
  63. package/dist/agents/tools/image-tool.js +2 -2
  64. package/dist/agents/tools/memory-tool.js +93 -5
  65. package/dist/agents/tools/message-tool.js +56 -2
  66. package/dist/agents/tools/sessions-history-tool.js +69 -1
  67. package/dist/agents/tools/web-search.js +211 -42
  68. package/dist/agents/usage.js +23 -1
  69. package/dist/agents/workspace-run.js +67 -0
  70. package/dist/agents/workspace-templates.js +44 -0
  71. package/dist/auto-reply/command-auth.js +121 -6
  72. package/dist/auto-reply/commands-registry.data.js +1 -1
  73. package/dist/auto-reply/envelope.js +50 -72
  74. package/dist/auto-reply/reply/commands-compact.js +1 -0
  75. package/dist/auto-reply/reply/commands-context-report.js +3 -2
  76. package/dist/auto-reply/reply/commands-context.js +1 -0
  77. package/dist/auto-reply/reply/commands-models.js +107 -60
  78. package/dist/auto-reply/reply/commands-ptt.js +171 -0
  79. package/dist/auto-reply/reply/commands-session.js +2 -2
  80. package/dist/auto-reply/reply/get-reply-run.js +16 -5
  81. package/dist/auto-reply/reply/groups.js +1 -1
  82. package/dist/auto-reply/reply/inbound-context.js +9 -1
  83. package/dist/auto-reply/reply/inbound-meta.js +130 -0
  84. package/dist/auto-reply/reply/model-selection.js +3 -3
  85. package/dist/auto-reply/reply/untrusted-context.js +15 -0
  86. package/dist/auto-reply/status.js +1 -1
  87. package/dist/auto-reply/thinking.js +88 -43
  88. package/dist/browser/bridge-server.js +13 -0
  89. package/dist/browser/cdp.helpers.js +38 -24
  90. package/dist/browser/client-fetch.js +51 -8
  91. package/dist/browser/config.js +2 -11
  92. package/dist/browser/extension-relay.js +104 -43
  93. package/dist/browser/pw-ai.js +1 -1
  94. package/dist/browser/pw-session.js +143 -8
  95. package/dist/browser/pw-tools-core.interactions.js +125 -27
  96. package/dist/browser/pw-tools-core.responses.js +1 -1
  97. package/dist/browser/pw-tools-core.state.js +1 -1
  98. package/dist/browser/routes/agent.act.js +86 -41
  99. package/dist/browser/routes/dispatcher.js +4 -4
  100. package/dist/browser/screenshot.js +1 -1
  101. package/dist/browser/server-context.js +2 -2
  102. package/dist/browser/server.js +13 -0
  103. package/dist/build-info.json +3 -3
  104. package/dist/canvas-host/a2ui.js +3 -3
  105. package/dist/channels/plugins/catalog.js +2 -2
  106. package/dist/channels/plugins/onboarding/imessage.js +1 -1
  107. package/dist/channels/plugins/onboarding/signal.js +1 -1
  108. package/dist/channels/plugins/onboarding/slack.js +4 -4
  109. package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
  110. package/dist/channels/plugins/pairing-message.js +1 -1
  111. package/dist/channels/reply-prefix.js +8 -1
  112. package/dist/cli/browser-cli-extension.js +2 -2
  113. package/dist/cli/cron-cli/register.cron-add.js +61 -40
  114. package/dist/cli/cron-cli/register.cron-edit.js +60 -34
  115. package/dist/cli/cron-cli/shared.js +56 -41
  116. package/dist/cli/dns-cli.js +26 -14
  117. package/dist/cli/docs-cli.js +1 -1
  118. package/dist/cli/gateway-cli/dev.js +1 -1
  119. package/dist/cli/gateway-cli/register.js +37 -19
  120. package/dist/cli/memory-cli.js +30 -20
  121. package/dist/cli/nodes-cli/register.canvas.js +1 -1
  122. package/dist/cli/parse-bytes.js +37 -0
  123. package/dist/cli/plugins-cli.js +1 -1
  124. package/dist/cli/run-main.js +2 -2
  125. package/dist/cli/security-cli.js +1 -1
  126. package/dist/cli/tagline.js +1 -1
  127. package/dist/cli/update-cli.js +173 -52
  128. package/dist/cli/webhooks-cli.js +5 -5
  129. package/dist/commands/agent.js +1 -0
  130. package/dist/commands/agents.commands.add.js +1 -1
  131. package/dist/commands/auth-choice.apply.api-providers.js +305 -17
  132. package/dist/commands/auth-choice.apply.js +4 -1
  133. package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
  134. package/dist/commands/auth-choice.apply.xai.js +63 -0
  135. package/dist/commands/auth-choice.preferred-provider.js +7 -1
  136. package/dist/commands/configure.wizard.js +1 -1
  137. package/dist/commands/dashboard.js +1 -1
  138. package/dist/commands/docs.js +1 -1
  139. package/dist/commands/doctor-config-flow.js +61 -5
  140. package/dist/commands/doctor-gateway-services.js +3 -3
  141. package/dist/commands/doctor-state-migrations.js +1 -1
  142. package/dist/commands/doctor-update.js +3 -3
  143. package/dist/commands/doctor.js +1 -1
  144. package/dist/commands/health.js +1 -1
  145. package/dist/commands/model-allowlist.js +29 -0
  146. package/dist/commands/model-picker.js +2 -1
  147. package/dist/commands/models/list.probe.js +2 -2
  148. package/dist/commands/models/list.registry.js +4 -4
  149. package/dist/commands/models/list.status-command.js +44 -24
  150. package/dist/commands/models/shared.js +15 -0
  151. package/dist/commands/onboard-auth.config-core.js +366 -28
  152. package/dist/commands/onboard-auth.credentials.js +71 -9
  153. package/dist/commands/onboard-auth.js +3 -3
  154. package/dist/commands/onboard-auth.models.js +26 -24
  155. package/dist/commands/onboard-custom.js +384 -0
  156. package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
  157. package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
  158. package/dist/commands/onboard-skills.js +63 -38
  159. package/dist/commands/openai-model-default.js +41 -0
  160. package/dist/commands/status-all/report-lines.js +1 -1
  161. package/dist/commands/status.command.js +1 -1
  162. package/dist/commands/uninstall.js +3 -3
  163. package/dist/compat/legacy-names.js +1 -1
  164. package/dist/config/defaults.js +3 -2
  165. package/dist/config/io.js +3 -3
  166. package/dist/config/paths.js +136 -35
  167. package/dist/config/plugin-auto-enable.js +21 -5
  168. package/dist/config/redact-snapshot.js +153 -0
  169. package/dist/config/schema.field-metadata.js +590 -0
  170. package/dist/config/schema.js +3 -3
  171. package/dist/config/sessions/store.js +291 -23
  172. package/dist/config/types.memory.js +1 -0
  173. package/dist/config/version.js +4 -4
  174. package/dist/config/zod-schema.agent-defaults.js +3 -0
  175. package/dist/config/zod-schema.agent-runtime.js +13 -2
  176. package/dist/config/zod-schema.providers-core.js +142 -0
  177. package/dist/config/zod-schema.session.js +3 -0
  178. package/dist/cron/delivery.js +57 -0
  179. package/dist/cron/isolated-agent/delivery-target.js +18 -3
  180. package/dist/cron/isolated-agent/helpers.js +22 -5
  181. package/dist/cron/isolated-agent/run.js +171 -63
  182. package/dist/cron/isolated-agent/session.js +2 -0
  183. package/dist/cron/normalize.js +356 -28
  184. package/dist/cron/parse.js +10 -5
  185. package/dist/cron/run-log.js +35 -10
  186. package/dist/cron/schedule.js +41 -6
  187. package/dist/cron/service/jobs.js +208 -35
  188. package/dist/cron/service/ops.js +72 -16
  189. package/dist/cron/service/state.js +2 -0
  190. package/dist/cron/service/store.js +386 -14
  191. package/dist/cron/service/timer.js +390 -147
  192. package/dist/cron/session-reaper.js +86 -0
  193. package/dist/cron/store.js +23 -8
  194. package/dist/cron/validate-timestamp.js +43 -0
  195. package/dist/daemon/constants.js +7 -7
  196. package/dist/daemon/inspect.js +6 -6
  197. package/dist/daemon/systemd-unit.js +1 -1
  198. package/dist/discord/monitor/agent-components.js +438 -0
  199. package/dist/discord/monitor/allow-list.js +28 -5
  200. package/dist/discord/monitor/gateway-registry.js +29 -0
  201. package/dist/discord/monitor/native-command.js +44 -23
  202. package/dist/discord/monitor/sender-identity.js +45 -0
  203. package/dist/discord/pluralkit.js +27 -0
  204. package/dist/discord/send.outbound.js +92 -5
  205. package/dist/discord/send.shared.js +60 -23
  206. package/dist/discord/targets.js +84 -1
  207. package/dist/entry.js +15 -9
  208. package/dist/extensionAPI.js +8 -0
  209. package/dist/gateway/control-ui.js +8 -1
  210. package/dist/gateway/hooks-mapping.js +3 -0
  211. package/dist/gateway/hooks.js +65 -0
  212. package/dist/gateway/live-image-probe.js +1 -66
  213. package/dist/gateway/net.js +96 -31
  214. package/dist/gateway/node-command-policy.js +50 -15
  215. package/dist/gateway/openai-http.js +2 -2
  216. package/dist/gateway/openresponses-http.js +4 -4
  217. package/dist/gateway/origin-check.js +56 -0
  218. package/dist/gateway/protocol/client-info.js +9 -0
  219. package/dist/gateway/protocol/index.js +9 -2
  220. package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
  221. package/dist/gateway/protocol/schema/cron.js +22 -10
  222. package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
  223. package/dist/gateway/protocol/schema/sessions.js +12 -0
  224. package/dist/gateway/server/hooks.js +1 -1
  225. package/dist/gateway/server-broadcast.js +26 -9
  226. package/dist/gateway/server-chat.js +112 -23
  227. package/dist/gateway/server-discovery-runtime.js +10 -2
  228. package/dist/gateway/server-discovery.js +2 -2
  229. package/dist/gateway/server-http.js +110 -12
  230. package/dist/gateway/server-methods/agent-timestamp.js +60 -0
  231. package/dist/gateway/server-methods/agents.js +321 -2
  232. package/dist/gateway/server-methods/usage.js +559 -16
  233. package/dist/gateway/server-runtime-state.js +22 -8
  234. package/dist/gateway/server-startup-memory.js +16 -0
  235. package/dist/gateway/server.impl.js +7 -3
  236. package/dist/gateway/session-utils.fs.js +23 -25
  237. package/dist/gateway/session-utils.js +20 -10
  238. package/dist/gateway/sessions-patch.js +7 -22
  239. package/dist/gateway/test-helpers.server.js +35 -2
  240. package/dist/hooks/frontmatter.js +1 -1
  241. package/dist/hooks/hooks-status.js +1 -1
  242. package/dist/hooks/install.js +2 -2
  243. package/dist/hooks/loader.js +1 -1
  244. package/dist/hooks/workspace.js +3 -3
  245. package/dist/imessage/constants.js +2 -0
  246. package/dist/imessage/monitor/deliver.js +4 -1
  247. package/dist/imessage/monitor/monitor-provider.js +51 -1
  248. package/dist/index.js +2 -2
  249. package/dist/infra/bonjour-discovery.js +131 -70
  250. package/dist/infra/bonjour.js +3 -3
  251. package/dist/infra/control-ui-assets.js +134 -12
  252. package/dist/infra/errors.js +12 -0
  253. package/dist/infra/exec-approvals.js +266 -57
  254. package/dist/infra/format-time/format-datetime.js +79 -0
  255. package/dist/infra/format-time/format-duration.js +81 -0
  256. package/dist/infra/format-time/format-relative.js +80 -0
  257. package/dist/infra/heartbeat-runner.js +140 -49
  258. package/dist/infra/home-dir.js +54 -0
  259. package/dist/infra/net/fetch-guard.js +122 -0
  260. package/dist/infra/net/ssrf.js +65 -29
  261. package/dist/infra/outbound/abort.js +14 -0
  262. package/dist/infra/outbound/message-action-runner.js +77 -13
  263. package/dist/infra/outbound/outbound-session.js +143 -37
  264. package/dist/infra/path-env.js +3 -3
  265. package/dist/infra/poolbot-root.js +43 -1
  266. package/dist/infra/provider-usage.fetch.minimax.js +1 -1
  267. package/dist/infra/restart.js +1 -1
  268. package/dist/infra/session-cost-usage.js +631 -41
  269. package/dist/infra/state-migrations.js +317 -47
  270. package/dist/infra/tailscale.js +1 -1
  271. package/dist/infra/update-global.js +35 -0
  272. package/dist/infra/update-runner.js +149 -43
  273. package/dist/infra/warning-filter.js +65 -0
  274. package/dist/infra/widearea-dns.js +30 -9
  275. package/dist/logging/redact-identifier.js +12 -0
  276. package/dist/macos/relay.js +2 -2
  277. package/dist/media/fetch.js +81 -58
  278. package/dist/media/input-files.js +1 -1
  279. package/dist/media/mime.js +4 -0
  280. package/dist/media/png-encode.js +74 -0
  281. package/dist/media-understanding/apply.js +403 -3
  282. package/dist/media-understanding/attachments.js +38 -27
  283. package/dist/media-understanding/defaults.js +16 -0
  284. package/dist/media-understanding/providers/deepgram/audio.js +22 -14
  285. package/dist/media-understanding/providers/google/audio.js +24 -17
  286. package/dist/media-understanding/providers/google/video.js +24 -17
  287. package/dist/media-understanding/providers/image.js +4 -4
  288. package/dist/media-understanding/providers/index.js +4 -1
  289. package/dist/media-understanding/providers/openai/audio.js +22 -14
  290. package/dist/media-understanding/providers/shared.js +16 -11
  291. package/dist/media-understanding/providers/zai/index.js +6 -0
  292. package/dist/media-understanding/runner.js +158 -90
  293. package/dist/memory/backend-config.js +207 -0
  294. package/dist/memory/batch-voyage.js +277 -0
  295. package/dist/memory/embeddings-voyage.js +75 -0
  296. package/dist/memory/embeddings.js +29 -17
  297. package/dist/memory/internal.js +101 -18
  298. package/dist/memory/manager.js +155 -48
  299. package/dist/memory/search-manager.js +173 -0
  300. package/dist/memory/session-files.js +9 -3
  301. package/dist/memory/types.js +1 -0
  302. package/dist/node-host/runner.js +36 -26
  303. package/dist/node-host/with-timeout.js +27 -0
  304. package/dist/pairing/pairing-messages.js +1 -1
  305. package/dist/plugins/commands.js +5 -1
  306. package/dist/plugins/config-state.js +86 -7
  307. package/dist/plugins/discovery.js +1 -1
  308. package/dist/plugins/install.js +2 -2
  309. package/dist/plugins/source-display.js +51 -0
  310. package/dist/plugins/update.js +1 -1
  311. package/dist/process/exec.js +20 -2
  312. package/dist/routing/resolve-route.js +12 -0
  313. package/dist/routing/session-key.js +15 -0
  314. package/dist/runtime.js +2 -0
  315. package/dist/security/audit-extra.async.js +601 -0
  316. package/dist/security/audit-extra.js +2 -830
  317. package/dist/security/audit-extra.sync.js +505 -0
  318. package/dist/security/audit.js +2 -2
  319. package/dist/security/channel-metadata.js +34 -0
  320. package/dist/security/external-content.js +88 -6
  321. package/dist/security/skill-scanner.js +330 -0
  322. package/dist/sessions/session-key-utils.js +7 -0
  323. package/dist/shared/text/reasoning-tags.js +52 -7
  324. package/dist/signal/monitor/event-handler.js +80 -1
  325. package/dist/slack/monitor/media.js +85 -15
  326. package/dist/tailscale/detect.js +145 -0
  327. package/dist/telegram/bot/helpers.js +109 -28
  328. package/dist/telegram/bot-handlers.js +144 -3
  329. package/dist/telegram/bot-message-context.js +38 -11
  330. package/dist/telegram/bot-message-dispatch.js +48 -15
  331. package/dist/telegram/bot-native-commands.js +86 -29
  332. package/dist/telegram/bot.js +30 -29
  333. package/dist/telegram/model-buttons.js +163 -0
  334. package/dist/telegram/monitor.js +110 -85
  335. package/dist/telegram/send.js +129 -47
  336. package/dist/terminal/restore.js +45 -0
  337. package/dist/test-helpers/state-dir-env.js +16 -0
  338. package/dist/test-helpers/workspace.js +11 -0
  339. package/dist/test-utils/channel-plugins.js +82 -0
  340. package/dist/test-utils/ports.js +73 -0
  341. package/dist/tts/tts.js +12 -6
  342. package/dist/tui/tui-session-actions.js +166 -54
  343. package/dist/utils/fetch-timeout.js +20 -0
  344. package/dist/utils/normalize-secret-input.js +19 -0
  345. package/dist/utils/shell-argv.js +61 -0
  346. package/dist/utils/transcript-tools.js +58 -0
  347. package/dist/utils.js +55 -14
  348. package/dist/version.js +42 -5
  349. package/dist/web/qr-image.js +1 -61
  350. package/dist/wizard/onboarding.finalize.js +7 -7
  351. package/dist/wizard/onboarding.js +3 -3
  352. package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
  353. package/docs/_config.yml +2 -2
  354. package/docs/_layouts/default.html +9 -9
  355. package/docs/concepts/typebox.md +1 -1
  356. package/docs/docs.json +1 -1
  357. package/docs/northflank.mdx +7 -7
  358. package/docs/railway.mdx +3 -3
  359. package/docs/render.mdx +5 -5
  360. package/docs/start/lore.md +2 -2
  361. package/extensions/bluebubbles/index.ts +2 -2
  362. package/extensions/bluebubbles/package.json +1 -1
  363. package/extensions/bluebubbles/src/accounts.ts +8 -8
  364. package/extensions/bluebubbles/src/actions.test.ts +22 -22
  365. package/extensions/bluebubbles/src/actions.ts +5 -5
  366. package/extensions/bluebubbles/src/attachments.ts +2 -2
  367. package/extensions/bluebubbles/src/channel.ts +16 -16
  368. package/extensions/bluebubbles/src/chat.ts +2 -2
  369. package/extensions/bluebubbles/src/media-send.ts +2 -2
  370. package/extensions/bluebubbles/src/monitor.test.ts +46 -46
  371. package/extensions/bluebubbles/src/monitor.ts +5 -5
  372. package/extensions/bluebubbles/src/onboarding.ts +7 -7
  373. package/extensions/bluebubbles/src/reactions.ts +2 -2
  374. package/extensions/bluebubbles/src/send.ts +2 -2
  375. package/extensions/copilot-proxy/README.md +1 -1
  376. package/extensions/copilot-proxy/package.json +1 -1
  377. package/extensions/diagnostics-otel/index.ts +2 -2
  378. package/extensions/diagnostics-otel/package.json +1 -1
  379. package/extensions/diagnostics-otel/src/service.ts +3 -3
  380. package/extensions/discord/index.ts +2 -2
  381. package/extensions/discord/package.json +1 -1
  382. package/extensions/google-antigravity-auth/README.md +1 -1
  383. package/extensions/google-antigravity-auth/index.ts +1 -1
  384. package/extensions/google-antigravity-auth/package.json +1 -1
  385. package/extensions/google-gemini-cli-auth/README.md +1 -1
  386. package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
  387. package/extensions/google-gemini-cli-auth/package.json +1 -1
  388. package/extensions/googlechat/index.ts +3 -3
  389. package/extensions/googlechat/package.json +1 -1
  390. package/extensions/googlechat/src/accounts.ts +8 -8
  391. package/extensions/googlechat/src/actions.ts +6 -6
  392. package/extensions/googlechat/src/channel.ts +21 -21
  393. package/extensions/googlechat/src/monitor.ts +8 -8
  394. package/extensions/googlechat/src/onboarding.ts +10 -10
  395. package/extensions/imessage/index.ts +2 -2
  396. package/extensions/imessage/package.json +1 -1
  397. package/extensions/line/index.ts +2 -2
  398. package/extensions/line/package.json +1 -1
  399. package/extensions/line/src/card-command.ts +2 -2
  400. package/extensions/line/src/channel.logout.test.ts +4 -4
  401. package/extensions/line/src/channel.sendPayload.test.ts +8 -8
  402. package/extensions/line/src/channel.ts +3 -3
  403. package/extensions/llm-task/README.md +3 -3
  404. package/extensions/llm-task/index.ts +2 -2
  405. package/extensions/llm-task/package.json +1 -1
  406. package/extensions/llm-task/src/llm-task-tool.ts +4 -4
  407. package/extensions/lobster/README.md +6 -6
  408. package/extensions/lobster/index.ts +2 -2
  409. package/extensions/lobster/src/lobster-tool.test.ts +4 -4
  410. package/extensions/lobster/src/lobster-tool.ts +2 -2
  411. package/extensions/matrix/index.ts +2 -2
  412. package/extensions/matrix/package.json +1 -1
  413. package/extensions/matrix/src/matrix/client/config.ts +1 -1
  414. package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
  415. package/extensions/matrix/src/onboarding.ts +1 -1
  416. package/extensions/mattermost/index.ts +2 -2
  417. package/extensions/mattermost/package.json +1 -1
  418. package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
  419. package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
  420. package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
  421. package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
  422. package/extensions/mattermost/src/onboarding.ts +2 -2
  423. package/extensions/memory-core/index.ts +2 -2
  424. package/extensions/memory-core/package.json +1 -1
  425. package/extensions/memory-lancedb/index.ts +3 -3
  426. package/extensions/memory-lancedb/package.json +1 -1
  427. package/extensions/msteams/index.ts +2 -2
  428. package/extensions/msteams/package.json +1 -1
  429. package/extensions/msteams/src/channel.directory.test.ts +2 -2
  430. package/extensions/msteams/src/channel.ts +2 -2
  431. package/extensions/msteams/src/graph-upload.ts +4 -4
  432. package/extensions/msteams/src/monitor-handler.ts +2 -2
  433. package/extensions/msteams/src/monitor.ts +2 -2
  434. package/extensions/msteams/src/onboarding.ts +9 -9
  435. package/extensions/msteams/src/reply-dispatcher.ts +2 -2
  436. package/extensions/msteams/src/send-context.ts +2 -2
  437. package/extensions/msteams/src/send.ts +4 -4
  438. package/extensions/nextcloud-talk/index.ts +2 -2
  439. package/extensions/nextcloud-talk/package.json +1 -1
  440. package/extensions/nextcloud-talk/src/channel.ts +7 -7
  441. package/extensions/nextcloud-talk/src/inbound.ts +7 -7
  442. package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
  443. package/extensions/nostr/README.md +2 -2
  444. package/extensions/nostr/index.ts +5 -5
  445. package/extensions/nostr/package.json +1 -1
  446. package/extensions/nostr/src/types.ts +4 -4
  447. package/extensions/open-prose/index.ts +2 -2
  448. package/extensions/qwen-portal-auth/README.md +1 -1
  449. package/extensions/signal/index.ts +2 -2
  450. package/extensions/signal/package.json +1 -1
  451. package/extensions/slack/index.ts +2 -2
  452. package/extensions/slack/package.json +1 -1
  453. package/extensions/telegram/index.ts +2 -2
  454. package/extensions/telegram/package.json +1 -1
  455. package/extensions/telegram/src/channel.ts +2 -2
  456. package/extensions/tlon/README.md +2 -2
  457. package/extensions/tlon/index.ts +2 -2
  458. package/extensions/tlon/package.json +1 -1
  459. package/extensions/tlon/src/channel.ts +13 -13
  460. package/extensions/tlon/src/monitor/index.ts +3 -3
  461. package/extensions/tlon/src/onboarding.ts +3 -3
  462. package/extensions/tlon/src/types.ts +3 -3
  463. package/extensions/twitch/README.md +1 -1
  464. package/extensions/twitch/index.ts +2 -2
  465. package/extensions/twitch/package.json +1 -1
  466. package/extensions/twitch/src/config.ts +3 -3
  467. package/extensions/twitch/src/monitor.ts +3 -3
  468. package/extensions/twitch/src/onboarding.ts +9 -9
  469. package/extensions/twitch/src/outbound.test.ts +2 -2
  470. package/extensions/twitch/src/plugin.test.ts +2 -2
  471. package/extensions/twitch/src/plugin.ts +8 -8
  472. package/extensions/twitch/src/send.test.ts +2 -2
  473. package/extensions/twitch/src/send.ts +4 -4
  474. package/extensions/twitch/src/token.test.ts +8 -8
  475. package/extensions/twitch/src/token.ts +3 -3
  476. package/extensions/twitch/src/twitch-client.ts +3 -3
  477. package/extensions/twitch/src/types.ts +3 -3
  478. package/extensions/twitch/src/utils/markdown.ts +1 -1
  479. package/extensions/voice-call/README.md +3 -3
  480. package/extensions/voice-call/package.json +1 -1
  481. package/extensions/voice-call/src/core-bridge.ts +2 -2
  482. package/extensions/voice-call/src/response-generator.ts +1 -1
  483. package/extensions/whatsapp/index.ts +2 -2
  484. package/extensions/whatsapp/package.json +1 -1
  485. package/extensions/zalo/README.md +1 -1
  486. package/extensions/zalo/index.ts +2 -2
  487. package/extensions/zalo/package.json +1 -1
  488. package/extensions/zalo/src/accounts.ts +8 -8
  489. package/extensions/zalo/src/actions.ts +4 -4
  490. package/extensions/zalo/src/channel.directory.test.ts +2 -2
  491. package/extensions/zalo/src/channel.ts +18 -18
  492. package/extensions/zalo/src/monitor.ts +9 -9
  493. package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
  494. package/extensions/zalo/src/onboarding.ts +24 -24
  495. package/extensions/zalo/src/send.ts +2 -2
  496. package/extensions/zalouser/README.md +2 -2
  497. package/extensions/zalouser/index.ts +2 -2
  498. package/extensions/zalouser/package.json +1 -1
  499. package/extensions/zalouser/src/accounts.ts +9 -9
  500. package/extensions/zalouser/src/channel.ts +24 -24
  501. package/extensions/zalouser/src/monitor.ts +4 -4
  502. package/extensions/zalouser/src/onboarding.ts +28 -28
  503. package/package.json +13 -251
  504. package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
  505. package/skills/tmux/scripts/find-sessions.sh +1 -1
  506. package/CHANGELOG.md +0 -102
  507. package/README-header.png +0 -0
  508. package/git-hooks/pre-commit +0 -4
  509. package/scripts/format-staged.js +0 -148
  510. package/scripts/postinstall.js +0 -300
  511. package/scripts/setup-git-hooks.js +0 -96
@@ -13,6 +13,16 @@ export function normalizeRelPath(value) {
13
13
  const trimmed = value.trim().replace(/^[./]+/, "");
14
14
  return trimmed.replace(/\\/g, "/");
15
15
  }
16
+ export function normalizeExtraMemoryPaths(workspaceDir, extraPaths) {
17
+ if (!extraPaths?.length) {
18
+ return [];
19
+ }
20
+ const resolved = extraPaths
21
+ .map((value) => value.trim())
22
+ .filter(Boolean)
23
+ .map((value) => path.isAbsolute(value) ? path.resolve(value) : path.resolve(workspaceDir, value));
24
+ return Array.from(new Set(resolved));
25
+ }
16
26
  export function isMemoryPath(relPath) {
17
27
  const normalized = normalizeRelPath(relPath);
18
28
  if (!normalized)
@@ -21,15 +31,6 @@ export function isMemoryPath(relPath) {
21
31
  return true;
22
32
  return normalized.startsWith("memory/");
23
33
  }
24
- async function exists(filePath) {
25
- try {
26
- await fs.access(filePath);
27
- return true;
28
- }
29
- catch {
30
- return false;
31
- }
32
- }
33
34
  async function walkDir(dir, files) {
34
35
  const entries = await fs.readdir(dir, { withFileTypes: true });
35
36
  for (const entry of entries) {
@@ -45,20 +46,55 @@ async function walkDir(dir, files) {
45
46
  files.push(full);
46
47
  }
47
48
  }
48
- export async function listMemoryFiles(workspaceDir) {
49
+ export async function listMemoryFiles(workspaceDir, extraPaths) {
49
50
  const result = [];
50
51
  const memoryFile = path.join(workspaceDir, "MEMORY.md");
51
52
  const altMemoryFile = path.join(workspaceDir, "memory.md");
52
- if (await exists(memoryFile))
53
- result.push(memoryFile);
54
- if (await exists(altMemoryFile))
55
- result.push(altMemoryFile);
56
53
  const memoryDir = path.join(workspaceDir, "memory");
57
- if (await exists(memoryDir)) {
58
- await walkDir(memoryDir, result);
54
+ const addMarkdownFile = async (absPath) => {
55
+ try {
56
+ const stat = await fs.lstat(absPath);
57
+ if (stat.isSymbolicLink() || !stat.isFile()) {
58
+ return;
59
+ }
60
+ if (!absPath.endsWith(".md")) {
61
+ return;
62
+ }
63
+ result.push(absPath);
64
+ }
65
+ catch { }
66
+ };
67
+ await addMarkdownFile(memoryFile);
68
+ await addMarkdownFile(altMemoryFile);
69
+ try {
70
+ const dirStat = await fs.lstat(memoryDir);
71
+ if (!dirStat.isSymbolicLink() && dirStat.isDirectory()) {
72
+ await walkDir(memoryDir, result);
73
+ }
59
74
  }
60
- if (result.length <= 1)
75
+ catch { }
76
+ const normalizedExtraPaths = normalizeExtraMemoryPaths(workspaceDir, extraPaths);
77
+ if (normalizedExtraPaths.length > 0) {
78
+ for (const inputPath of normalizedExtraPaths) {
79
+ try {
80
+ const stat = await fs.lstat(inputPath);
81
+ if (stat.isSymbolicLink()) {
82
+ continue;
83
+ }
84
+ if (stat.isDirectory()) {
85
+ await walkDir(inputPath, result);
86
+ continue;
87
+ }
88
+ if (stat.isFile() && inputPath.endsWith(".md")) {
89
+ result.push(inputPath);
90
+ }
91
+ }
92
+ catch { }
93
+ }
94
+ }
95
+ if (result.length <= 1) {
61
96
  return result;
97
+ }
62
98
  const seen = new Set();
63
99
  const deduped = [];
64
100
  for (const entry of result) {
@@ -67,8 +103,9 @@ export async function listMemoryFiles(workspaceDir) {
67
103
  key = await fs.realpath(entry);
68
104
  }
69
105
  catch { }
70
- if (seen.has(key))
106
+ if (seen.has(key)) {
71
107
  continue;
108
+ }
72
109
  seen.add(key);
73
110
  deduped.push(entry);
74
111
  }
@@ -187,3 +224,49 @@ export function cosineSimilarity(a, b) {
187
224
  return 0;
188
225
  return dot / (Math.sqrt(normA) * Math.sqrt(normB));
189
226
  }
227
+ export async function runWithConcurrency(tasks, limit) {
228
+ if (tasks.length === 0) {
229
+ return [];
230
+ }
231
+ const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));
232
+ const results = Array.from({ length: tasks.length });
233
+ let next = 0;
234
+ let firstError = null;
235
+ const workers = Array.from({ length: resolvedLimit }, async () => {
236
+ while (true) {
237
+ if (firstError) {
238
+ return;
239
+ }
240
+ const index = next;
241
+ next += 1;
242
+ if (index >= tasks.length) {
243
+ return;
244
+ }
245
+ try {
246
+ results[index] = await tasks[index]();
247
+ }
248
+ catch (err) {
249
+ firstError = err;
250
+ return;
251
+ }
252
+ }
253
+ });
254
+ await Promise.allSettled(workers);
255
+ if (firstError) {
256
+ throw firstError;
257
+ }
258
+ return results;
259
+ }
260
+ /**
261
+ * Remap chunk startLine/endLine using a lineMap from session file building.
262
+ */
263
+ export function remapChunkLines(chunks, lineMap) {
264
+ if (!lineMap || lineMap.length === 0) {
265
+ return;
266
+ }
267
+ for (const chunk of chunks) {
268
+ // startLine/endLine are 1-indexed; lineMap is 0-indexed by content line
269
+ chunk.startLine = lineMap[chunk.startLine - 1] ?? chunk.startLine;
270
+ chunk.endLine = lineMap[chunk.endLine - 1] ?? chunk.endLine;
271
+ }
272
+ }
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import fs from "node:fs/promises";
3
+ import fsSync from "node:fs";
3
4
  import path from "node:path";
4
5
  import chokidar from "chokidar";
5
6
  import { resolveAgentDir, resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
@@ -11,9 +12,11 @@ import { resolveUserPath } from "../utils.js";
11
12
  import { createEmbeddingProvider, } from "./embeddings.js";
12
13
  import { DEFAULT_GEMINI_EMBEDDING_MODEL } from "./embeddings-gemini.js";
13
14
  import { DEFAULT_OPENAI_EMBEDDING_MODEL } from "./embeddings-openai.js";
15
+ import { DEFAULT_VOYAGE_EMBEDDING_MODEL } from "./embeddings-voyage.js";
14
16
  import { OPENAI_BATCH_ENDPOINT, runOpenAiEmbeddingBatches, } from "./batch-openai.js";
15
17
  import { runGeminiEmbeddingBatches } from "./batch-gemini.js";
16
- import { buildFileEntry, chunkMarkdown, ensureDir, hashText, isMemoryPath, listMemoryFiles, normalizeRelPath, parseEmbedding, } from "./internal.js";
18
+ import { runVoyageEmbeddingBatches } from "./batch-voyage.js";
19
+ import { buildFileEntry, chunkMarkdown, ensureDir, hashText, isMemoryPath, listMemoryFiles, normalizeExtraMemoryPaths, parseEmbedding, remapChunkLines, runWithConcurrency, } from "./internal.js";
17
20
  import { bm25RankToScore, buildFtsQuery, mergeHybridResults } from "./hybrid.js";
18
21
  import { searchKeyword, searchVector } from "./manager-search.js";
19
22
  import { ensureMemoryIndexSchema } from "./memory-schema.js";
@@ -53,6 +56,7 @@ export class MemoryIndexManager {
53
56
  fallbackReason;
54
57
  openAi;
55
58
  gemini;
59
+ voyage;
56
60
  batch;
57
61
  batchFailureCount = 0;
58
62
  batchFailureLastError;
@@ -120,6 +124,7 @@ export class MemoryIndexManager {
120
124
  this.fallbackReason = params.providerResult.fallbackReason;
121
125
  this.openAi = params.providerResult.openAi;
122
126
  this.gemini = params.providerResult.gemini;
127
+ this.voyage = params.providerResult.voyage;
123
128
  this.sources = new Set(params.settings.sources);
124
129
  this.db = this.openDatabase();
125
130
  this.providerKey = this.computeProviderKey();
@@ -257,13 +262,51 @@ export class MemoryIndexManager {
257
262
  return this.syncing;
258
263
  }
259
264
  async readFile(params) {
260
- const relPath = normalizeRelPath(params.relPath);
261
- if (!relPath || !isMemoryPath(relPath)) {
265
+ const rawPath = params.relPath.trim();
266
+ if (!rawPath) {
262
267
  throw new Error("path required");
263
268
  }
264
- const absPath = path.resolve(this.workspaceDir, relPath);
265
- if (!absPath.startsWith(this.workspaceDir)) {
266
- throw new Error("path escapes workspace");
269
+ const absPath = path.isAbsolute(rawPath)
270
+ ? path.resolve(rawPath)
271
+ : path.resolve(this.workspaceDir, rawPath);
272
+ const relPath = path.relative(this.workspaceDir, absPath).replace(/\\/g, "/");
273
+ const inWorkspace = relPath.length > 0 && !relPath.startsWith("..") && !path.isAbsolute(relPath);
274
+ const allowedWorkspace = inWorkspace && isMemoryPath(relPath);
275
+ let allowedAdditional = false;
276
+ if (!allowedWorkspace && this.settings.extraPaths.length > 0) {
277
+ const additionalPaths = normalizeExtraMemoryPaths(this.workspaceDir, this.settings.extraPaths);
278
+ for (const additionalPath of additionalPaths) {
279
+ try {
280
+ const stat = await fs.lstat(additionalPath);
281
+ if (stat.isSymbolicLink()) {
282
+ continue;
283
+ }
284
+ if (stat.isDirectory()) {
285
+ if (absPath === additionalPath || absPath.startsWith(`${additionalPath}${path.sep}`)) {
286
+ allowedAdditional = true;
287
+ break;
288
+ }
289
+ continue;
290
+ }
291
+ if (stat.isFile()) {
292
+ if (absPath === additionalPath && absPath.endsWith(".md")) {
293
+ allowedAdditional = true;
294
+ break;
295
+ }
296
+ }
297
+ }
298
+ catch { }
299
+ }
300
+ }
301
+ if (!allowedWorkspace && !allowedAdditional) {
302
+ throw new Error("path required");
303
+ }
304
+ if (!absPath.endsWith(".md")) {
305
+ throw new Error("path required");
306
+ }
307
+ const stat = await fs.lstat(absPath);
308
+ if (stat.isSymbolicLink() || !stat.isFile()) {
309
+ throw new Error("path required");
267
310
  }
268
311
  const content = await fs.readFile(absPath, "utf-8");
269
312
  if (!params.from && !params.lines) {
@@ -307,18 +350,20 @@ export class MemoryIndexManager {
307
350
  entry.chunks = row.c ?? 0;
308
351
  bySource.set(row.source, entry);
309
352
  }
310
- return sources.map((source) => ({ source, ...bySource.get(source) }));
353
+ return sources.map((source) => Object.assign({ source }, bySource.get(source)));
311
354
  })();
312
355
  return {
356
+ backend: "builtin",
313
357
  files: files?.c ?? 0,
314
358
  chunks: chunks?.c ?? 0,
315
- dirty: this.dirty,
359
+ dirty: this.dirty || this.sessionsDirty,
316
360
  workspaceDir: this.workspaceDir,
317
361
  dbPath: this.settings.store.path,
318
362
  provider: this.provider.id,
319
363
  model: this.provider.model,
320
364
  requestedProvider: this.requestedProvider,
321
365
  sources: Array.from(this.sources),
366
+ extraPaths: this.settings.extraPaths,
322
367
  sourceCounts,
323
368
  cache: this.cache.enabled
324
369
  ? {
@@ -559,13 +604,27 @@ export class MemoryIndexManager {
559
604
  }
560
605
  }
561
606
  ensureWatcher() {
562
- if (!this.sources.has("memory") || !this.settings.sync.watch || this.watcher)
607
+ if (!this.sources.has("memory") || !this.settings.sync.watch || this.watcher) {
563
608
  return;
564
- const watchPaths = [
609
+ }
610
+ const additionalPaths = normalizeExtraMemoryPaths(this.workspaceDir, this.settings.extraPaths)
611
+ .map((entry) => {
612
+ try {
613
+ const stat = fsSync.lstatSync(entry);
614
+ return stat.isSymbolicLink() ? null : entry;
615
+ }
616
+ catch {
617
+ return null;
618
+ }
619
+ })
620
+ .filter((entry) => Boolean(entry));
621
+ const watchPaths = new Set([
565
622
  path.join(this.workspaceDir, "MEMORY.md"),
623
+ path.join(this.workspaceDir, "memory.md"),
566
624
  path.join(this.workspaceDir, "memory"),
567
- ];
568
- this.watcher = chokidar.watch(watchPaths, {
625
+ ...additionalPaths,
626
+ ]);
627
+ this.watcher = chokidar.watch(Array.from(watchPaths), {
569
628
  ignoreInitial: true,
570
629
  awaitWriteFinish: {
571
630
  stabilityThreshold: this.settings.sync.watchDebounceMs,
@@ -764,7 +823,7 @@ export class MemoryIndexManager {
764
823
  return this.sessionsDirty && this.sessionsDirtyFiles.size > 0;
765
824
  }
766
825
  async syncMemoryFiles(params) {
767
- const files = await listMemoryFiles(this.workspaceDir);
826
+ const files = await listMemoryFiles(this.workspaceDir, this.settings.extraPaths);
768
827
  const fileEntries = await Promise.all(files.map(async (file) => buildFileEntry(file, this.workspaceDir)));
769
828
  log.debug("memory sync: indexing memory files", {
770
829
  files: fileEntries.length,
@@ -804,7 +863,7 @@ export class MemoryIndexManager {
804
863
  });
805
864
  }
806
865
  });
807
- await this.runWithConcurrency(tasks, this.getIndexConcurrency());
866
+ await runWithConcurrency(tasks, this.getIndexConcurrency());
808
867
  const staleRows = this.db
809
868
  .prepare(`SELECT path FROM files WHERE source = ?`)
810
869
  .all("memory");
@@ -894,7 +953,7 @@ export class MemoryIndexManager {
894
953
  });
895
954
  }
896
955
  });
897
- await this.runWithConcurrency(tasks, this.getIndexConcurrency());
956
+ await runWithConcurrency(tasks, this.getIndexConcurrency());
898
957
  const staleRows = this.db
899
958
  .prepare(`SELECT path FROM files WHERE source = ?`)
900
959
  .all("sessions");
@@ -1010,7 +1069,8 @@ export class MemoryIndexManager {
1010
1069
  const batch = this.settings.remote?.batch;
1011
1070
  const enabled = Boolean(batch?.enabled &&
1012
1071
  ((this.openAi && this.provider.id === "openai") ||
1013
- (this.gemini && this.provider.id === "gemini")));
1072
+ (this.gemini && this.provider.id === "gemini") ||
1073
+ (this.voyage && this.provider.id === "voyage")));
1014
1074
  return {
1015
1075
  enabled,
1016
1076
  wait: batch?.wait ?? true,
@@ -1030,7 +1090,9 @@ export class MemoryIndexManager {
1030
1090
  ? DEFAULT_GEMINI_EMBEDDING_MODEL
1031
1091
  : fallback === "openai"
1032
1092
  ? DEFAULT_OPENAI_EMBEDDING_MODEL
1033
- : this.settings.model;
1093
+ : fallback === "voyage"
1094
+ ? DEFAULT_VOYAGE_EMBEDDING_MODEL
1095
+ : this.settings.model;
1034
1096
  const fallbackResult = await createEmbeddingProvider({
1035
1097
  config: this.cfg,
1036
1098
  agentDir: resolveAgentDir(this.cfg, this.agentId),
@@ -1045,6 +1107,7 @@ export class MemoryIndexManager {
1045
1107
  this.provider = fallbackResult.provider;
1046
1108
  this.openAi = fallbackResult.openAi;
1047
1109
  this.gemini = fallbackResult.gemini;
1110
+ this.voyage = fallbackResult.voyage;
1048
1111
  this.providerKey = this.computeProviderKey();
1049
1112
  this.batch = this.resolveBatchConfig();
1050
1113
  log.warn(`memory embeddings: switched to fallback provider (${fallback})`, { reason });
@@ -1401,7 +1464,7 @@ export class MemoryIndexManager {
1401
1464
  if (this.provider.id === "openai" && this.openAi) {
1402
1465
  const entries = Object.entries(this.openAi.headers)
1403
1466
  .filter(([key]) => key.toLowerCase() !== "authorization")
1404
- .sort(([a], [b]) => a.localeCompare(b))
1467
+ .toSorted(([a], [b]) => a.localeCompare(b))
1405
1468
  .map(([key, value]) => [key, value]);
1406
1469
  return hashText(JSON.stringify({
1407
1470
  provider: "openai",
@@ -1416,7 +1479,7 @@ export class MemoryIndexManager {
1416
1479
  const lower = key.toLowerCase();
1417
1480
  return lower !== "authorization" && lower !== "x-goog-api-key";
1418
1481
  })
1419
- .sort(([a], [b]) => a.localeCompare(b))
1482
+ .toSorted(([a], [b]) => a.localeCompare(b))
1420
1483
  .map(([key, value]) => [key, value]);
1421
1484
  return hashText(JSON.stringify({
1422
1485
  provider: "gemini",
@@ -1434,8 +1497,78 @@ export class MemoryIndexManager {
1434
1497
  if (this.provider.id === "gemini" && this.gemini) {
1435
1498
  return this.embedChunksWithGeminiBatch(chunks, entry, source);
1436
1499
  }
1500
+ if (this.provider.id === "voyage" && this.voyage) {
1501
+ return this.embedChunksWithVoyageBatch(chunks, entry, source);
1502
+ }
1437
1503
  return this.embedChunksInBatches(chunks);
1438
1504
  }
1505
+ async embedChunksWithVoyageBatch(chunks, entry, source) {
1506
+ const voyage = this.voyage;
1507
+ if (!voyage) {
1508
+ return this.embedChunksInBatches(chunks);
1509
+ }
1510
+ if (chunks.length === 0) {
1511
+ return [];
1512
+ }
1513
+ const cached = this.loadEmbeddingCache(chunks.map((chunk) => chunk.hash));
1514
+ const embeddings = Array.from({ length: chunks.length }, () => []);
1515
+ const missing = [];
1516
+ for (let i = 0; i < chunks.length; i += 1) {
1517
+ const chunk = chunks[i];
1518
+ const hit = chunk?.hash ? cached.get(chunk.hash) : undefined;
1519
+ if (hit && hit.length > 0) {
1520
+ embeddings[i] = hit;
1521
+ }
1522
+ else if (chunk) {
1523
+ missing.push({ index: i, chunk });
1524
+ }
1525
+ }
1526
+ if (missing.length === 0) {
1527
+ return embeddings;
1528
+ }
1529
+ const requests = [];
1530
+ const mapping = new Map();
1531
+ for (const item of missing) {
1532
+ const chunk = item.chunk;
1533
+ const customId = hashText(`${source}:${entry.path}:${chunk.startLine}:${chunk.endLine}:${chunk.hash}:${item.index}`);
1534
+ mapping.set(customId, { index: item.index, hash: chunk.hash });
1535
+ requests.push({
1536
+ custom_id: customId,
1537
+ body: {
1538
+ input: chunk.text,
1539
+ },
1540
+ });
1541
+ }
1542
+ const batchResult = await this.runBatchWithFallback({
1543
+ provider: "voyage",
1544
+ run: async () => await runVoyageEmbeddingBatches({
1545
+ client: voyage,
1546
+ agentId: this.agentId,
1547
+ requests,
1548
+ wait: this.batch.wait,
1549
+ concurrency: this.batch.concurrency,
1550
+ pollIntervalMs: this.batch.pollIntervalMs,
1551
+ timeoutMs: this.batch.timeoutMs,
1552
+ debug: (message, data) => log.debug(message, { ...data, source, chunks: chunks.length }),
1553
+ }),
1554
+ fallback: async () => await this.embedChunksInBatches(chunks),
1555
+ });
1556
+ if (Array.isArray(batchResult)) {
1557
+ return batchResult;
1558
+ }
1559
+ const byCustomId = batchResult;
1560
+ const toCache = [];
1561
+ for (const [customId, embedding] of byCustomId.entries()) {
1562
+ const mapped = mapping.get(customId);
1563
+ if (!mapped) {
1564
+ continue;
1565
+ }
1566
+ embeddings[mapped.index] = embedding;
1567
+ toCache.push({ hash: mapped.hash, embedding });
1568
+ }
1569
+ this.upsertEmbeddingCache(toCache);
1570
+ return embeddings;
1571
+ }
1439
1572
  async embedChunksWithOpenAiBatch(chunks, entry, source) {
1440
1573
  const openAi = this.openAi;
1441
1574
  if (!openAi) {
@@ -1622,35 +1755,6 @@ export class MemoryIndexManager {
1622
1755
  clearTimeout(timer);
1623
1756
  }
1624
1757
  }
1625
- async runWithConcurrency(tasks, limit) {
1626
- if (tasks.length === 0)
1627
- return [];
1628
- const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));
1629
- const results = Array.from({ length: tasks.length });
1630
- let next = 0;
1631
- let firstError = null;
1632
- const workers = Array.from({ length: resolvedLimit }, async () => {
1633
- while (true) {
1634
- if (firstError)
1635
- return;
1636
- const index = next;
1637
- next += 1;
1638
- if (index >= tasks.length)
1639
- return;
1640
- try {
1641
- results[index] = await tasks[index]();
1642
- }
1643
- catch (err) {
1644
- firstError = err;
1645
- return;
1646
- }
1647
- }
1648
- });
1649
- await Promise.allSettled(workers);
1650
- if (firstError)
1651
- throw firstError;
1652
- return results;
1653
- }
1654
1758
  async withBatchFailureLock(fn) {
1655
1759
  let release;
1656
1760
  const wait = this.batchFailureLock;
@@ -1748,6 +1852,9 @@ export class MemoryIndexManager {
1748
1852
  async indexFile(entry, options) {
1749
1853
  const content = options.content ?? (await fs.readFile(entry.absPath, "utf-8"));
1750
1854
  const chunks = chunkMarkdown(content, this.settings.chunking).filter((chunk) => chunk.text.trim().length > 0);
1855
+ if (options.source === "sessions" && "lineMap" in entry) {
1856
+ remapChunkLines(chunks, entry.lineMap);
1857
+ }
1751
1858
  const embeddings = this.batch.enabled
1752
1859
  ? await this.embedChunksWithBatch(chunks, entry, options.source)
1753
1860
  : await this.embedChunksInBatches(chunks);
@@ -1,4 +1,40 @@
1
+ import { createSubsystemLogger } from "../logging/subsystem.js";
2
+ import { resolveMemoryBackendConfig } from "./backend-config.js";
3
+ const log = createSubsystemLogger("memory");
4
+ const QMD_MANAGER_CACHE = new Map();
1
5
  export async function getMemorySearchManager(params) {
6
+ const resolved = resolveMemoryBackendConfig(params);
7
+ if (resolved.backend === "qmd" && resolved.qmd) {
8
+ const cacheKey = buildQmdCacheKey(params.agentId, resolved.qmd);
9
+ const cached = QMD_MANAGER_CACHE.get(cacheKey);
10
+ if (cached) {
11
+ return { manager: cached };
12
+ }
13
+ try {
14
+ // @ts-expect-error qmd-manager is an optional module that may not exist at build time
15
+ const { QmdMemoryManager } = await import("./qmd-manager.js");
16
+ const primary = await QmdMemoryManager.create({
17
+ cfg: params.cfg,
18
+ agentId: params.agentId,
19
+ resolved,
20
+ });
21
+ if (primary) {
22
+ const wrapper = new FallbackMemoryManager({
23
+ primary,
24
+ fallbackFactory: async () => {
25
+ const { MemoryIndexManager } = await import("./manager.js");
26
+ return await MemoryIndexManager.get(params);
27
+ },
28
+ }, () => QMD_MANAGER_CACHE.delete(cacheKey));
29
+ QMD_MANAGER_CACHE.set(cacheKey, wrapper);
30
+ return { manager: wrapper };
31
+ }
32
+ }
33
+ catch (err) {
34
+ const message = err instanceof Error ? err.message : String(err);
35
+ log.warn(`qmd memory unavailable; falling back to builtin: ${message}`);
36
+ }
37
+ }
2
38
  try {
3
39
  const { MemoryIndexManager } = await import("./manager.js");
4
40
  const manager = await MemoryIndexManager.get(params);
@@ -9,3 +45,140 @@ export async function getMemorySearchManager(params) {
9
45
  return { manager: null, error: message };
10
46
  }
11
47
  }
48
+ class FallbackMemoryManager {
49
+ deps;
50
+ onClose;
51
+ fallback = null;
52
+ primaryFailed = false;
53
+ lastError;
54
+ cacheEvicted = false;
55
+ constructor(deps, onClose) {
56
+ this.deps = deps;
57
+ this.onClose = onClose;
58
+ }
59
+ async search(query, opts) {
60
+ if (!this.primaryFailed) {
61
+ try {
62
+ return await this.deps.primary.search(query, opts);
63
+ }
64
+ catch (err) {
65
+ this.primaryFailed = true;
66
+ this.lastError = err instanceof Error ? err.message : String(err);
67
+ log.warn(`qmd memory failed; switching to builtin index: ${this.lastError}`);
68
+ await this.deps.primary.close?.().catch(() => { });
69
+ // Evict the failed wrapper so the next request can retry QMD with a fresh manager.
70
+ this.evictCacheEntry();
71
+ }
72
+ }
73
+ const fallback = await this.ensureFallback();
74
+ if (fallback) {
75
+ return await fallback.search(query, opts);
76
+ }
77
+ throw new Error(this.lastError ?? "memory search unavailable");
78
+ }
79
+ async readFile(params) {
80
+ if (!this.primaryFailed) {
81
+ return await this.deps.primary.readFile(params);
82
+ }
83
+ const fallback = await this.ensureFallback();
84
+ if (fallback) {
85
+ return await fallback.readFile(params);
86
+ }
87
+ throw new Error(this.lastError ?? "memory read unavailable");
88
+ }
89
+ status() {
90
+ if (!this.primaryFailed) {
91
+ return this.deps.primary.status();
92
+ }
93
+ const fallbackStatus = this.fallback?.status();
94
+ const fallbackInfo = { from: "qmd", reason: this.lastError ?? "unknown" };
95
+ if (fallbackStatus) {
96
+ const custom = fallbackStatus.custom ?? {};
97
+ return {
98
+ ...fallbackStatus,
99
+ fallback: fallbackInfo,
100
+ custom: {
101
+ ...custom,
102
+ fallback: { disabled: true, reason: this.lastError ?? "unknown" },
103
+ },
104
+ };
105
+ }
106
+ const primaryStatus = this.deps.primary.status();
107
+ const custom = primaryStatus.custom ?? {};
108
+ return {
109
+ ...primaryStatus,
110
+ fallback: fallbackInfo,
111
+ custom: {
112
+ ...custom,
113
+ fallback: { disabled: true, reason: this.lastError ?? "unknown" },
114
+ },
115
+ };
116
+ }
117
+ async sync(params) {
118
+ if (!this.primaryFailed) {
119
+ await this.deps.primary.sync?.(params);
120
+ return;
121
+ }
122
+ const fallback = await this.ensureFallback();
123
+ await fallback?.sync?.(params);
124
+ }
125
+ async probeEmbeddingAvailability() {
126
+ if (!this.primaryFailed) {
127
+ return await this.deps.primary.probeEmbeddingAvailability();
128
+ }
129
+ const fallback = await this.ensureFallback();
130
+ if (fallback) {
131
+ return await fallback.probeEmbeddingAvailability();
132
+ }
133
+ return { ok: false, error: this.lastError ?? "memory embeddings unavailable" };
134
+ }
135
+ async probeVectorAvailability() {
136
+ if (!this.primaryFailed) {
137
+ return await this.deps.primary.probeVectorAvailability();
138
+ }
139
+ const fallback = await this.ensureFallback();
140
+ return (await fallback?.probeVectorAvailability()) ?? false;
141
+ }
142
+ async close() {
143
+ await this.deps.primary.close?.();
144
+ await this.fallback?.close?.();
145
+ this.evictCacheEntry();
146
+ }
147
+ async ensureFallback() {
148
+ if (this.fallback) {
149
+ return this.fallback;
150
+ }
151
+ const fallback = await this.deps.fallbackFactory();
152
+ if (!fallback) {
153
+ log.warn("memory fallback requested but builtin index is unavailable");
154
+ return null;
155
+ }
156
+ this.fallback = fallback;
157
+ return this.fallback;
158
+ }
159
+ evictCacheEntry() {
160
+ if (this.cacheEvicted) {
161
+ return;
162
+ }
163
+ this.cacheEvicted = true;
164
+ this.onClose?.();
165
+ }
166
+ }
167
+ function buildQmdCacheKey(agentId, config) {
168
+ return `${agentId}:${stableSerialize(config)}`;
169
+ }
170
+ function stableSerialize(value) {
171
+ return JSON.stringify(sortValue(value));
172
+ }
173
+ function sortValue(value) {
174
+ if (Array.isArray(value)) {
175
+ return value.map((entry) => sortValue(entry));
176
+ }
177
+ if (value && typeof value === "object") {
178
+ const sortedEntries = Object.keys(value)
179
+ .toSorted((a, b) => a.localeCompare(b))
180
+ .map((key) => [key, sortValue(value[key])]);
181
+ return Object.fromEntries(sortedEntries);
182
+ }
183
+ return value;
184
+ }