@vellumai/assistant 0.10.12 → 0.11.0-staging.2

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 (809) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +4 -5
  3. package/README.md +1 -1
  4. package/docs/architecture/memory.md +60 -23
  5. package/docs/error-handling.md +3 -3
  6. package/docs/guardian-request-flow.md +112 -0
  7. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts +28 -0
  13. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
  14. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts +2 -2
  15. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
  16. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.js.map +1 -1
  17. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts +2 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
  19. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/package.json +1 -1
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  25. package/node_modules/@vellumai/gateway-client/package.json +1 -1
  26. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +6 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +34 -0
  28. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  29. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  30. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  31. package/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  32. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  33. package/openapi.yaml +264 -14
  34. package/package.json +2 -2
  35. package/src/__tests__/acp-session.test.ts +3 -3
  36. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +3 -0
  37. package/src/__tests__/anthropic-provider.test.ts +40 -0
  38. package/src/__tests__/app-conversation-ids-backfill.test.ts +33 -2
  39. package/src/__tests__/app-conversation-ids.test.ts +204 -0
  40. package/src/__tests__/approval-cascade.test.ts +5 -5
  41. package/src/__tests__/approval-routes-http.test.ts +3 -3
  42. package/src/__tests__/ask-question-resolver.test.ts +207 -0
  43. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
  44. package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
  45. package/src/__tests__/assistant-event-hub.test.ts +13 -11
  46. package/src/__tests__/assistant-event.test.ts +12 -9
  47. package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
  48. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
  49. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
  50. package/src/__tests__/assistant-stream-state.test.ts +17 -7
  51. package/src/__tests__/avatar-identity-sync.test.ts +3 -3
  52. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  53. package/src/__tests__/call-conversation-messages.test.ts +134 -18
  54. package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
  55. package/src/__tests__/channel-approvals.test.ts +0 -27
  56. package/src/__tests__/channel-guardian.test.ts +85 -512
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
  58. package/src/__tests__/channel-retry-sweep.test.ts +88 -1
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
  60. package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
  61. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  62. package/src/__tests__/compaction-events.test.ts +8 -8
  63. package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
  64. package/src/__tests__/config-model-image-provider.test.ts +20 -0
  65. package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
  66. package/src/__tests__/config-schema.test.ts +14 -2
  67. package/src/__tests__/config-set-platform-guard.test.ts +11 -12
  68. package/src/__tests__/config-sounds-sync.test.ts +4 -4
  69. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
  70. package/src/__tests__/context-search-memory-source.test.ts +1 -1
  71. package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
  72. package/src/__tests__/context-token-estimator.test.ts +54 -1
  73. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
  74. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
  75. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
  76. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
  77. package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
  78. package/src/__tests__/conversation-agent-loop.test.ts +39 -30
  79. package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
  80. package/src/__tests__/conversation-evictor.test.ts +49 -0
  81. package/src/__tests__/conversation-fork-crud.test.ts +1 -1
  82. package/src/__tests__/conversation-group-tools.test.ts +279 -0
  83. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  84. package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
  85. package/src/__tests__/conversation-lineage.test.ts +235 -0
  86. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
  87. package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
  88. package/src/__tests__/conversation-queue.test.ts +81 -81
  89. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
  90. package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
  91. package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
  92. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
  93. package/src/__tests__/conversation-slash-queue.test.ts +11 -11
  94. package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
  95. package/src/__tests__/conversation-speed-override.test.ts +2 -2
  96. package/src/__tests__/conversation-summarize-route.test.ts +9 -0
  97. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
  98. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
  99. package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
  100. package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
  101. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
  102. package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
  103. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  104. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
  105. package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
  106. package/src/__tests__/conversation-sync-tags.test.ts +5 -5
  107. package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
  108. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  109. package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
  110. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
  111. package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
  112. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  113. package/src/__tests__/daemon-assistant-events.test.ts +14 -15
  114. package/src/__tests__/db-test-helpers.ts +13 -27
  115. package/src/__tests__/disk-pressure-routes.test.ts +12 -3
  116. package/src/__tests__/document-tool-security.test.ts +95 -0
  117. package/src/__tests__/drain-kick-guard.test.ts +232 -0
  118. package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
  119. package/src/__tests__/emit-event-signal.test.ts +5 -6
  120. package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
  121. package/src/__tests__/events-tail-route.test.ts +6 -4
  122. package/src/__tests__/feature-flag-test-helpers.ts +10 -20
  123. package/src/__tests__/file-edit-tool.test.ts +24 -4
  124. package/src/__tests__/file-list-tool.test.ts +2 -1
  125. package/src/__tests__/file-read-tool.test.ts +62 -10
  126. package/src/__tests__/file-write-tool.test.ts +24 -5
  127. package/src/__tests__/followup-tools.test.ts +58 -0
  128. package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
  129. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  130. package/src/__tests__/guardian-question-mode.test.ts +42 -3
  131. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
  132. package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
  133. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  134. package/src/__tests__/heartbeat-service.test.ts +1 -0
  135. package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
  136. package/src/__tests__/host-browser-proxy.test.ts +1 -1
  137. package/src/__tests__/host-file-edit-tool.test.ts +3 -3
  138. package/src/__tests__/host-file-read-tool.test.ts +2 -2
  139. package/src/__tests__/host-file-write-tool.test.ts +7 -3
  140. package/src/__tests__/host-shell-tool.test.ts +17 -5
  141. package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
  142. package/src/__tests__/image-credentials.test.ts +65 -8
  143. package/src/__tests__/injection-block.test.ts +4 -4
  144. package/src/__tests__/injector-chain.test.ts +1 -1
  145. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  146. package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
  147. package/src/__tests__/injector-v3-suppression.test.ts +6 -4
  148. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
  149. package/src/__tests__/list-messages-page-latest.test.ts +2 -2
  150. package/src/__tests__/llm-usage-store.test.ts +67 -4
  151. package/src/__tests__/log-redact.test.ts +18 -0
  152. package/src/__tests__/managed-profile-guard.test.ts +27 -0
  153. package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
  154. package/src/__tests__/media-generate-image.test.ts +62 -11
  155. package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
  156. package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
  157. package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
  158. package/src/__tests__/notification-decision-strategy.test.ts +115 -11
  159. package/src/__tests__/notification-deep-link.test.ts +12 -12
  160. package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
  161. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  162. package/src/__tests__/path-policy.test.ts +315 -0
  163. package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
  164. package/src/__tests__/persistence-layering-guard.test.ts +2 -2
  165. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  166. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
  167. package/src/__tests__/platform-callback-registration.test.ts +10 -10
  168. package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
  169. package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
  170. package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
  171. package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
  172. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  173. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
  174. package/src/__tests__/require-fresh-approval.test.ts +38 -38
  175. package/src/__tests__/resolve-app-id.test.ts +32 -0
  176. package/src/__tests__/run-due-schedules.test.ts +72 -1
  177. package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
  178. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  179. package/src/__tests__/schedule-routes.test.ts +44 -5
  180. package/src/__tests__/schedule-store.test.ts +3 -3
  181. package/src/__tests__/schedule-tools.test.ts +176 -0
  182. package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
  183. package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
  184. package/src/__tests__/secret-response-routing.test.ts +3 -3
  185. package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
  186. package/src/__tests__/secret-scanner.test.ts +36 -0
  187. package/src/__tests__/send-endpoint-busy.test.ts +7 -7
  188. package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
  189. package/src/__tests__/starter-task-flow.test.ts +26 -3
  190. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  191. package/src/__tests__/subagent-disposal.test.ts +40 -11
  192. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  193. package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
  194. package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
  195. package/src/__tests__/subagent-manager-notify.test.ts +73 -14
  196. package/src/__tests__/subagent-notify-parent.test.ts +48 -4
  197. package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
  198. package/src/__tests__/subagent-tools.test.ts +64 -0
  199. package/src/__tests__/sync-message-contract.test.ts +3 -3
  200. package/src/__tests__/terminal-tools.test.ts +12 -3
  201. package/src/__tests__/test-preload.ts +9 -0
  202. package/src/__tests__/tool-approval-handler.test.ts +587 -43
  203. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
  204. package/src/__tests__/tool-executor.test.ts +116 -0
  205. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
  206. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
  207. package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
  208. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  209. package/src/__tests__/tool-start-timestamp.test.ts +4 -4
  210. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
  211. package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
  212. package/src/__tests__/ui-work-result-surface.test.ts +3 -3
  213. package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
  214. package/src/__tests__/voice-session-bridge.test.ts +44 -44
  215. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
  216. package/src/__tests__/workspace-policy.test.ts +482 -2
  217. package/src/acp/__tests__/client-handler.test.ts +3 -3
  218. package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
  219. package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
  220. package/src/acp/client-handler.ts +3 -3
  221. package/src/acp/session-manager.ts +8 -8
  222. package/src/api/events/subagent-event.ts +2 -2
  223. package/src/api/responses/memory-v2-activation-log.ts +2 -2
  224. package/src/api/responses/subagent-detail.ts +13 -0
  225. package/src/approvals/AGENTS.md +2 -0
  226. package/src/approvals/guardian-request-resolvers.ts +118 -24
  227. package/src/apps/app-store.ts +95 -4
  228. package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
  229. package/src/calls/__tests__/voice-session-bridge.test.ts +229 -7
  230. package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
  231. package/src/calls/call-controller.ts +27 -27
  232. package/src/calls/call-conversation-messages.ts +58 -18
  233. package/src/calls/voice-control-protocol.ts +56 -0
  234. package/src/calls/voice-session-bridge.ts +178 -65
  235. package/src/calls/voice-triage-escalate.ts +2 -3
  236. package/src/channels/config.ts +8 -0
  237. package/src/channels/types.ts +1 -0
  238. package/src/cli/commands/config.ts +49 -13
  239. package/src/cli/commands/memory/index.help.ts +4 -2
  240. package/src/cli/commands/memory/memory-retrospective.ts +5 -0
  241. package/src/cli/commands/webhooks.help.ts +9 -4
  242. package/src/cli/lib/bundled-marketplace.json +12 -0
  243. package/src/cli.ts +2 -109
  244. package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
  245. package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
  246. package/src/config/assistant-feature-flags.ts +1 -1
  247. package/src/config/bundled-skills/conversation-groups/SKILL.md +29 -0
  248. package/src/config/bundled-skills/conversation-groups/TOOLS.json +58 -0
  249. package/src/config/bundled-skills/conversation-groups/tools/group-create.ts +12 -0
  250. package/src/config/bundled-skills/conversation-groups/tools/group-list.ts +12 -0
  251. package/src/config/bundled-skills/conversation-groups/tools/move-to-group.ts +12 -0
  252. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
  253. package/src/config/bundled-skills/schedule/SKILL.md +2 -0
  254. package/src/config/feature-flag-cache.ts +6 -16
  255. package/src/config/feature-flag-registry.json +14 -38
  256. package/src/config/loader.ts +7 -1
  257. package/src/config/memory-tier.ts +15 -10
  258. package/src/config/memory-v3-gate.test.ts +278 -1
  259. package/src/config/memory-v3-gate.ts +88 -26
  260. package/src/config/raw-config-utils.ts +1 -1
  261. package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
  262. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  263. package/src/config/schemas/live-voice.ts +33 -7
  264. package/src/config/schemas/llm.ts +1 -0
  265. package/src/config/schemas/memory-retrospective.ts +13 -0
  266. package/src/config/schemas/memory-substrate.ts +183 -0
  267. package/src/config/schemas/memory-v2.ts +3 -2
  268. package/src/config/schemas/memory-v3.ts +11 -4
  269. package/src/config/schemas/memory.ts +35 -1
  270. package/src/config/schemas/services.ts +10 -2
  271. package/src/config/substrate-twin-shadowing.ts +195 -0
  272. package/src/config/webhook-routing.ts +67 -0
  273. package/src/context/compactor.ts +10 -3
  274. package/src/context/token-estimator.ts +21 -0
  275. package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
  276. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
  277. package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
  278. package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
  279. package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
  280. package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
  281. package/src/daemon/channel-ui-capability.ts +70 -1
  282. package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
  283. package/src/daemon/conversation-agent-loop.ts +12 -5
  284. package/src/daemon/conversation-evictor.ts +26 -4
  285. package/src/daemon/conversation-launch.ts +11 -14
  286. package/src/daemon/conversation-lineage.ts +76 -0
  287. package/src/daemon/conversation-messaging.ts +14 -14
  288. package/src/daemon/conversation-notifiers.ts +2 -2
  289. package/src/daemon/conversation-process.ts +133 -21
  290. package/src/daemon/conversation-queue-manager.ts +7 -7
  291. package/src/daemon/conversation-runtime-assembly.ts +16 -0
  292. package/src/daemon/conversation-store.ts +11 -3
  293. package/src/daemon/conversation-surfaces.ts +8 -14
  294. package/src/daemon/conversation-tool-setup.ts +13 -7
  295. package/src/daemon/conversation-usage.ts +12 -11
  296. package/src/daemon/conversation.ts +38 -15
  297. package/src/daemon/disk-pressure-guard.ts +5 -12
  298. package/src/daemon/embedding-reconcile.ts +14 -9
  299. package/src/daemon/handlers/config-channels.ts +40 -134
  300. package/src/daemon/handlers/config-model.ts +15 -7
  301. package/src/daemon/handlers/conversations.ts +4 -2
  302. package/src/daemon/handlers/shared.ts +29 -0
  303. package/src/daemon/host-proxy-base.ts +4 -4
  304. package/src/daemon/lifecycle.ts +13 -0
  305. package/src/daemon/message-protocol.ts +8 -144
  306. package/src/daemon/message-types/computer-use.ts +0 -12
  307. package/src/daemon/message-types/conversations.ts +9 -345
  308. package/src/daemon/message-types/host-app-control.ts +0 -9
  309. package/src/daemon/message-types/host-browser.ts +0 -7
  310. package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
  311. package/src/daemon/message-types/messages.ts +0 -48
  312. package/src/daemon/message-types/notifications.ts +0 -7
  313. package/src/daemon/message-types/skills.ts +0 -5
  314. package/src/daemon/message-types/surfaces.ts +0 -9
  315. package/src/daemon/message-types/sync.ts +0 -2
  316. package/src/daemon/process-message.ts +5 -5
  317. package/src/daemon/skill-memory-refresh.ts +5 -5
  318. package/src/daemon/tool-side-effects.ts +32 -16
  319. package/src/daemon/trust-context.ts +1 -1
  320. package/src/daemon/wake-conversation-ops.ts +4 -4
  321. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
  322. package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
  323. package/src/heartbeat/heartbeat-run-store.ts +81 -4
  324. package/src/heartbeat/heartbeat-service.ts +32 -1
  325. package/src/home/__tests__/feed-writer.test.ts +7 -7
  326. package/src/home/__tests__/home-content-refresh.test.ts +3 -0
  327. package/src/home/__tests__/suggested-prompts.test.ts +1 -0
  328. package/src/home/feed-writer.ts +6 -13
  329. package/src/home/home-content-refresh.ts +6 -9
  330. package/src/home/relationship-state-writer.ts +5 -12
  331. package/src/home/suggested-prompts-cache.ts +6 -19
  332. package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
  333. package/src/ipc/events-publish-client.ts +44 -0
  334. package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
  335. package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
  336. package/src/ipc/routes/events-ipc-routes.ts +11 -31
  337. package/src/live-voice/__tests__/front-decision.test.ts +4 -176
  338. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
  339. package/src/live-voice/__tests__/live-voice-continuation-fork-hydration.test.ts +286 -0
  340. package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
  341. package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
  342. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
  343. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
  344. package/src/live-voice/__tests__/live-voice-vad.test.ts +1154 -636
  345. package/src/live-voice/front-decision.ts +5 -155
  346. package/src/live-voice/live-voice-metrics.ts +4 -1
  347. package/src/live-voice/live-voice-session.ts +1288 -439
  348. package/src/live-voice/progress-phrases.ts +17 -0
  349. package/src/live-voice/protocol.ts +15 -0
  350. package/src/media/app-icon-generator.ts +15 -8
  351. package/src/media/avatar-router.ts +9 -5
  352. package/src/media/image-credentials.ts +42 -10
  353. package/src/media/image-service.ts +1 -13
  354. package/src/media/types.ts +26 -3
  355. package/src/notifications/AGENTS.md +2 -0
  356. package/src/notifications/__tests__/broadcaster.test.ts +95 -0
  357. package/src/notifications/adapters/macos.ts +3 -3
  358. package/src/notifications/broadcaster.ts +57 -0
  359. package/src/notifications/copy-composer.ts +0 -15
  360. package/src/notifications/decision-engine.ts +21 -22
  361. package/src/notifications/guardian-question-mode.ts +57 -2
  362. package/src/notifications/home-feed-side-effect.ts +4 -0
  363. package/src/notifications/signal.ts +6 -4
  364. package/src/notifications/trusted-contact-payloads.ts +3 -4
  365. package/src/notifications/vellum-card-affinity.ts +39 -0
  366. package/src/oauth/AGENTS.md +1 -1
  367. package/src/permissions/channel-permission-query.test.ts +69 -0
  368. package/src/permissions/channel-permission-query.ts +73 -1
  369. package/src/permissions/checker.test.ts +298 -15
  370. package/src/permissions/checker.ts +102 -36
  371. package/src/permissions/confirmation-guardian-request.test.ts +2 -2
  372. package/src/permissions/confirmation-guardian-request.ts +2 -2
  373. package/src/permissions/gateway-threshold-reader.test.ts +224 -17
  374. package/src/permissions/gateway-threshold-reader.ts +82 -10
  375. package/src/permissions/ipc-risk-types.ts +8 -0
  376. package/src/permissions/prompter.ts +5 -5
  377. package/src/permissions/question-guardian-request.test.ts +222 -0
  378. package/src/permissions/question-guardian-request.ts +179 -0
  379. package/src/permissions/question-prompter.test.ts +8 -8
  380. package/src/permissions/question-prompter.ts +18 -0
  381. package/src/permissions/secret-prompter.ts +2 -4
  382. package/src/permissions/workspace-policy.ts +269 -34
  383. package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
  384. package/src/persistence/__tests__/message-content-file.test.ts +58 -3
  385. package/src/persistence/conversation-crud.ts +93 -0
  386. package/src/persistence/conversation-key-store.ts +63 -0
  387. package/src/persistence/conversation-parent.ts +27 -0
  388. package/src/persistence/db-async-query.ts +1 -1
  389. package/src/persistence/db-singleton.ts +14 -27
  390. package/src/persistence/delivery-crud.ts +45 -0
  391. package/src/persistence/embeddings/embedding-backend.ts +2 -1
  392. package/src/persistence/embeddings/embedding-identity.ts +7 -3
  393. package/src/persistence/job-utils.ts +32 -27
  394. package/src/persistence/jobs-store.ts +92 -3
  395. package/src/persistence/lifecycle-quiesce.ts +80 -0
  396. package/src/persistence/llm-usage-store.ts +45 -8
  397. package/src/persistence/message-content-file.ts +4 -4
  398. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
  399. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
  400. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
  401. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
  402. package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
  403. package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
  404. package/src/persistence/migrations/354-backfill-app-conversation-lineage.ts +41 -0
  405. package/src/persistence/schema/infrastructure.ts +11 -0
  406. package/src/persistence/steps.ts +9 -1
  407. package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
  408. package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
  409. package/src/plugin-api/conversation-turn.ts +4 -4
  410. package/src/plugin-api/event-hub-facade.ts +15 -6
  411. package/src/plugin-api/index.ts +10 -4
  412. package/src/plugin-api/publish-event.ts +36 -0
  413. package/src/plugins/AGENTS.md +2 -0
  414. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  415. package/src/plugins/defaults/index.ts +9 -13
  416. package/src/plugins/defaults/memory/AGENTS.md +775 -0
  417. package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
  418. package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
  419. package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
  420. package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
  421. package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
  422. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
  423. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
  424. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
  425. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
  426. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
  427. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
  428. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
  429. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  430. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
  431. package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
  432. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
  433. package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
  434. package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
  435. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
  436. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
  437. package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
  438. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
  439. package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
  440. package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
  441. package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
  442. package/src/plugins/defaults/memory/graph/store.ts +1 -0
  443. package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
  444. package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
  445. package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
  446. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
  447. package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
  448. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
  449. package/src/plugins/defaults/memory/indexer.ts +146 -89
  450. package/src/plugins/defaults/memory/injectors.ts +86 -41
  451. package/src/plugins/defaults/memory/job-handlers.ts +130 -39
  452. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
  453. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
  454. package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
  455. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
  456. package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
  457. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
  458. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
  459. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
  460. package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
  461. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
  462. package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
  463. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
  464. package/src/plugins/defaults/memory/startup.ts +58 -21
  465. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
  466. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
  467. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
  468. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
  469. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
  470. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
  471. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
  472. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
  473. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
  474. package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
  475. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
  476. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
  477. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
  478. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
  479. package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
  480. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
  481. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
  482. package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
  483. package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
  484. package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
  485. package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
  486. package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
  487. package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
  488. package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
  489. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
  490. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
  491. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
  492. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
  493. package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
  494. package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
  495. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
  496. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
  497. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
  498. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
  499. package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
  500. package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
  501. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
  502. package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
  503. package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
  504. package/src/plugins/defaults/memory/tools.test.ts +1 -1
  505. package/src/plugins/defaults/memory/tools.ts +1 -1
  506. package/src/plugins/defaults/memory/v1/README.md +5 -0
  507. package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
  508. package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
  509. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
  510. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
  511. package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
  512. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
  513. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
  514. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
  515. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
  516. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
  517. package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
  518. package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
  519. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
  520. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
  521. package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
  522. package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
  523. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
  524. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
  525. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
  526. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
  527. package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
  528. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
  529. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
  530. package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
  531. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
  532. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
  533. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
  534. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
  535. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
  536. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
  537. package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
  538. package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
  539. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
  540. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
  541. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
  542. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
  543. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
  544. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
  545. package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
  546. package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
  547. package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
  548. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
  549. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
  550. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
  551. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
  552. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  553. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  554. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
  555. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
  556. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
  557. package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
  558. package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
  559. package/src/plugins/defaults/memory/v2/activation.ts +30 -163
  560. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
  561. package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
  562. package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
  563. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
  564. package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
  565. package/src/plugins/defaults/memory/v2/injection.ts +36 -26
  566. package/src/plugins/defaults/memory/v2/migration.ts +2 -2
  567. package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
  568. package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
  569. package/src/plugins/defaults/memory/v2/router.ts +38 -15
  570. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
  571. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
  572. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
  574. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
  575. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
  576. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
  578. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
  579. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
  580. package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
  581. package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
  582. package/src/plugins/defaults/memory/v3/card.ts +25 -9
  583. package/src/plugins/defaults/memory/v3/edge.ts +52 -18
  584. package/src/plugins/defaults/memory/v3/gate.ts +4 -4
  585. package/src/plugins/defaults/memory/v3/injector.ts +10 -3
  586. package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
  587. package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
  588. package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
  589. package/src/plugins/defaults/memory/v3/prune.ts +40 -16
  590. package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
  591. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
  592. package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
  593. package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
  594. package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
  595. package/src/plugins/defaults/memory/v3/types.ts +4 -1
  596. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
  597. package/src/plugins/defaults/memory/validation.ts +1 -1
  598. package/src/plugins/defaults/memory/worker.ts +2 -1
  599. package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
  600. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
  601. package/src/plugins/types.ts +2 -2
  602. package/src/prompts/sections.ts +4 -16
  603. package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
  604. package/src/providers/anthropic/client.ts +15 -6
  605. package/src/providers/content-block-schema.ts +26 -0
  606. package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
  607. package/src/providers/inference/adapter-factory.ts +6 -0
  608. package/src/providers/inference/connections.ts +30 -14
  609. package/src/providers/model-catalog.ts +77 -0
  610. package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
  611. package/src/providers/openai/chat-completions-provider.ts +65 -17
  612. package/src/providers/openai/input-audio.ts +76 -0
  613. package/src/providers/openrouter/client.ts +0 -2
  614. package/src/providers/platform-proxy/constants.ts +4 -0
  615. package/src/providers/poolside/client.ts +42 -0
  616. package/src/providers/registry.ts +40 -8
  617. package/src/providers/retry.ts +2 -0
  618. package/src/providers/types.ts +39 -1
  619. package/src/providers/vercel-ai-gateway/client.ts +0 -2
  620. package/src/runtime/AGENTS.md +7 -5
  621. package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
  622. package/src/runtime/__tests__/question-resolution.test.ts +111 -0
  623. package/src/runtime/access-request-helper.ts +7 -15
  624. package/src/runtime/assistant-event-hub.ts +43 -31
  625. package/src/runtime/assistant-event-publish-options.ts +31 -0
  626. package/src/runtime/assistant-event.ts +19 -30
  627. package/src/runtime/assistant-stream-state.ts +4 -4
  628. package/src/runtime/channel-approvals.ts +0 -25
  629. package/src/runtime/channel-readiness-service.ts +99 -40
  630. package/src/runtime/channel-retry-sweep.ts +38 -15
  631. package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
  632. package/src/runtime/guardian-reply-router.ts +108 -0
  633. package/src/runtime/http-server.ts +8 -0
  634. package/src/runtime/http-types.ts +2 -2
  635. package/src/runtime/process-role.ts +42 -0
  636. package/src/runtime/question-request-guardian-bridge.ts +184 -0
  637. package/src/runtime/question-resolution.ts +153 -0
  638. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
  639. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
  640. package/src/runtime/routes/__tests__/subagents-routes.test.ts +250 -0
  641. package/src/runtime/routes/__tests__/webhook-routes.test.ts +201 -0
  642. package/src/runtime/routes/acp-routes.ts +2 -2
  643. package/src/runtime/routes/bookmark-routes.ts +3 -15
  644. package/src/runtime/routes/canned-message-complete.ts +2 -2
  645. package/src/runtime/routes/consolidation-routes.ts +8 -2
  646. package/src/runtime/routes/conversation-list-routes.ts +3 -19
  647. package/src/runtime/routes/conversation-management-routes.ts +1 -5
  648. package/src/runtime/routes/conversation-query-routes.ts +52 -8
  649. package/src/runtime/routes/conversation-routes.ts +36 -22
  650. package/src/runtime/routes/credential-request-routes.ts +0 -1
  651. package/src/runtime/routes/filing-routes.ts +7 -7
  652. package/src/runtime/routes/global-search-routes.ts +1 -1
  653. package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
  654. package/src/runtime/routes/image-generation-routes.ts +12 -9
  655. package/src/runtime/routes/inbound-message-handler.ts +17 -0
  656. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
  657. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
  658. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
  659. package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
  660. package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
  661. package/src/runtime/routes/index.ts +2 -0
  662. package/src/runtime/routes/lifecycle-routes.ts +199 -0
  663. package/src/runtime/routes/platform-routes.ts +3 -8
  664. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
  665. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
  666. package/src/runtime/routes/question-routes.ts +34 -87
  667. package/src/runtime/routes/secret-routes.ts +11 -1
  668. package/src/runtime/routes/settings-routes.ts +8 -18
  669. package/src/runtime/routes/subagents-routes.ts +35 -8
  670. package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
  671. package/src/runtime/routes/webhook-routes.ts +89 -30
  672. package/src/runtime/routes/workspace-routes.test.ts +7 -4
  673. package/src/runtime/slack-reply-session.test.ts +12 -12
  674. package/src/runtime/slack-reply-session.ts +17 -17
  675. package/src/runtime/sync/sync-publisher.test.ts +7 -5
  676. package/src/runtime/tool-grant-request-helper.ts +4 -0
  677. package/src/schedule/schedule-store.ts +70 -0
  678. package/src/schedule/scheduler.ts +27 -0
  679. package/src/security/AGENTS.md +1 -1
  680. package/src/security/credential-key.ts +17 -0
  681. package/src/security/secret-ingress.ts +14 -105
  682. package/src/security/secret-patterns.ts +8 -139
  683. package/src/security/secret-scanner.ts +8 -3
  684. package/src/security/store-path-override.ts +6 -16
  685. package/src/sequence/store.ts +8 -0
  686. package/src/signals/emit-event.ts +5 -10
  687. package/src/signals/event-stream.ts +20 -10
  688. package/src/subagent/manager.ts +76 -25
  689. package/src/subagent/notify.ts +8 -0
  690. package/src/subagent/types.ts +13 -3
  691. package/src/telegram/__tests__/webhook-health.test.ts +442 -0
  692. package/src/telegram/webhook-health.ts +478 -0
  693. package/src/telemetry/AGENTS.md +6 -0
  694. package/src/telemetry/memory-corpus-size.test.ts +129 -0
  695. package/src/telemetry/memory-corpus-size.ts +184 -0
  696. package/src/telemetry/memory-tier-reporter.test.ts +67 -2
  697. package/src/telemetry/memory-tier-reporter.ts +30 -3
  698. package/src/tools/__tests__/conversation-group-tool-input-schemas.test.ts +61 -0
  699. package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
  700. package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
  701. package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
  702. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
  703. package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
  704. package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
  705. package/src/tools/acp/abort.ts +21 -1
  706. package/src/tools/acp/context.ts +5 -5
  707. package/src/tools/acp/spawn.test.ts +15 -5
  708. package/src/tools/acp/spawn.ts +26 -3
  709. package/src/tools/acp/status.ts +20 -1
  710. package/src/tools/acp/steer.test.ts +20 -0
  711. package/src/tools/acp/steer.ts +23 -2
  712. package/src/tools/apps/resolve-app-id.ts +15 -3
  713. package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
  714. package/src/tools/ask-question/ask-question-tool.ts +68 -92
  715. package/src/tools/browser/browser-screencast.ts +6 -6
  716. package/src/tools/calls/call-end.ts +24 -3
  717. package/src/tools/calls/call-start.ts +35 -11
  718. package/src/tools/calls/call-status.ts +20 -1
  719. package/src/tools/conversation-groups/group_create.ts +63 -0
  720. package/src/tools/conversation-groups/group_list.ts +20 -0
  721. package/src/tools/conversation-groups/group_shared.ts +52 -0
  722. package/src/tools/conversation-groups/move_to_group.ts +106 -0
  723. package/src/tools/document/document-comment-tool.test.ts +49 -0
  724. package/src/tools/document/document-comment-tool.ts +45 -6
  725. package/src/tools/document/document-tool.ts +142 -24
  726. package/src/tools/executor.ts +27 -13
  727. package/src/tools/filesystem/edit.ts +62 -60
  728. package/src/tools/filesystem/list.ts +36 -29
  729. package/src/tools/filesystem/read.ts +56 -39
  730. package/src/tools/filesystem/write.ts +44 -38
  731. package/src/tools/followups/followup_create.ts +41 -12
  732. package/src/tools/followups/followup_list.ts +34 -6
  733. package/src/tools/followups/followup_resolve.ts +26 -4
  734. package/src/tools/host-filesystem/edit.ts +50 -60
  735. package/src/tools/host-filesystem/read.ts +45 -39
  736. package/src/tools/host-filesystem/write.ts +31 -36
  737. package/src/tools/host-terminal/host-shell.ts +76 -62
  738. package/src/tools/policy-context.ts +27 -10
  739. package/src/tools/schedule/create.ts +76 -33
  740. package/src/tools/schedule/delete.ts +21 -2
  741. package/src/tools/schedule/list.ts +25 -3
  742. package/src/tools/schedule/update.ts +105 -48
  743. package/src/tools/shared/filesystem/path-policy.ts +246 -40
  744. package/src/tools/shared/zod-tool-schema.ts +117 -0
  745. package/src/tools/subagent/abort.ts +12 -4
  746. package/src/tools/subagent/consult-deadline.ts +9 -3
  747. package/src/tools/subagent/message.ts +21 -5
  748. package/src/tools/subagent/notify-parent.ts +44 -23
  749. package/src/tools/subagent/read.ts +15 -4
  750. package/src/tools/subagent/resolve.ts +26 -4
  751. package/src/tools/subagent/spawn.ts +37 -13
  752. package/src/tools/subagent/status.ts +12 -4
  753. package/src/tools/system/request-permission.ts +35 -26
  754. package/src/tools/terminal/shell.ts +68 -55
  755. package/src/tools/tool-approval-handler.ts +327 -53
  756. package/src/tools/tool-input-schemas.ts +85 -0
  757. package/src/tools/tool-types.ts +7 -0
  758. package/src/tools/types.ts +8 -0
  759. package/src/tools/workflows/manage-workflows.ts +30 -2
  760. package/src/tools/workflows/run-workflow.test.ts +54 -2
  761. package/src/tools/workflows/run-workflow.ts +32 -4
  762. package/src/util/fs-symlinks.ts +30 -0
  763. package/src/util/log-redact.ts +7 -3
  764. package/src/util/platform.ts +15 -0
  765. package/src/vellum-assistant-namespace.d.ts +80 -0
  766. package/src/watcher/watcher-store.ts +8 -0
  767. package/src/workflows/leaf-runner.test.ts +104 -2
  768. package/src/workflows/leaf-runner.ts +31 -6
  769. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
  770. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
  771. package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
  772. package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
  773. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
  774. package/src/workspace/migrations/registry.ts +4 -0
  775. package/tsconfig.plugin-api.json +1 -1
  776. package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
  777. package/src/__tests__/secret-patterns.test.ts +0 -27
  778. package/src/config/__tests__/proc-to-skills.test.ts +0 -21
  779. package/src/config/memory-tier.test.ts +0 -44
  780. package/src/daemon/message-types/acp.ts +0 -20
  781. package/src/daemon/message-types/apps.ts +0 -11
  782. package/src/daemon/message-types/background-tools.ts +0 -14
  783. package/src/daemon/message-types/bookmarks.ts +0 -13
  784. package/src/daemon/message-types/contacts.ts +0 -13
  785. package/src/daemon/message-types/document-comments.ts +0 -14
  786. package/src/daemon/message-types/documents.ts +0 -13
  787. package/src/daemon/message-types/home.ts +0 -15
  788. package/src/daemon/message-types/host-bash.ts +0 -12
  789. package/src/daemon/message-types/host-cu.ts +0 -10
  790. package/src/daemon/message-types/host-file.ts +0 -12
  791. package/src/daemon/message-types/host-transfer.ts +0 -12
  792. package/src/daemon/message-types/integrations.ts +0 -90
  793. package/src/daemon/message-types/memory.ts +0 -10
  794. package/src/daemon/message-types/schedules.ts +0 -14
  795. package/src/daemon/message-types/settings.ts +0 -17
  796. package/src/daemon/message-types/subagents.ts +0 -63
  797. package/src/daemon/message-types/upgrades.ts +0 -14
  798. package/src/daemon/message-types/workflows.ts +0 -25
  799. package/src/daemon/message-types/workspace.ts +0 -137
  800. package/src/live-voice/ack-phrases.ts +0 -58
  801. package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
  802. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
  803. package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
  804. package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
  805. package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
  806. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  807. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
  808. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
  809. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
@@ -54,7 +54,7 @@ import {
54
54
  isInteractiveInterface,
55
55
  parseInterfaceId,
56
56
  } from "../../../channels/types.js";
57
- import { isProcToSkillsActive } from "../../../config/memory-v3-gate.js";
57
+ import { isV3TierActive } from "../../../config/memory-v3-gate.js";
58
58
  import type { AssistantConfig } from "../../../config/types.js";
59
59
  import { getGuardianDelivery } from "../../../contacts/guardian-delivery-reader.js";
60
60
  import { extractTurnContextTimestamp } from "../../../context/compactor.js";
@@ -97,6 +97,7 @@ import {
97
97
  getRetrospectiveState,
98
98
  upsertRetrospectiveState,
99
99
  } from "./memory-retrospective-state.js";
100
+ import { effectiveSweepLookbackMs } from "./memory-retrospective-sweep.js";
100
101
 
101
102
  const log = getLogger("memory-retrospective-job");
102
103
 
@@ -124,6 +125,7 @@ const MEMORY_RETROSPECTIVE_RUN_CHECK_NAME = "memory_retrospective_run";
124
125
  export type MemoryRetrospectiveOutcome =
125
126
  | { kind: "disabled" }
126
127
  | { kind: "no_new_messages" }
128
+ | { kind: "source_dormant" }
127
129
  | { kind: "source_processing" }
128
130
  | { kind: "wake_failed"; reason?: string; conversationId?: string }
129
131
  | {
@@ -170,7 +172,9 @@ export async function memoryRetrospectiveJob(
170
172
 
171
173
  let outcome: MemoryRetrospectiveOutcome;
172
174
  try {
173
- outcome = await runForkBasedRetrospective(sourceConversationId, config);
175
+ outcome = await runForkBasedRetrospective(sourceConversationId, config, {
176
+ enforceSweepLookback: true,
177
+ });
174
178
  } catch (err) {
175
179
  emitRunOutcome("error", err instanceof Error ? err.message : String(err));
176
180
  throw err;
@@ -196,6 +200,16 @@ export async function memoryRetrospectiveJob(
196
200
  export async function runForkBasedRetrospective(
197
201
  sourceConversationId: string,
198
202
  config: AssistantConfig,
203
+ opts?: {
204
+ /**
205
+ * Skip the run when the source's last message is older than
206
+ * `memory.retrospective.sweepLookbackMs`. The queue handler passes this so
207
+ * a stale pending backlog is completed as no-ops instead of run; the CLI's
208
+ * manual command omits it — an operator's explicit request overrides the
209
+ * window.
210
+ */
211
+ enforceSweepLookback?: boolean;
212
+ },
199
213
  ): Promise<MemoryRetrospectiveOutcome> {
200
214
  // Start stamp for the retrospective's end-to-end wall time, surfaced as
201
215
  // `durationMs` on the "invoked" log (start → invoked).
@@ -209,6 +223,29 @@ export async function runForkBasedRetrospective(
209
223
  return { kind: "no_new_messages" };
210
224
  }
211
225
 
226
+ // Execution-time twin of the sweep's lookback window (see
227
+ // memory-retrospective-sweep.ts). Event triggers enqueue in response to a
228
+ // just-persisted message, so a legitimately-enqueued job's source sits
229
+ // inside the window when the job runs; a numeric stamp older than the
230
+ // window means the row is stale backlog, and running it would burn an
231
+ // inference pass on a conversation the sweep no longer considers stalled.
232
+ // A missing stamp is NOT dormancy here — the enqueue itself evidences
233
+ // activity, unlike the sweep's scan where the stamp is the only signal.
234
+ // Both state pointers stay untouched.
235
+ if (opts?.enforceSweepLookback === true) {
236
+ const lastMessageAt = sourceConversation.lastMessageAt;
237
+ if (
238
+ typeof lastMessageAt === "number" &&
239
+ startedAtMs - lastMessageAt > effectiveSweepLookbackMs(config)
240
+ ) {
241
+ log.info(
242
+ { sourceConversationId, lastMessageAt },
243
+ "memory-retrospective (fork): source dormant beyond the sweep lookback; skipping",
244
+ );
245
+ return { kind: "source_dormant" };
246
+ }
247
+ }
248
+
212
249
  // Forking mid-turn would capture a half-finished display turn — incremental
213
250
  // checkpoint persistence writes complete tool turns to the DB while the
214
251
  // agent loop is still running. Check the persisted `processing_started_at`
@@ -335,7 +372,7 @@ export async function runForkBasedRetrospective(
335
372
  }
336
373
  const forkId = forkConversationRow.id;
337
374
 
338
- const procToSkillsActive = isProcToSkillsActive(config);
375
+ const procToSkillsActive = isV3TierActive(config);
339
376
  const instruction = buildForkInstruction({
340
377
  windowStartTimestamp,
341
378
  windowAnchorKind: turnContextTimestamp ? "turn_context" : "created_at",
@@ -27,6 +27,14 @@
27
27
  // (filtered in `EXCLUDED_SOURCES`).
28
28
  //
29
29
  // Cost discipline:
30
+ // - The scan is bounded to conversations whose last message falls inside
31
+ // `memory.retrospective.sweepLookbackMs`. A crash-orphaned turn is by
32
+ // definition recent, so a conversation dormant beyond the window is not
33
+ // stalled work — its unprocessed tail is an ordinary end-of-conversation
34
+ // remainder. Without this bound, the scan degenerates into a full-history
35
+ // backfill: nearly every conversation ever carries a tail past its final
36
+ // retrospective cursor, so a cold start would enqueue an inference pass
37
+ // per conversation across the entire history.
30
38
  // - The per-conversation gate skips any conversation whose last retrospective
31
39
  // attempt is newer than the sweep interval, so the sweep never competes
32
40
  // with the responsive event triggers on active conversations — it only
@@ -35,11 +43,22 @@
35
43
  // `upsertMemoryRetrospectiveJob` coalesces against any already-pending job,
36
44
  // so a conversation already queued by an event trigger is never
37
45
  // double-processed.
46
+ // - Enqueues are capped at `SWEEP_MAX_ENQUEUES_PER_PASS` per pass. Inside
47
+ // the lookback window, organic stalled work is a handful of conversations;
48
+ // a pass wanting more signals an anomalous backlog. Each pass re-scans
49
+ // from the start, so the deferred remainder is picked up by later passes.
50
+ // Sources with an already-pending retrospective job are skipped before
51
+ // the cap, so coalescing no-ops never consume it; a running job does not
52
+ // suppress the sweep (its cursor is a pre-run snapshot — a mid-run
53
+ // arrival needs a follow-up row behind it).
38
54
  // - The scan is keyset-paginated in bounded batches with a yield between
39
55
  // pages (mirrors `conversation-memory-orphan-sweep.ts`), so a large history
40
- // never materializes all ids at once or holds the event loop. Every
41
- // eligible conversation is examined each pass — there is no front-of-list
42
- // limit that could starve later conversations.
56
+ // never materializes all ids at once or holds the event loop.
57
+ //
58
+ // The retrospective job re-applies the lookback window at execution time
59
+ // (`runForkBasedRetrospective`'s `enforceSweepLookback` gate), so pending rows
60
+ // that outlive the window — e.g. a backlog drained long after enqueue — are
61
+ // completed as no-ops instead of run.
43
62
 
44
63
  import { and, asc, gt, ne, notInArray } from "drizzle-orm";
45
64
 
@@ -48,20 +67,32 @@ import { AUTO_ANALYSIS_SOURCE } from "../../../persistence/auto-analysis-constan
48
67
  import { getConversationRecentProvenanceTrustClass } from "../../../persistence/conversation-crud.js";
49
68
  import { getDb } from "../../../persistence/db-connection.js";
50
69
  import type { MemoryJob } from "../../../persistence/jobs-store.js";
51
- import { isMemoryEnabled } from "../../../persistence/jobs-store.js";
70
+ import {
71
+ isMemoryEnabled,
72
+ listPendingMemoryRetrospectiveSourceConversationIds,
73
+ } from "../../../persistence/jobs-store.js";
52
74
  import { conversations } from "../../../persistence/schema/index.js";
53
75
  import { getLogger } from "./logging.js";
54
76
  import { countRetrospectiveMessagesAfter } from "./memory-retrospective-accounting.js";
55
77
  import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
56
78
  import { enqueueMemoryRetrospectiveIfEnabled } from "./memory-retrospective-enqueue.js";
57
79
  import { getRetrospectiveState } from "./memory-retrospective-state.js";
58
- import { MEMORY_V2_CONSOLIDATION_SOURCE } from "./v3/substrate/constants.js";
80
+ import { MEMORY_V2_CONSOLIDATION_SOURCE } from "./substrate/constants.js";
59
81
 
60
82
  const log = getLogger("memory-retrospective-sweep");
61
83
 
62
84
  /** Rows per keyset-paginated page — bounds each statement and the id set held. */
63
85
  const SWEEP_BATCH = 200;
64
86
 
87
+ /**
88
+ * Hard ceiling on retrospectives enqueued by a single sweep pass. Each
89
+ * enqueue fans out an LLM inference pass, so a pass that wants more than this
90
+ * many is anomalous (organic in-window stalled work is a handful of
91
+ * conversations at most) and gets clamped with a warning. Safe to defer: every
92
+ * pass re-scans from the start, so the remainder is enqueued by later passes.
93
+ */
94
+ export const SWEEP_MAX_ENQUEUES_PER_PASS = 50;
95
+
65
96
  /**
66
97
  * Conversation `source` values excluded from the sweep up front:
67
98
  * - retrospective background conversations — recursion guard (never run a
@@ -107,15 +138,44 @@ function breathe(): Promise<void> {
107
138
  return Bun.sleep(0);
108
139
  }
109
140
 
141
+ /**
142
+ * The lookback window the sweep actually applies: never smaller than TWICE
143
+ * `sweepIntervalMs`. One interval is not enough — the pass checkpoint is
144
+ * stamped at enqueue but the cutoff is computed at execution, so tick, queue,
145
+ * and runtime delay stretch the gap between consecutive executions past the
146
+ * nominal cadence, and a message landing in that skew right after a pass
147
+ * would sit permanently outside an exact-interval window. The doubled floor
148
+ * absorbs the skew while staying BOUNDED: deriving the window from elapsed
149
+ * time since the previous pass would cover arbitrary gaps, but after
150
+ * extended downtime it would recreate the cold-start backfill this window
151
+ * exists to prevent. Outages longer than a full interval can therefore still
152
+ * leave tails outside the window — accepted by design, like the cold start.
153
+ * Shared by the sweep scan and the retrospective job's execution-time gate;
154
+ * the two must agree or the gate would kill jobs the scan legitimately
155
+ * enqueued.
156
+ */
157
+ export function effectiveSweepLookbackMs(config: AssistantConfig): number {
158
+ return Math.max(
159
+ config.memory.retrospective.sweepLookbackMs,
160
+ 2 * config.memory.retrospective.sweepIntervalMs,
161
+ );
162
+ }
163
+
110
164
  /**
111
165
  * One keyset page of sweep-eligible conversation ids past `cursor`. The empty
112
166
  * string sorts before any real id, so the first page starts at the beginning.
113
167
  * `scheduled`-type conversations are filtered here (low-yield, matching the
114
168
  * enqueue guard); other low-yield cases are caught by the enqueue itself.
169
+ *
170
+ * `lastMessageAtCutoff` bounds the scan to the sweep's lookback window
171
+ * (indexed via `idx_conversations_last_message_at`). `gt` NULL semantics
172
+ * exclude rows with no recorded message stamp: absent any evidence of recent
173
+ * activity, a conversation is not sweepable.
115
174
  */
116
175
  export function listSweepCandidateConversationIds(
117
176
  cursor: string,
118
177
  limit: number,
178
+ lastMessageAtCutoff: number,
119
179
  ): string[] {
120
180
  return getDb()
121
181
  .select({ id: conversations.id })
@@ -123,6 +183,7 @@ export function listSweepCandidateConversationIds(
123
183
  .where(
124
184
  and(
125
185
  gt(conversations.id, cursor),
186
+ gt(conversations.lastMessageAt, lastMessageAtCutoff),
126
187
  notInArray(conversations.source, EXCLUDED_SOURCES),
127
188
  ne(conversations.conversationType, "scheduled"),
128
189
  ),
@@ -141,11 +202,12 @@ export interface RetrospectiveSweepResult {
141
202
  }
142
203
 
143
204
  /**
144
- * Scan all sweep-eligible conversations and enqueue a `sweep`-triggered
145
- * retrospective for any with unprocessed messages whose last attempt is older
146
- * than `sweepIntervalMs`. Idempotent and best-effort: enqueue coalescing
147
- * prevents duplicates, and the scan degrades to a no-op when memory is
148
- * disabled.
205
+ * Scan sweep-eligible conversations with activity inside the lookback window
206
+ * and enqueue a `sweep`-triggered retrospective for any with unprocessed
207
+ * messages whose last attempt is older than `sweepIntervalMs`, up to
208
+ * {@link SWEEP_MAX_ENQUEUES_PER_PASS} per pass. Idempotent and best-effort:
209
+ * enqueue coalescing prevents duplicates, and the scan degrades to a no-op
210
+ * when memory is disabled.
149
211
  */
150
212
  export async function runRetrospectiveSweep(
151
213
  config: AssistantConfig,
@@ -155,12 +217,20 @@ export async function runRetrospectiveSweep(
155
217
  return { scanned: 0, enqueued: 0 };
156
218
  }
157
219
  const sweepIntervalMs = config.memory.retrospective.sweepIntervalMs;
220
+ const lookbackCutoff = now - effectiveSweepLookbackMs(config);
221
+ const pendingSourceIds = new Set(
222
+ listPendingMemoryRetrospectiveSourceConversationIds(),
223
+ );
158
224
 
159
225
  let scanned = 0;
160
226
  let enqueued = 0;
161
227
  let cursor = "";
162
228
  for (;;) {
163
- const page = listSweepCandidateConversationIds(cursor, SWEEP_BATCH);
229
+ const page = listSweepCandidateConversationIds(
230
+ cursor,
231
+ SWEEP_BATCH,
232
+ lookbackCutoff,
233
+ );
164
234
  if (page.length === 0) {
165
235
  break;
166
236
  }
@@ -169,6 +239,17 @@ export async function runRetrospectiveSweep(
169
239
  for (const conversationId of page) {
170
240
  scanned += 1;
171
241
 
242
+ // A source with a pending row has nothing for the sweep to add — the
243
+ // row runs on its own. Skipping it up front keeps coalescing upserts
244
+ // from consuming the per-pass enqueue cap: counted no-ops would starve
245
+ // conversations later in id order across passes (every pass restarts
246
+ // from the lowest id). A RUNNING job does not suppress the sweep — its
247
+ // cursor is a pre-run snapshot, so a mid-run arrival needs a follow-up
248
+ // row, and the upsert's pending-only coalescing creates exactly that.
249
+ if (pendingSourceIds.has(conversationId)) {
250
+ continue;
251
+ }
252
+
172
253
  // Memory trust boundary: never enqueue a retrospective (which runs under
173
254
  // guardian trust with `remember`) for a conversation whose actor isn't
174
255
  // memory-trusted. This is the sweep's equivalent of the per-message
@@ -198,6 +279,13 @@ export async function runRetrospectiveSweep(
198
279
 
199
280
  enqueueMemoryRetrospectiveIfEnabled({ conversationId, trigger: "sweep" });
200
281
  enqueued += 1;
282
+ if (enqueued >= SWEEP_MAX_ENQUEUES_PER_PASS) {
283
+ log.warn(
284
+ { scanned, enqueued },
285
+ "Memory retrospective sweep hit the per-pass enqueue cap; deferring the remainder to the next pass",
286
+ );
287
+ return { scanned, enqueued };
288
+ }
201
289
  }
202
290
 
203
291
  await breathe();
@@ -14,8 +14,8 @@ import { join } from "node:path";
14
14
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
15
15
 
16
16
  import type { RouteDefinition } from "../../../../../runtime/routes/types.js";
17
- import { writePage } from "../../v3/substrate/page-store.js";
18
- import type { ConceptPage } from "../../v3/substrate/types.js";
17
+ import { writePage } from "../../substrate/page-store.js";
18
+ import type { ConceptPage } from "../../substrate/types.js";
19
19
  import type { MemoryV2ListConceptPagesResult } from "../memory-v2-routes.js";
20
20
  import { ROUTES } from "../memory-v2-routes.js";
21
21
 
@@ -26,7 +26,9 @@ let origWorkspaceDir: string | undefined;
26
26
 
27
27
  function findHandler(operationId: string): RouteDefinition["handler"] {
28
28
  const route = ROUTES.find((r) => r.operationId === operationId);
29
- if (!route) throw new Error(`Route ${operationId} not found`);
29
+ if (!route) {
30
+ throw new Error(`Route ${operationId} not found`);
31
+ }
30
32
  return route.handler;
31
33
  }
32
34
 
@@ -32,7 +32,7 @@ import type { ToolDefinition } from "../../llm-helpers.js";
32
32
  // ---------------------------------------------------------------------------
33
33
 
34
34
  // Skill store: empty by default so the page index only contains test pages.
35
- mock.module("../../v3/substrate/skill-store.js", () => ({
35
+ mock.module("../../substrate/skill-store.js", () => ({
36
36
  SKILL_SLUG_PREFIX: "skills/",
37
37
  listSkillEntries: () => [],
38
38
  seedV2SkillEntries: async () => undefined,
@@ -118,9 +118,8 @@ mock.module("../../../../../util/platform.js", () => ({
118
118
  // ---------------------------------------------------------------------------
119
119
 
120
120
  const { handleSimulateRouter } = await import("../memory-v2-routes.js");
121
- const { writePage } = await import("../../v3/substrate/page-store.js");
122
- const { invalidatePageIndex } =
123
- await import("../../v3/substrate/page-index.js");
121
+ const { writePage } = await import("../../substrate/page-store.js");
122
+ const { invalidatePageIndex } = await import("../../substrate/page-index.js");
124
123
 
125
124
  // ---------------------------------------------------------------------------
126
125
  // Helpers
@@ -61,7 +61,8 @@ export const ROUTES: RouteDefinition[] = [
61
61
  {
62
62
  name: "id",
63
63
  schema: { type: "string" },
64
- description: "Node id from the graph payload (memory-v3: the concept-page slug).",
64
+ description:
65
+ "Node id from the graph payload (memory-v3: the concept-page slug).",
65
66
  },
66
67
  ],
67
68
  responseBody: MemoryGraphNodeDetailSchema,
@@ -68,7 +68,7 @@ mock.module(
68
68
  // stats test seed synthetic (modifiedAt: 0) rows and assert they're excluded.
69
69
  let mockSkillEntries: Array<{ id: string; content: string }> = [];
70
70
 
71
- mock.module("../v3/substrate/skill-store.js", () => ({
71
+ mock.module("../substrate/skill-store.js", () => ({
72
72
  SKILL_SLUG_PREFIX: "skills/",
73
73
  listSkillEntries: () => mockSkillEntries,
74
74
  }));
@@ -92,9 +92,9 @@ import {
92
92
  } from "../../../../runtime/routes/errors.js";
93
93
  import type { RouteDefinition } from "../../../../runtime/routes/types.js";
94
94
  import { readPendingBufferEntries } from "../graph-topology/pending-buffer.js";
95
- import { invalidatePageIndex } from "../v3/substrate/page-index.js";
96
- import { writePage } from "../v3/substrate/page-store.js";
97
- import type { ConceptPage } from "../v3/substrate/types.js";
95
+ import { invalidatePageIndex } from "../substrate/page-index.js";
96
+ import { writePage } from "../substrate/page-store.js";
97
+ import type { ConceptPage } from "../substrate/types.js";
98
98
  import { ROUTES } from "./memory-item-routes.js";
99
99
 
100
100
  // ---------------------------------------------------------------------------
@@ -105,7 +105,9 @@ function getRoute(endpoint: string, method: string): RouteDefinition {
105
105
  const route = ROUTES.find(
106
106
  (r: RouteDefinition) => r.endpoint === endpoint && r.method === method,
107
107
  );
108
- if (!route) throw new Error(`No route: ${method} ${endpoint}`);
108
+ if (!route) {
109
+ throw new Error(`No route: ${method} ${endpoint}`);
110
+ }
109
111
  return route;
110
112
  }
111
113
 
@@ -33,7 +33,7 @@ import { z } from "zod";
33
33
 
34
34
  import { getConfig } from "../../../../config/loader.js";
35
35
  import {
36
- isMemoryGraphSupported,
36
+ isV3TierActive,
37
37
  usesConceptPageMemory,
38
38
  } from "../../../../config/memory-v3-gate.js";
39
39
  import type { AssistantConfig } from "../../../../config/types.js";
@@ -81,7 +81,8 @@ import { consolidationBackoffRemainingMs } from "../jobs-worker.js";
81
81
  import { getLogger } from "../logging.js";
82
82
  import { memoryDbOrNull } from "../memory-db.js";
83
83
  import { getWorkspaceDir } from "../paths.js";
84
- import { getPageIndex } from "../v3/substrate/page-index.js";
84
+ import { getPageIndex } from "../substrate/page-index.js";
85
+ import { resolveSubstrateTuning } from "../substrate/tuning.js";
85
86
 
86
87
  const log = getLogger("memory-item-routes");
87
88
 
@@ -211,13 +212,19 @@ async function searchNodesSemantic(
211
212
  // search (the caller's `null` branch) instead of querying the v1
212
213
  // collection, which is in active retirement and a corrupted sparse
213
214
  // segment can OOM-crash the shared Qdrant process.
214
- if (usesConceptPageMemory(config.memory)) return null;
215
+ if (usesConceptPageMemory(config.memory)) {
216
+ return null;
217
+ }
215
218
  const backendStatus = await getMemoryBackendStatus(config);
216
- if (!backendStatus.provider) return null;
219
+ if (!backendStatus.provider) {
220
+ return null;
221
+ }
217
222
 
218
223
  const embedded = await embedWithBackend(config, [query]);
219
224
  const queryVector = embedded.vectors[0];
220
- if (!queryVector) return null;
225
+ if (!queryVector) {
226
+ return null;
227
+ }
221
228
 
222
229
  const sparse = generateSparseEmbedding(query);
223
230
  const sparseVector = { indices: sparse.indices, values: sparse.values };
@@ -320,7 +327,9 @@ async function handleListMemoryItems(queryParams: Record<string, string>) {
320
327
  }
321
328
 
322
329
  const db = memoryDbOrNull("listMemoryItems");
323
- if (!db) throw new Error("memory database unavailable");
330
+ if (!db) {
331
+ throw new Error("memory database unavailable");
332
+ }
324
333
 
325
334
  // Build fidelity filter based on status param
326
335
  const fidelityFilter =
@@ -343,7 +352,9 @@ async function handleListMemoryItems(queryParams: Record<string, string>) {
343
352
  const kindCountConditions = [
344
353
  inArray(memoryGraphNodes.id, semanticResult.ids),
345
354
  ];
346
- if (fidelityFilter) kindCountConditions.push(fidelityFilter);
355
+ if (fidelityFilter) {
356
+ kindCountConditions.push(fidelityFilter);
357
+ }
347
358
 
348
359
  const kindCountRows = db
349
360
  .select({ kind: memoryGraphNodes.type, count: count() })
@@ -365,7 +376,9 @@ async function handleListMemoryItems(queryParams: Record<string, string>) {
365
376
  if (kindParam) {
366
377
  filterConditions.push(eq(memoryGraphNodes.type, kindParam));
367
378
  }
368
- if (fidelityFilter) filterConditions.push(fidelityFilter);
379
+ if (fidelityFilter) {
380
+ filterConditions.push(fidelityFilter);
381
+ }
369
382
 
370
383
  if (filterConditions.length > 1) {
371
384
  const validIdSet = new Set(
@@ -393,9 +406,12 @@ async function handleListMemoryItems(queryParams: Record<string, string>) {
393
406
 
394
407
  // Hydrate nodes from DB
395
408
  const hydrationConditions = [inArray(memoryGraphNodes.id, pageIds)];
396
- if (fidelityFilter) hydrationConditions.push(fidelityFilter);
397
- if (kindParam)
409
+ if (fidelityFilter) {
410
+ hydrationConditions.push(fidelityFilter);
411
+ }
412
+ if (kindParam) {
398
413
  hydrationConditions.push(eq(memoryGraphNodes.type, kindParam));
414
+ }
399
415
 
400
416
  const rows = db
401
417
  .select()
@@ -419,7 +435,9 @@ async function handleListMemoryItems(queryParams: Record<string, string>) {
419
435
 
420
436
  // ── Kind counts for SQL path ───────────────────────────────────────
421
437
  const kindCountConditions = [];
422
- if (fidelityFilter) kindCountConditions.push(fidelityFilter);
438
+ if (fidelityFilter) {
439
+ kindCountConditions.push(fidelityFilter);
440
+ }
423
441
  if (searchParam) {
424
442
  kindCountConditions.push(
425
443
  like(memoryGraphNodes.content, `%${searchParam}%`),
@@ -441,8 +459,12 @@ async function handleListMemoryItems(queryParams: Record<string, string>) {
441
459
 
442
460
  // ── SQL path (default or fallback) ──────────────────────────────────
443
461
  const conditions = [];
444
- if (fidelityFilter) conditions.push(fidelityFilter);
445
- if (kindParam) conditions.push(eq(memoryGraphNodes.type, kindParam));
462
+ if (fidelityFilter) {
463
+ conditions.push(fidelityFilter);
464
+ }
465
+ if (kindParam) {
466
+ conditions.push(eq(memoryGraphNodes.type, kindParam));
467
+ }
446
468
  if (searchParam) {
447
469
  conditions.push(like(memoryGraphNodes.content, `%${searchParam}%`));
448
470
  }
@@ -497,7 +519,7 @@ function handleGetMemoryItem(id: string) {
497
519
  * concept graph is deliberately kept off identity-page load.
498
520
  *
499
521
  * `graph_supported` reports whether the memory-concept graph is available for
500
- * this assistant — the same `isMemoryGraphSupported` condition under which
522
+ * this assistant — the same `isV3TierActive` condition under which
501
523
  * `GET /memory-graph` returns `supported: true` (memory enabled + v3 live). It
502
524
  * is a cheap config read (no page I/O), so glanceable surfaces can gate the
503
525
  * graph entry point on real availability without triggering the graph build.
@@ -507,7 +529,7 @@ async function handleGetMemoryStats(
507
529
  ): Promise<{ concepts: number; graph_supported: boolean }> {
508
530
  const pageIndex = await getPageIndex(getWorkspaceDir());
509
531
  const concepts = pageIndex.entries.filter((e) => e.modifiedAt > 0).length;
510
- return { concepts, graph_supported: isMemoryGraphSupported(config) };
532
+ return { concepts, graph_supported: isV3TierActive(config) };
511
533
  }
512
534
 
513
535
  async function handleCreateMemoryItem(body: Record<string, unknown>) {
@@ -538,7 +560,9 @@ async function handleCreateMemoryItem(body: Record<string, unknown>) {
538
560
 
539
561
  // Check for duplicate content
540
562
  const db = memoryDbOrNull("createMemoryItem");
541
- if (!db) throw new Error("memory database unavailable");
563
+ if (!db) {
564
+ throw new Error("memory database unavailable");
565
+ }
542
566
  const existing = db
543
567
  .select({ id: memoryGraphNodes.id })
544
568
  .from(memoryGraphNodes)
@@ -658,7 +682,9 @@ async function handleUpdateMemoryItem(
658
682
  if (contentChanged || reactivating) {
659
683
  const contentToCheck = changes.content ?? existing.content;
660
684
  const db = memoryDbOrNull("updateMemoryItem");
661
- if (!db) throw new Error("memory database unavailable");
685
+ if (!db) {
686
+ throw new Error("memory database unavailable");
687
+ }
662
688
  const collision = db
663
689
  .select({ id: memoryGraphNodes.id })
664
690
  .from(memoryGraphNodes)
@@ -705,14 +731,20 @@ async function handleUpdateMemoryItem(
705
731
  */
706
732
  function maybeEnqueueConsolidationForCreate(config: AssistantConfig): void {
707
733
  try {
708
- if (!usesConceptPageMemory(config.memory) || !isMemoryEnabled()) {
734
+ // `usesConceptPageMemory` already covers the memory-off case (an explicit
735
+ // `memory.enabled === false` makes it false), so a second
736
+ // `isMemoryEnabled()` clause would be unreachable.
737
+ if (!usesConceptPageMemory(config.memory)) {
709
738
  return;
710
739
  }
711
740
  if (hasActiveJobOfType("memory_v2_consolidate")) {
712
741
  return;
713
742
  }
714
743
  const intervalMs =
715
- config.memory.v2.consolidation_interval_hours * 60 * 60 * 1000;
744
+ resolveSubstrateTuning(config.memory).consolidation_interval_hours *
745
+ 60 *
746
+ 60 *
747
+ 1000;
716
748
  if (consolidationBackoffRemainingMs(intervalMs, Date.now()) > 0) {
717
749
  return;
718
750
  }
@@ -21,11 +21,25 @@ import { RouteError } from "../../../../runtime/routes/errors.js";
21
21
  import type { RouteDefinition } from "../../../../runtime/routes/types.js";
22
22
  import type { RouteHandlerArgs } from "../../../../runtime/routes/types.js";
23
23
  import { getLogger } from "../logging.js";
24
+ import { getWorkspaceDir } from "../paths.js";
25
+ import {
26
+ getEdgeIndex,
27
+ totalEdgeCount,
28
+ validateEdgeTargets,
29
+ } from "../substrate/edge-index.js";
30
+ import { getPageIndex } from "../substrate/page-index.js";
31
+ import {
32
+ getConceptsDir,
33
+ listPages,
34
+ readPage,
35
+ renderPageContent,
36
+ } from "../substrate/page-store.js";
37
+ import { seedV2SkillEntries } from "../substrate/skill-store.js";
38
+ import { resolveSubstrateTuning } from "../substrate/tuning.js";
24
39
  import {
25
40
  type ConceptFrequencyResponse,
26
41
  getConceptFrequencySummary,
27
- } from "../memory-v2-concept-frequency.js";
28
- import { getWorkspaceDir } from "../paths.js";
42
+ } from "../v2/concept-frequency.js";
29
43
  import { runComparisonOverHistory } from "../v2/harness/compare.js";
30
44
  import type { Retriever } from "../v2/harness/retriever.js";
31
45
  import { createRouterRetriever } from "../v2/harness/router-retriever.js";
@@ -34,19 +48,6 @@ import { computeInjectionScores } from "../v2/injection-events.js";
34
48
  import { loadNowText } from "../v2/now-text.js";
35
49
  import { ROUTER_PROMPT } from "../v2/prompts/router.js";
36
50
  import { type RouterSource, runRouter } from "../v2/router.js";
37
- import {
38
- getEdgeIndex,
39
- totalEdgeCount,
40
- validateEdgeTargets,
41
- } from "../v3/substrate/edge-index.js";
42
- import { getPageIndex } from "../v3/substrate/page-index.js";
43
- import {
44
- getConceptsDir,
45
- listPages,
46
- readPage,
47
- renderPageContent,
48
- } from "../v3/substrate/page-store.js";
49
- import { seedV2SkillEntries } from "../v3/substrate/skill-store.js";
50
51
 
51
52
  const log = getLogger("memory-v2-routes");
52
53
 
@@ -133,7 +134,9 @@ async function handleValidate({
133
134
  MemoryV2ValidateParams.parse(body);
134
135
 
135
136
  const workspaceDir = getWorkspaceDir();
136
- const maxPageChars = loadConfig().memory.v2.max_page_chars;
137
+ const maxPageChars = resolveSubstrateTuning(
138
+ loadConfig().memory,
139
+ ).max_page_chars;
137
140
 
138
141
  const slugs = await listPages(workspaceDir);
139
142
  const knownSlugs = new Set<string>();
@@ -143,7 +146,9 @@ async function handleValidate({
143
146
  for (const slug of slugs) {
144
147
  try {
145
148
  const page = await readPage(workspaceDir, slug);
146
- if (!page) continue;
149
+ if (!page) {
150
+ continue;
151
+ }
147
152
  knownSlugs.add(slug);
148
153
  const chars = page.body.length;
149
154
  if (chars > maxPageChars) {
@@ -242,7 +247,9 @@ async function handleListConceptPages({
242
247
  slugs.map(async (slug) => {
243
248
  try {
244
249
  const page = await readPage(workspaceDir, slug);
245
- if (!page) return null;
250
+ if (!page) {
251
+ return null;
252
+ }
246
253
  const stats = await stat(join(conceptsDir, `${slug}.md`));
247
254
  return {
248
255
  slug,
@@ -346,7 +353,9 @@ async function handleEmaScores({
346
353
  modifiedAt: entry.modifiedAt,
347
354
  }));
348
355
  entries.sort((a, b) => {
349
- if (a.score !== b.score) return b.score - a.score;
356
+ if (a.score !== b.score) {
357
+ return b.score - a.score;
358
+ }
350
359
  return a.slug < b.slug ? -1 : a.slug > b.slug ? 1 : 0;
351
360
  });
352
361
  return { entries };
@@ -455,7 +464,9 @@ function applySimulateOverrides(
455
464
  live: AssistantConfig,
456
465
  overrides: z.infer<typeof SimulateRouterOverridesSchema> | undefined,
457
466
  ): AssistantConfig {
458
- if (!overrides) return live;
467
+ if (!overrides) {
468
+ return live;
469
+ }
459
470
  const liveRouter = live.memory.v2.router;
460
471
  const mergedRouter = {
461
472
  ...liveRouter,