@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
@@ -12,11 +12,14 @@ import { v4 as uuid } from "uuid";
12
12
 
13
13
  import { cleanupBootstrapFiles } from "../prompts/bootstrap-cleanup.js";
14
14
  import { getCurrentSeq } from "../runtime/assistant-stream-state.js";
15
+ import { getLogger } from "../util/logger.js";
15
16
  import { initConversationDir } from "./conversation-disk-view.js";
16
17
  import { GENERATING_TITLE } from "./conversation-title-service.js";
17
18
  import { getDb } from "./db-connection.js";
18
19
  import { conversationKeys, conversations } from "./schema/index.js";
19
20
 
21
+ const log = getLogger("conversation-key-store");
22
+
20
23
  /** Set after the first conversation is created so BOOTSTRAP.md is deleted on the second. */
21
24
  let firstConversationSeen = false;
22
25
 
@@ -267,6 +270,23 @@ export function getOrCreateConversation(
267
270
 
268
271
  if (result.created) {
269
272
  initConversationDir({ ...result.conversation, originChannel: null });
273
+ // Attribution for every key-materialized conversation: this is the single
274
+ // choke point through which all unseen-key creations flow, and the key
275
+ // shape + caller frames identify the entry point from the log alone. The
276
+ // raw key is never logged — channel-backed keys embed external chat ids
277
+ // (phone numbers, Slack/Telegram ids), and assistant logs travel in
278
+ // support bundles. Emitted only on the creation branch, never on hot
279
+ // read/write paths.
280
+ log.info(
281
+ {
282
+ conversationKeyShape: classifyConversationKey(conversationKey),
283
+ conversationId: result.conversationId,
284
+ conversationType,
285
+ hasCustomTitle: Boolean(opts?.title?.trim()),
286
+ caller: captureCallerFrames(),
287
+ },
288
+ "Materialized conversation for unseen conversation key",
289
+ );
270
290
  }
271
291
 
272
292
  return {
@@ -275,3 +295,46 @@ export function getOrCreateConversation(
275
295
  created: result.created,
276
296
  };
277
297
  }
298
+
299
+ const UUID_SHAPE_RE =
300
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
301
+
302
+ /**
303
+ * PII-free shape label for a conversation key. Channel-backed keys embed
304
+ * external chat/user ids, so only the structural prefix is kept (e.g.
305
+ * `asst:<id>:slack:<chat>:thread:<ts>` → "asst-scoped:slack:threaded");
306
+ * free-form keys collapse to a coarse class.
307
+ */
308
+ function classifyConversationKey(conversationKey: string): string {
309
+ if (conversationKey.startsWith("asst:")) {
310
+ const parts = conversationKey.split(":");
311
+ const channel = parts[2] ?? "unknown";
312
+ const threaded = parts.includes("thread") ? ":threaded" : "";
313
+ return `asst-scoped:${channel}${threaded}`;
314
+ }
315
+ const prefixed = conversationKey.match(/^([a-z-]+)[:-]/i);
316
+ if (prefixed) {
317
+ return `prefixed:${prefixed[1].toLowerCase()}`;
318
+ }
319
+ if (UUID_SHAPE_RE.test(conversationKey)) {
320
+ return "uuid";
321
+ }
322
+ return "opaque";
323
+ }
324
+
325
+ /**
326
+ * Compact caller summary for creation attribution: the first few stack
327
+ * frames above this module, joined into one log-friendly line.
328
+ */
329
+ function captureCallerFrames(): string {
330
+ const stack = new Error().stack?.split("\n") ?? [];
331
+ return stack
332
+ .slice(1)
333
+ .map((line) => line.trim())
334
+ .filter(
335
+ (line) =>
336
+ line.startsWith("at ") && !line.includes("conversation-key-store"),
337
+ )
338
+ .slice(0, 4)
339
+ .join(" | ");
340
+ }
@@ -0,0 +1,27 @@
1
+ import { eq } from "drizzle-orm";
2
+
3
+ import { getDb } from "./db-connection.js";
4
+ import { conversations } from "./schema/index.js";
5
+
6
+ /**
7
+ * The durable spawn parent of a conversation: the `parent_conversation_id`
8
+ * column stamped at subagent bootstrap. Returns `undefined` for a conversation
9
+ * with no recorded parent or no row at all.
10
+ *
11
+ * Unlike the in-memory conversation registry — which drops a subagent entry as
12
+ * soon as its run goes terminal and evicts idle top-level conversations — this
13
+ * survives for the life of the row, so an ancestry walk still resolves long
14
+ * after the run that created the chain has finished.
15
+ *
16
+ * A single-row primary-key lookup.
17
+ */
18
+ export function getPersistedParentConversationId(
19
+ conversationId: string,
20
+ ): string | undefined {
21
+ const row = getDb()
22
+ .select({ parentConversationId: conversations.parentConversationId })
23
+ .from(conversations)
24
+ .where(eq(conversations.id, conversationId))
25
+ .get();
26
+ return row?.parentConversationId ?? undefined;
27
+ }
@@ -228,7 +228,7 @@ async function runViaCli(
228
228
  // corrupt) — the durability posture every daemon write already has, so
229
229
  // FULL here buys no end-to-end guarantee. Prepended to the piped SQL so
230
230
  // both take effect before the statement runs.
231
- const sqlWithPragma = `PRAGMA busy_timeout=${SQLITE_BUSY_TIMEOUT_MS};\nPRAGMA synchronous=NORMAL;\n${sql}`;
231
+ const sqlWithPragma = `PRAGMA busy_timeout=${SQLITE_BUSY_TIMEOUT_MS};\nPRAGMA synchronous=NORMAL;\nPRAGMA journal_mode=WAL;\n${sql}`;
232
232
 
233
233
  // Write the SQL and close stdin so sqlite3 sees EOF and exits.
234
234
  proc.stdin.write(sqlWithPragma + "\n");
@@ -17,10 +17,10 @@
17
17
  *
18
18
  * State is held on `globalThis.vellumAssistant.dbSingletons` so test
19
19
  * helpers in `__tests__/` can read/write it WITHOUT importing this
20
- * module — they declare the same slot shape locally and access the
21
- * globalThis namespace directly. See
22
- * `__tests__/db-test-helpers.ts` for the test-side mirror; the slot
23
- * shape MUST stay in sync between the two.
20
+ * module. Both sides reference the shared ambient `VellumDbSlots` type
21
+ * (declared in `src/vellum-assistant-namespace.d.ts`), which types the
22
+ * slot without adding a runtime import between them. See
23
+ * `__tests__/db-test-helpers.ts` for the test-side reader.
24
24
  *
25
25
  * The stored value is typed as `unknown` so this file never has to import
26
26
  * Drizzle types. Callers in `db-connection.ts` narrow via the type
@@ -33,32 +33,19 @@
33
33
  * - `__tests__/db-test-helpers.ts` (per-test reset, via globalThis)
34
34
  */
35
35
 
36
- /** Which connection a slot holds. */
37
- export type DbSlotKey =
38
- | "main"
39
- | "main-readonly"
40
- | "logs"
41
- | "memory"
42
- | "telemetry";
43
-
44
- type DbSlot = {
45
- db: unknown;
46
- closer: (() => void) | null;
47
- };
48
-
49
- type DbSlots = Record<DbSlotKey, DbSlot>;
50
-
51
- type VellumAssistantNamespace = {
52
- dbSingletons?: DbSlots;
53
- };
36
+ /**
37
+ * Which connection a slot holds. The canonical union is the ambient
38
+ * `VellumDbSlotKey` (see `src/vellum-assistant-namespace.d.ts`); this
39
+ * re-export is the DB layer's public name for it.
40
+ */
41
+ export type DbSlotKey = VellumDbSlotKey;
54
42
 
55
- function emptySlot(): DbSlot {
43
+ function emptySlot(): VellumDbSlot {
56
44
  return { db: null, closer: null };
57
45
  }
58
46
 
59
- function slots(): DbSlots {
60
- const g = globalThis as { vellumAssistant?: VellumAssistantNamespace };
61
- const ns = (g.vellumAssistant ??= {});
47
+ function slots(): VellumDbSlots {
48
+ const ns = (globalThis.vellumAssistant ??= {});
62
49
  return (ns.dbSingletons ??= {
63
50
  main: emptySlot(),
64
51
  "main-readonly": emptySlot(),
@@ -68,7 +55,7 @@ function slots(): DbSlots {
68
55
  });
69
56
  }
70
57
 
71
- function slot(key: DbSlotKey): DbSlot {
58
+ function slot(key: DbSlotKey): VellumDbSlot {
72
59
  return slots()[key];
73
60
  }
74
61
 
@@ -188,6 +188,51 @@ function resolveInboundConversation(
188
188
  return getOrCreateConversation(threadedKey);
189
189
  }
190
190
 
191
+ /**
192
+ * Resolve the internal conversation already bound to an inbound
193
+ * (channel, chat, thread) address, or `null` when none exists. Mirrors
194
+ * {@link resolveInboundConversation}'s lookup order — threaded key first,
195
+ * then the Slack flat-key alias when thread evidence exists — but is
196
+ * strictly read-only: deny lanes use it to attach the in-app
197
+ * access-request card to the originating conversation, and a denied
198
+ * inbound must never mint a conversation as a side effect.
199
+ */
200
+ export function findInboundConversationId(
201
+ sourceChannel: string,
202
+ externalChatId: string,
203
+ sourceThreadId?: string | null,
204
+ ): string | null {
205
+ const threadedKey = buildScopedConversationKey(
206
+ sourceChannel,
207
+ externalChatId,
208
+ sourceThreadId,
209
+ );
210
+ const threadedMapping = getConversationByKey(threadedKey);
211
+ if (threadedMapping) {
212
+ return threadedMapping.conversationId;
213
+ }
214
+
215
+ const threadId = sourceThreadId?.trim();
216
+ if (sourceChannel !== "slack" || !threadId) {
217
+ return null;
218
+ }
219
+
220
+ const legacyKey = buildScopedConversationKey(sourceChannel, externalChatId);
221
+ const legacyMapping = getConversationByKey(legacyKey);
222
+ if (
223
+ legacyMapping &&
224
+ legacySlackConversationHasThreadEvidence(
225
+ legacyMapping.conversationId,
226
+ externalChatId,
227
+ threadId,
228
+ )
229
+ ) {
230
+ return legacyMapping.conversationId;
231
+ }
232
+
233
+ return null;
234
+ }
235
+
191
236
  /**
192
237
  * Record an inbound channel event. Returns `duplicate: true` if this
193
238
  * exact (channel, chat, message) combination was already seen.
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
2
2
 
3
3
  import { getOllamaBaseUrlEnv } from "../../config/env.js";
4
4
  import { resolveCallSiteConfig } from "../../config/llm-resolver.js";
5
+ import { isMemoryEnabled } from "../../config/memory-v3-gate.js";
5
6
  import type { AssistantConfig } from "../../config/types.js";
6
7
  import { PLATFORM_PROVIDER_META } from "../../providers/platform-proxy/constants.js";
7
8
  import { resolveManagedProxyContext } from "../../providers/platform-proxy/context.js";
@@ -507,7 +508,7 @@ export async function getMemoryBackendStatus(config: AssistantConfig): Promise<{
507
508
  model: string | null;
508
509
  reason: string | null;
509
510
  }> {
510
- if (config.memory.enabled === false) {
511
+ if (!isMemoryEnabled(config)) {
511
512
  return {
512
513
  enabled: false,
513
514
  degraded: false,
@@ -12,9 +12,13 @@ import { resolveQdrantUrl } from "./qdrant-client.js";
12
12
 
13
13
  const log = getLogger("embedding-identity");
14
14
 
15
- // Inlined rather than imported from `memory/v2/qdrant.ts`: the persistence
16
- // layer must not import from the memory feature layer (enforced by
17
- // persistence-layering-guard). The dependency direction is memory → persistence.
15
+ // FROZEN: `memory_v2_concept_pages` is a Qdrant collection name on disk, and it
16
+ // belongs to the concept-page SUBSTRATE (which outlives the v2 engine) despite
17
+ // the `v2` spelling — see `plugins/defaults/memory/AGENTS.md`. Inlined rather
18
+ // than imported from `memory/substrate/qdrant.ts`'s `MEMORY_V2_COLLECTION`: the
19
+ // persistence layer must not import from the memory feature layer (enforced by
20
+ // persistence-layering-guard). The dependency direction is memory →
21
+ // persistence. This copy and the substrate's must change together or never.
18
22
  const MEMORY_V2_COLLECTION = "memory_v2_concept_pages";
19
23
 
20
24
  export interface BackendDimensionProbe {
@@ -230,8 +230,39 @@ export async function embedAndUpsert(
230
230
  ? generateSparseEmbedding(normalized.text)
231
231
  : undefined;
232
232
 
233
- // Persist embedding in SQLite for cross-restart cache
234
233
  const now = Date.now();
234
+ const qdrant = requireQdrantClient();
235
+
236
+ try {
237
+ const modality = normalized.type;
238
+ await withQdrantBreaker(() =>
239
+ qdrant.upsert(
240
+ targetType,
241
+ targetId,
242
+ vector,
243
+ {
244
+ text: payloadText,
245
+ modality,
246
+ created_at: (extraPayload?.created_at as number) ?? now,
247
+ ...(extraPayload as Record<string, unknown> | undefined),
248
+ },
249
+ sparseVector,
250
+ ),
251
+ );
252
+ } catch (err) {
253
+ log.warn(
254
+ { err, targetType, targetId },
255
+ "Failed to upsert embedding to Qdrant",
256
+ );
257
+ throw err;
258
+ }
259
+
260
+ // Persist the embedding in SQLite for the cross-restart cache, after the
261
+ // point is live in Qdrant. Consumers read a row as "this target is indexed"
262
+ // — the graph-node orphan sweep does — so a row written ahead of the upsert
263
+ // would mark a missing point as embedded and suppress the re-embed that
264
+ // would restore it. Best-effort in the other direction: a write failure logs
265
+ // and leaves the point in place, and the next run re-embeds.
235
266
  try {
236
267
  const blobValue = vectorToBlob(vector);
237
268
  db.insert(memoryEmbeddings)
@@ -267,30 +298,4 @@ export async function embedAndUpsert(
267
298
  } catch (err) {
268
299
  log.warn({ err, targetType, targetId }, "Failed to write embedding cache");
269
300
  }
270
-
271
- const qdrant = requireQdrantClient();
272
-
273
- try {
274
- const modality = normalized.type;
275
- await withQdrantBreaker(() =>
276
- qdrant.upsert(
277
- targetType,
278
- targetId,
279
- vector,
280
- {
281
- text: payloadText,
282
- modality,
283
- created_at: (extraPayload?.created_at as number) ?? now,
284
- ...(extraPayload as Record<string, unknown> | undefined),
285
- },
286
- sparseVector,
287
- ),
288
- );
289
- } catch (err) {
290
- log.warn(
291
- { err, targetType, targetId },
292
- "Failed to upsert embedding to Qdrant",
293
- );
294
- throw err;
295
- }
296
301
  }
@@ -2,6 +2,7 @@ import { and, asc, eq, inArray, lte, notInArray, sql } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import { getConfig } from "../config/loader.js";
5
+ import { isMemoryEnabled as isMemoryEnabledForConfig } from "../config/memory-v3-gate.js";
5
6
  import { getLogger } from "../util/logger.js";
6
7
  import { truncate } from "../util/truncate.js";
7
8
  import { type DrizzleDb, getMemoryDb } from "./db-connection.js";
@@ -13,6 +14,7 @@ import {
13
14
  isQdrantBreakerOpen,
14
15
  shouldAllowQdrantProbe,
15
16
  } from "./embeddings/qdrant-circuit-breaker.js";
17
+ import { isLifecycleQuiesced } from "./lifecycle-quiesce.js";
16
18
  import { rawMemoryAll, rawMemoryChanges } from "./raw-query.js";
17
19
  import { memoryJobs } from "./schema/index.js";
18
20
 
@@ -55,6 +57,8 @@ export type MemoryJobType =
55
57
  | "graph_trigger_embed"
56
58
  | "graph_bootstrap"
57
59
  | "embed_concept_page"
60
+ // FROZEN: `memory_v2_*` job type values are persisted in job rows — never
61
+ // rename them.
58
62
  | "memory_v2_sweep"
59
63
  | "memory_v2_consolidate"
60
64
  | "memory_v2_migrate"
@@ -68,12 +72,12 @@ export type MemoryJobType =
68
72
  | "delete_message_lexical"
69
73
  | "backfill_lexical_index"
70
74
  | "skill_card_insert"
75
+ | "memory_retrospective"
71
76
  | "memory_retrospective_sweep"
72
77
  // Retired/legacy — no live handler; persisted rows drop via LEGACY_JOB_TYPES.
73
78
  | "memory_v3_consolidate"
74
79
  | "memory_v3_index_maintenance"
75
80
  | "memory_v3_edge_learning"
76
- | "memory_retrospective"
77
81
  | "conversation_analyze";
78
82
 
79
83
  export const EMBED_JOB_TYPES: MemoryJobType[] = [
@@ -127,10 +131,11 @@ export const MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS = {
127
131
  remember: "remember",
128
132
  } as const;
129
133
 
130
- /** Returns `false` only when `config.memory.enabled` is explicitly `false`; defaults to `true` on missing config or load errors. */
134
+ /** Config-singleton wrapper over the canonical gate predicate in
135
+ * `config/memory-v3-gate.ts`; defaults to `true` on config load errors. */
131
136
  export function isMemoryEnabled(): boolean {
132
137
  try {
133
- return getConfig().memory?.enabled !== false;
138
+ return isMemoryEnabledForConfig(getConfig());
134
139
  } catch {
135
140
  return true;
136
141
  }
@@ -374,6 +379,33 @@ function mergeSkillCardEntries(
374
379
  return merged;
375
380
  }
376
381
 
382
+ /**
383
+ * Source-conversation ids of every PENDING `memory_retrospective` job. The
384
+ * retrospective sweep skips these up front: a pending row already covers the
385
+ * source's unprocessed span, and a coalescing upsert against it must not
386
+ * consume the sweep's per-pass enqueue cap. Deliberately excludes `running`
387
+ * rows — a running job's fork and cursor are pre-run snapshots, so messages
388
+ * arriving mid-run need a follow-up row behind it, and the sweep must be able
389
+ * to create that follow-up. Mirrors `upsertMemoryRetrospectiveJob`'s
390
+ * pending-only coalescing.
391
+ */
392
+ export function listPendingMemoryRetrospectiveSourceConversationIds(): string[] {
393
+ return memoryDb()
394
+ .select({
395
+ conversationId: sql<string>`json_extract(${memoryJobs.payload}, '$.conversationId')`,
396
+ })
397
+ .from(memoryJobs)
398
+ .where(
399
+ and(
400
+ eq(memoryJobs.type, "memory_retrospective"),
401
+ eq(memoryJobs.status, "pending"),
402
+ ),
403
+ )
404
+ .all()
405
+ .map((row) => row.conversationId)
406
+ .filter((id): id is string => typeof id === "string" && id.length > 0);
407
+ }
408
+
377
409
  /**
378
410
  * Check whether a pending or running job of the given type already exists.
379
411
  * Used to prevent duplicate enqueues for long-running maintenance jobs.
@@ -453,6 +485,36 @@ export function upsertEmbedConceptPageJob(payload: { slug: string }): string {
453
485
  return enqueueMemoryJob("embed_concept_page", { slug: payload.slug });
454
486
  }
455
487
 
488
+ /**
489
+ * Enqueue an `embed_graph_node` job, coalescing with an existing pending row
490
+ * for the same node id. The payload carries only the node id — the handler
491
+ * reads the node's content at execution time — so a pending row is exactly
492
+ * equivalent to a fresh enqueue and a duplicate would only redo identical
493
+ * embedding work and Qdrant upserts. A running row never matches: it may have
494
+ * embedded a pre-write snapshot of the node, so the new enqueue must survive
495
+ * it. Same synchronous check-then-insert rationale as
496
+ * {@link upsertEmbedConceptPageJob}. Returns the id of the pending row,
497
+ * existing or newly inserted.
498
+ */
499
+ export function upsertEmbedGraphNodeJob(payload: { nodeId: string }): string {
500
+ const db = memoryDb();
501
+ const existing = db
502
+ .select({ id: memoryJobs.id })
503
+ .from(memoryJobs)
504
+ .where(
505
+ and(
506
+ eq(memoryJobs.type, "embed_graph_node"),
507
+ eq(memoryJobs.status, "pending"),
508
+ sql`json_extract(${memoryJobs.payload}, '$.nodeId') = ${payload.nodeId}`,
509
+ ),
510
+ )
511
+ .get();
512
+ if (existing) {
513
+ return existing.id;
514
+ }
515
+ return enqueueMemoryJob("embed_graph_node", { nodeId: payload.nodeId });
516
+ }
517
+
456
518
  export function enqueuePruneOldLlmRequestLogsJob(retentionMs?: number): string {
457
519
  const db = memoryDb();
458
520
  const existing = db
@@ -618,6 +680,13 @@ export function claimMemoryJobs(
618
680
  return [];
619
681
  }
620
682
 
683
+ // Drain gate: while a quiesce lease is active, claim nothing so in-flight
684
+ // jobs finish and the queue drains to a stop. Enqueues are unaffected;
685
+ // claims resume when the lease expires. Fail-open via the lease read.
686
+ if (isLifecycleQuiesced()) {
687
+ return [];
688
+ }
689
+
621
690
  const db = memoryDb();
622
691
  const now = Date.now();
623
692
  const restrictFilter = restrictToTypes
@@ -868,6 +937,26 @@ export function resetRunningJobsToPending(): number {
868
937
  return rawMemoryChanges();
869
938
  }
870
939
 
940
+ /** Currently-running memory jobs, oldest first — the drain-status view. */
941
+ export function listRunningMemoryJobs(): Array<{
942
+ id: string;
943
+ type: string;
944
+ startedAt: number | null;
945
+ }> {
946
+ const db = memoryDb();
947
+ return db
948
+ .select({
949
+ id: memoryJobs.id,
950
+ type: memoryJobs.type,
951
+ startedAt: memoryJobs.startedAt,
952
+ })
953
+ .from(memoryJobs)
954
+ .where(eq(memoryJobs.status, "running"))
955
+ .orderBy(asc(memoryJobs.startedAt))
956
+ .limit(20)
957
+ .all();
958
+ }
959
+
871
960
  /**
872
961
  * Fail running jobs whose `startedAt` is older than `timeoutMs` ago.
873
962
  * Returns the number of jobs that were timed out.
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Cross-process quiesce lease for graceful drains.
3
+ *
4
+ * `vellum sleep --wait` sets a short-TTL lease before stopping the assistant;
5
+ * every background-work claim/fire site (heartbeat, the daemon's
6
+ * watcher/sequence tick, the schedule worker's claim tick, the memory jobs
7
+ * worker) checks it and stops STARTING new work while it is active. Enqueue
8
+ * paths are unaffected — queued work runs after the restart.
9
+ *
10
+ * The lease is a single `memory_checkpoints` row on the main database so the
11
+ * daemon and both worker processes read the same value. The value is an
12
+ * epoch-ms deadline, refreshed by the waiting client, so a dead client can
13
+ * never silence background work for longer than one TTL. Readers fail OPEN —
14
+ * a missing, malformed, or unreadable lease means "not quiesced".
15
+ */
16
+
17
+ import {
18
+ deleteMemoryCheckpoint,
19
+ getMemoryCheckpoint,
20
+ setMemoryCheckpoint,
21
+ } from "./checkpoints.js";
22
+
23
+ const QUIESCE_UNTIL_KEY = "lifecycle:quiesce_until";
24
+
25
+ export const MIN_QUIESCE_TTL_MS = 5_000;
26
+ export const MAX_QUIESCE_TTL_MS = 10 * 60_000;
27
+ export const DEFAULT_QUIESCE_TTL_MS = 60_000;
28
+
29
+ /**
30
+ * Arm (or refresh) the quiesce lease. Returns the lease deadline (epoch ms).
31
+ *
32
+ * Throws when the lease cannot be persisted — callers that promise a drain
33
+ * must surface the failure rather than pretend background work is paused.
34
+ */
35
+ export function setLifecycleQuiesce(
36
+ ttlMs: number = DEFAULT_QUIESCE_TTL_MS,
37
+ ): number {
38
+ const clamped = Math.min(
39
+ Math.max(Math.floor(ttlMs), MIN_QUIESCE_TTL_MS),
40
+ MAX_QUIESCE_TTL_MS,
41
+ );
42
+ const quiescedUntil = Date.now() + clamped;
43
+ setMemoryCheckpoint(QUIESCE_UNTIL_KEY, String(quiescedUntil));
44
+ return quiescedUntil;
45
+ }
46
+
47
+ /**
48
+ * The active lease deadline, or null when no unexpired lease exists.
49
+ * Fail-open: any read or parse failure reads as "no lease".
50
+ */
51
+ export function getLifecycleQuiesceUntil(): number | null {
52
+ let raw: string | null;
53
+ try {
54
+ raw = getMemoryCheckpoint(QUIESCE_UNTIL_KEY);
55
+ } catch {
56
+ return null;
57
+ }
58
+ if (raw == null) {
59
+ return null;
60
+ }
61
+ const until = Number.parseInt(raw, 10);
62
+ if (!Number.isFinite(until) || until <= Date.now()) {
63
+ return null;
64
+ }
65
+ return until;
66
+ }
67
+
68
+ /** True while an unexpired quiesce lease is active. Fail-open. */
69
+ export function isLifecycleQuiesced(): boolean {
70
+ return getLifecycleQuiesceUntil() != null;
71
+ }
72
+
73
+ /** Drop the lease. Best-effort — a failure leaves the TTL to expire it. */
74
+ export function clearLifecycleQuiesce(): void {
75
+ try {
76
+ deleteMemoryCheckpoint(QUIESCE_UNTIL_KEY);
77
+ } catch {
78
+ // Fail-soft: the lease self-expires.
79
+ }
80
+ }
@@ -42,6 +42,30 @@ import {
42
42
  // Write
43
43
  // ---------------------------------------------------------------------------
44
44
 
45
+ /**
46
+ * Resolve the parent conversation's `conversation_type` at record time.
47
+ * Usage rows outlive conversation rows (retrospective forks are GC'd,
48
+ * users delete conversations), so the type must be captured while the
49
+ * conversation still exists — the telemetry flush can run after the
50
+ * parent row is gone. Best-effort: a lookup failure degrades to null
51
+ * (same as the pre-column behavior) rather than dropping the usage row.
52
+ */
53
+ function lookupConversationType(conversationId: string | null): string | null {
54
+ if (conversationId === null) {
55
+ return null;
56
+ }
57
+ try {
58
+ const row = getDb()
59
+ .select({ conversationType: conversations.conversationType })
60
+ .from(conversations)
61
+ .where(eq(conversations.id, conversationId))
62
+ .get();
63
+ return row?.conversationType ?? null;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
45
69
  export function recordUsageEvent(
46
70
  input: UsageEventInput,
47
71
  pricing: PricingResult,
@@ -88,6 +112,10 @@ export function recordUsageEvent(
88
112
  // the assistant happens to be running on at upload time. See
89
113
  // migration 267 + `TelemetryEventBase.assistant_version` (wire).
90
114
  assistantVersion: event.assistantVersion,
115
+ // Capture the parent conversation's type at RECORD time for the
116
+ // same reason: the conversation row may be deleted before the
117
+ // telemetry flush joins against it. See migration 353.
118
+ conversationType: lookupConversationType(event.conversationId),
91
119
  })
92
120
  .run();
93
121
  return event;
@@ -192,9 +220,11 @@ export function listUsageEvents(options?: { limit?: number }): UsageEvent[] {
192
220
  export interface UnreportedUsageEvent extends UsageEvent {
193
221
  /**
194
222
  * Type of the parent conversation (`"standard"` / `"background"` /
195
- * `"scheduled"`). Null when the LLM call has no `conversationId`
196
- * (memory consolidation, background embedding work, etc.) and so no
197
- * `conversations` row to join against.
223
+ * `"scheduled"`). Sourced from the value captured at record time
224
+ * (survives deletion of the parent conversation before flush), with a
225
+ * JOIN to `conversations` as the fallback for rows persisted before
226
+ * migration 353. Null when the LLM call has no `conversationId`
227
+ * (memory consolidation, background embedding work, etc.).
198
228
  */
199
229
  conversationType: string | null;
200
230
  /**
@@ -263,10 +293,13 @@ export function queryUnreportedUsageEvents(
263
293
  ${conversations.createdAt}
264
294
  )
265
295
  END`;
266
- // JOIN to `conversations` to attach `conversationType`. LEFT JOIN
267
- // because `llm_usage_events.conversationId` is nullable — calls that
268
- // aren't tied to a conversation (memory consolidation, etc.) still
269
- // need to flush through telemetry.
296
+ // `conversationType` prefers the value stamped on the row at record
297
+ // time (migration 353) — the parent conversation may have been deleted
298
+ // before this flush (retrospective fork GC, user deletion) — and falls
299
+ // back to a LEFT JOIN against `conversations` for pre-353 rows. LEFT
300
+ // JOIN because `llm_usage_events.conversationId` is nullable — calls
301
+ // that aren't tied to a conversation (memory consolidation, etc.)
302
+ // still need to flush through telemetry.
270
303
  //
271
304
  // `turnIndex` is a correlated subquery counting real user turns in
272
305
  // the same conversation up to and including this LLM call's
@@ -297,7 +330,11 @@ export function queryUnreportedUsageEvents(
297
330
  pricingStatus: llmUsageEvents.pricingStatus,
298
331
  assistantVersion: llmUsageEvents.assistantVersion,
299
332
  llmCallCount: llmUsageEvents.llmCallCount,
300
- conversationType: conversations.conversationType,
333
+ conversationType: sql<
334
+ string | null
335
+ >`COALESCE(${llmUsageEvents.conversationType}, ${conversations.conversationType})`.as(
336
+ "resolved_conversation_type",
337
+ ),
301
338
  // Null when conversationId is null (no parent conversation).
302
339
  // Otherwise the count of eligible user turns up to and including
303
340
  // this LLM call's createdAt. The COALESCE guard returns null