@vellumai/assistant 0.10.12 → 0.11.0-staging.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (776) 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 +246 -10
  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__/approval-cascade.test.ts +5 -5
  39. package/src/__tests__/approval-routes-http.test.ts +3 -3
  40. package/src/__tests__/ask-question-resolver.test.ts +207 -0
  41. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
  42. package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
  43. package/src/__tests__/assistant-event-hub.test.ts +13 -11
  44. package/src/__tests__/assistant-event.test.ts +12 -9
  45. package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
  46. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
  47. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
  48. package/src/__tests__/assistant-stream-state.test.ts +17 -7
  49. package/src/__tests__/avatar-identity-sync.test.ts +3 -3
  50. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/call-conversation-messages.test.ts +134 -18
  52. package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
  53. package/src/__tests__/channel-approvals.test.ts +0 -27
  54. package/src/__tests__/channel-guardian.test.ts +85 -512
  55. package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
  56. package/src/__tests__/channel-retry-sweep.test.ts +88 -1
  57. package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
  58. package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
  59. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  60. package/src/__tests__/compaction-events.test.ts +8 -8
  61. package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
  62. package/src/__tests__/config-model-image-provider.test.ts +20 -0
  63. package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
  64. package/src/__tests__/config-schema.test.ts +14 -2
  65. package/src/__tests__/config-set-platform-guard.test.ts +11 -12
  66. package/src/__tests__/config-sounds-sync.test.ts +4 -4
  67. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
  68. package/src/__tests__/context-search-memory-source.test.ts +1 -1
  69. package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
  70. package/src/__tests__/context-token-estimator.test.ts +54 -1
  71. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
  72. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
  73. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
  74. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
  75. package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
  76. package/src/__tests__/conversation-agent-loop.test.ts +39 -30
  77. package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
  78. package/src/__tests__/conversation-evictor.test.ts +49 -0
  79. package/src/__tests__/conversation-fork-crud.test.ts +1 -1
  80. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  81. package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
  82. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
  83. package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
  84. package/src/__tests__/conversation-queue.test.ts +81 -81
  85. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
  86. package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
  87. package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
  88. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
  89. package/src/__tests__/conversation-slash-queue.test.ts +11 -11
  90. package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
  91. package/src/__tests__/conversation-speed-override.test.ts +2 -2
  92. package/src/__tests__/conversation-summarize-route.test.ts +9 -0
  93. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
  94. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
  95. package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
  96. package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
  97. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
  98. package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
  99. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  100. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
  101. package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
  102. package/src/__tests__/conversation-sync-tags.test.ts +5 -5
  103. package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
  104. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  105. package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
  106. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
  107. package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
  108. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  109. package/src/__tests__/daemon-assistant-events.test.ts +14 -15
  110. package/src/__tests__/db-test-helpers.ts +13 -27
  111. package/src/__tests__/disk-pressure-routes.test.ts +12 -3
  112. package/src/__tests__/document-tool-security.test.ts +95 -0
  113. package/src/__tests__/drain-kick-guard.test.ts +232 -0
  114. package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
  115. package/src/__tests__/emit-event-signal.test.ts +5 -6
  116. package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
  117. package/src/__tests__/events-tail-route.test.ts +6 -4
  118. package/src/__tests__/feature-flag-test-helpers.ts +10 -20
  119. package/src/__tests__/file-edit-tool.test.ts +24 -4
  120. package/src/__tests__/file-list-tool.test.ts +2 -1
  121. package/src/__tests__/file-read-tool.test.ts +62 -10
  122. package/src/__tests__/file-write-tool.test.ts +24 -5
  123. package/src/__tests__/followup-tools.test.ts +58 -0
  124. package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
  125. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  126. package/src/__tests__/guardian-question-mode.test.ts +42 -3
  127. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
  128. package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
  129. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  130. package/src/__tests__/heartbeat-service.test.ts +1 -0
  131. package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
  132. package/src/__tests__/host-browser-proxy.test.ts +1 -1
  133. package/src/__tests__/host-file-edit-tool.test.ts +3 -3
  134. package/src/__tests__/host-file-read-tool.test.ts +2 -2
  135. package/src/__tests__/host-file-write-tool.test.ts +7 -3
  136. package/src/__tests__/host-shell-tool.test.ts +17 -5
  137. package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
  138. package/src/__tests__/image-credentials.test.ts +65 -8
  139. package/src/__tests__/injection-block.test.ts +4 -4
  140. package/src/__tests__/injector-chain.test.ts +1 -1
  141. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  142. package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
  143. package/src/__tests__/injector-v3-suppression.test.ts +6 -4
  144. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
  145. package/src/__tests__/list-messages-page-latest.test.ts +2 -2
  146. package/src/__tests__/llm-usage-store.test.ts +67 -4
  147. package/src/__tests__/log-redact.test.ts +18 -0
  148. package/src/__tests__/managed-profile-guard.test.ts +27 -0
  149. package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
  150. package/src/__tests__/media-generate-image.test.ts +62 -11
  151. package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
  153. package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
  154. package/src/__tests__/notification-decision-strategy.test.ts +115 -11
  155. package/src/__tests__/notification-deep-link.test.ts +12 -12
  156. package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
  157. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  158. package/src/__tests__/path-policy.test.ts +315 -0
  159. package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
  160. package/src/__tests__/persistence-layering-guard.test.ts +2 -2
  161. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  162. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
  163. package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
  164. package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
  165. package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
  166. package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
  167. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  168. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
  169. package/src/__tests__/require-fresh-approval.test.ts +38 -38
  170. package/src/__tests__/run-due-schedules.test.ts +72 -1
  171. package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
  172. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  173. package/src/__tests__/schedule-routes.test.ts +44 -5
  174. package/src/__tests__/schedule-store.test.ts +3 -3
  175. package/src/__tests__/schedule-tools.test.ts +176 -0
  176. package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
  177. package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
  178. package/src/__tests__/secret-response-routing.test.ts +3 -3
  179. package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
  180. package/src/__tests__/secret-scanner.test.ts +36 -0
  181. package/src/__tests__/send-endpoint-busy.test.ts +7 -7
  182. package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
  183. package/src/__tests__/starter-task-flow.test.ts +6 -3
  184. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  185. package/src/__tests__/subagent-disposal.test.ts +40 -11
  186. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  187. package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
  188. package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
  189. package/src/__tests__/subagent-manager-notify.test.ts +73 -14
  190. package/src/__tests__/subagent-notify-parent.test.ts +48 -4
  191. package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
  192. package/src/__tests__/subagent-tools.test.ts +64 -0
  193. package/src/__tests__/sync-message-contract.test.ts +3 -3
  194. package/src/__tests__/terminal-tools.test.ts +12 -3
  195. package/src/__tests__/test-preload.ts +9 -0
  196. package/src/__tests__/tool-approval-handler.test.ts +583 -43
  197. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
  198. package/src/__tests__/tool-executor.test.ts +116 -0
  199. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
  200. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
  201. package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
  202. package/src/__tests__/tool-start-timestamp.test.ts +4 -4
  203. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
  204. package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
  205. package/src/__tests__/ui-work-result-surface.test.ts +3 -3
  206. package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
  207. package/src/__tests__/voice-session-bridge.test.ts +44 -44
  208. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
  209. package/src/__tests__/workspace-policy.test.ts +399 -0
  210. package/src/acp/__tests__/client-handler.test.ts +3 -3
  211. package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
  212. package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
  213. package/src/acp/client-handler.ts +3 -3
  214. package/src/acp/session-manager.ts +8 -8
  215. package/src/api/events/subagent-event.ts +2 -2
  216. package/src/api/responses/memory-v2-activation-log.ts +2 -2
  217. package/src/approvals/AGENTS.md +2 -0
  218. package/src/approvals/guardian-request-resolvers.ts +118 -24
  219. package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
  220. package/src/calls/__tests__/voice-session-bridge.test.ts +158 -4
  221. package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
  222. package/src/calls/call-controller.ts +27 -27
  223. package/src/calls/call-conversation-messages.ts +58 -18
  224. package/src/calls/voice-control-protocol.ts +56 -0
  225. package/src/calls/voice-session-bridge.ts +156 -58
  226. package/src/calls/voice-triage-escalate.ts +2 -3
  227. package/src/channels/config.ts +8 -0
  228. package/src/channels/types.ts +1 -0
  229. package/src/cli/commands/config.ts +49 -13
  230. package/src/cli/commands/memory/index.help.ts +4 -2
  231. package/src/cli/commands/memory/memory-retrospective.ts +5 -0
  232. package/src/cli/lib/bundled-marketplace.json +12 -0
  233. package/src/cli.ts +2 -109
  234. package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
  235. package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
  236. package/src/config/assistant-feature-flags.ts +1 -1
  237. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
  238. package/src/config/feature-flag-cache.ts +6 -16
  239. package/src/config/feature-flag-registry.json +14 -30
  240. package/src/config/loader.ts +7 -1
  241. package/src/config/memory-tier.ts +15 -10
  242. package/src/config/memory-v3-gate.test.ts +278 -1
  243. package/src/config/memory-v3-gate.ts +88 -26
  244. package/src/config/raw-config-utils.ts +1 -1
  245. package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
  246. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  247. package/src/config/schemas/live-voice.ts +33 -7
  248. package/src/config/schemas/llm.ts +1 -0
  249. package/src/config/schemas/memory-retrospective.ts +13 -0
  250. package/src/config/schemas/memory-substrate.ts +183 -0
  251. package/src/config/schemas/memory-v2.ts +3 -2
  252. package/src/config/schemas/memory-v3.ts +11 -4
  253. package/src/config/schemas/memory.ts +35 -1
  254. package/src/config/schemas/services.ts +10 -2
  255. package/src/config/substrate-twin-shadowing.ts +195 -0
  256. package/src/config/webhook-routing.ts +67 -0
  257. package/src/context/compactor.ts +10 -3
  258. package/src/context/token-estimator.ts +21 -0
  259. package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
  260. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
  261. package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
  262. package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
  263. package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
  264. package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
  265. package/src/daemon/channel-ui-capability.ts +70 -1
  266. package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
  267. package/src/daemon/conversation-agent-loop.ts +12 -5
  268. package/src/daemon/conversation-evictor.ts +26 -4
  269. package/src/daemon/conversation-launch.ts +11 -14
  270. package/src/daemon/conversation-messaging.ts +14 -14
  271. package/src/daemon/conversation-notifiers.ts +2 -2
  272. package/src/daemon/conversation-process.ts +133 -21
  273. package/src/daemon/conversation-queue-manager.ts +7 -7
  274. package/src/daemon/conversation-runtime-assembly.ts +16 -0
  275. package/src/daemon/conversation-store.ts +11 -3
  276. package/src/daemon/conversation-surfaces.ts +4 -4
  277. package/src/daemon/conversation-tool-setup.ts +13 -7
  278. package/src/daemon/conversation-usage.ts +12 -11
  279. package/src/daemon/conversation.ts +38 -15
  280. package/src/daemon/disk-pressure-guard.ts +5 -12
  281. package/src/daemon/embedding-reconcile.ts +14 -9
  282. package/src/daemon/handlers/config-channels.ts +40 -134
  283. package/src/daemon/handlers/config-model.ts +15 -7
  284. package/src/daemon/handlers/conversations.ts +4 -2
  285. package/src/daemon/handlers/shared.ts +29 -0
  286. package/src/daemon/host-proxy-base.ts +4 -4
  287. package/src/daemon/lifecycle.ts +13 -0
  288. package/src/daemon/message-protocol.ts +8 -144
  289. package/src/daemon/message-types/computer-use.ts +0 -12
  290. package/src/daemon/message-types/conversations.ts +9 -345
  291. package/src/daemon/message-types/host-app-control.ts +0 -9
  292. package/src/daemon/message-types/host-browser.ts +0 -7
  293. package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
  294. package/src/daemon/message-types/messages.ts +0 -48
  295. package/src/daemon/message-types/notifications.ts +0 -7
  296. package/src/daemon/message-types/skills.ts +0 -5
  297. package/src/daemon/message-types/surfaces.ts +0 -9
  298. package/src/daemon/message-types/sync.ts +0 -2
  299. package/src/daemon/process-message.ts +5 -5
  300. package/src/daemon/skill-memory-refresh.ts +5 -5
  301. package/src/daemon/tool-side-effects.ts +13 -13
  302. package/src/daemon/trust-context.ts +1 -1
  303. package/src/daemon/wake-conversation-ops.ts +4 -4
  304. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
  305. package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
  306. package/src/heartbeat/heartbeat-run-store.ts +81 -4
  307. package/src/heartbeat/heartbeat-service.ts +32 -1
  308. package/src/home/__tests__/feed-writer.test.ts +7 -7
  309. package/src/home/__tests__/home-content-refresh.test.ts +3 -0
  310. package/src/home/__tests__/suggested-prompts.test.ts +1 -0
  311. package/src/home/feed-writer.ts +6 -13
  312. package/src/home/home-content-refresh.ts +6 -9
  313. package/src/home/relationship-state-writer.ts +5 -12
  314. package/src/home/suggested-prompts-cache.ts +6 -19
  315. package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
  316. package/src/ipc/events-publish-client.ts +44 -0
  317. package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
  318. package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
  319. package/src/ipc/routes/events-ipc-routes.ts +11 -31
  320. package/src/live-voice/__tests__/front-decision.test.ts +4 -176
  321. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
  322. package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
  323. package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
  324. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
  325. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
  326. package/src/live-voice/__tests__/live-voice-vad.test.ts +218 -422
  327. package/src/live-voice/front-decision.ts +5 -155
  328. package/src/live-voice/live-voice-metrics.ts +4 -1
  329. package/src/live-voice/live-voice-session.ts +650 -333
  330. package/src/live-voice/progress-phrases.ts +17 -0
  331. package/src/live-voice/protocol.ts +15 -0
  332. package/src/media/app-icon-generator.ts +15 -8
  333. package/src/media/avatar-router.ts +9 -5
  334. package/src/media/image-credentials.ts +42 -10
  335. package/src/media/image-service.ts +1 -13
  336. package/src/media/types.ts +26 -3
  337. package/src/notifications/AGENTS.md +2 -0
  338. package/src/notifications/__tests__/broadcaster.test.ts +95 -0
  339. package/src/notifications/adapters/macos.ts +3 -3
  340. package/src/notifications/broadcaster.ts +57 -0
  341. package/src/notifications/copy-composer.ts +0 -15
  342. package/src/notifications/decision-engine.ts +21 -22
  343. package/src/notifications/guardian-question-mode.ts +57 -2
  344. package/src/notifications/home-feed-side-effect.ts +4 -0
  345. package/src/notifications/signal.ts +6 -4
  346. package/src/notifications/trusted-contact-payloads.ts +3 -4
  347. package/src/notifications/vellum-card-affinity.ts +39 -0
  348. package/src/oauth/AGENTS.md +1 -1
  349. package/src/permissions/channel-permission-query.test.ts +69 -0
  350. package/src/permissions/channel-permission-query.ts +73 -1
  351. package/src/permissions/checker.test.ts +85 -9
  352. package/src/permissions/checker.ts +17 -22
  353. package/src/permissions/confirmation-guardian-request.test.ts +2 -2
  354. package/src/permissions/confirmation-guardian-request.ts +2 -2
  355. package/src/permissions/gateway-threshold-reader.test.ts +224 -17
  356. package/src/permissions/gateway-threshold-reader.ts +82 -10
  357. package/src/permissions/ipc-risk-types.ts +8 -0
  358. package/src/permissions/prompter.ts +5 -5
  359. package/src/permissions/question-guardian-request.test.ts +222 -0
  360. package/src/permissions/question-guardian-request.ts +179 -0
  361. package/src/permissions/question-prompter.test.ts +8 -8
  362. package/src/permissions/question-prompter.ts +18 -0
  363. package/src/permissions/secret-prompter.ts +2 -4
  364. package/src/permissions/workspace-policy.ts +236 -34
  365. package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
  366. package/src/persistence/__tests__/message-content-file.test.ts +58 -3
  367. package/src/persistence/conversation-crud.ts +93 -0
  368. package/src/persistence/conversation-key-store.ts +63 -0
  369. package/src/persistence/db-async-query.ts +1 -1
  370. package/src/persistence/db-singleton.ts +14 -27
  371. package/src/persistence/delivery-crud.ts +45 -0
  372. package/src/persistence/embeddings/embedding-backend.ts +2 -1
  373. package/src/persistence/embeddings/embedding-identity.ts +7 -3
  374. package/src/persistence/job-utils.ts +32 -27
  375. package/src/persistence/jobs-store.ts +92 -3
  376. package/src/persistence/lifecycle-quiesce.ts +80 -0
  377. package/src/persistence/llm-usage-store.ts +45 -8
  378. package/src/persistence/message-content-file.ts +4 -4
  379. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
  380. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
  381. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
  382. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
  383. package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
  384. package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
  385. package/src/persistence/schema/infrastructure.ts +11 -0
  386. package/src/persistence/steps.ts +7 -1
  387. package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
  388. package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
  389. package/src/plugin-api/conversation-turn.ts +4 -4
  390. package/src/plugin-api/event-hub-facade.ts +15 -6
  391. package/src/plugin-api/index.ts +10 -4
  392. package/src/plugin-api/publish-event.ts +36 -0
  393. package/src/plugins/AGENTS.md +2 -0
  394. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  395. package/src/plugins/defaults/index.ts +9 -13
  396. package/src/plugins/defaults/memory/AGENTS.md +775 -0
  397. package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
  398. package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
  399. package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
  400. package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
  401. package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
  402. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
  403. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
  404. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
  405. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
  406. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
  407. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
  408. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
  409. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  410. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
  411. package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
  412. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
  413. package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
  414. package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
  415. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
  416. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
  417. package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
  418. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
  419. package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
  420. package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
  421. package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
  422. package/src/plugins/defaults/memory/graph/store.ts +1 -0
  423. package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
  424. package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
  425. package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
  426. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
  427. package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
  428. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
  429. package/src/plugins/defaults/memory/indexer.ts +146 -89
  430. package/src/plugins/defaults/memory/injectors.ts +86 -41
  431. package/src/plugins/defaults/memory/job-handlers.ts +130 -39
  432. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
  433. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
  434. package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
  435. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
  436. package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
  437. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
  438. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
  439. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
  440. package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
  441. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
  442. package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
  443. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
  444. package/src/plugins/defaults/memory/startup.ts +58 -21
  445. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
  446. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
  447. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
  448. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
  449. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
  450. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
  451. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
  452. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
  453. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
  454. package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
  455. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
  456. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
  457. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
  458. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
  459. package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
  460. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
  461. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
  462. package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
  463. package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
  464. package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
  465. package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
  466. package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
  467. package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
  468. package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
  469. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
  470. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
  471. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
  472. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
  473. package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
  474. package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
  475. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
  476. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
  477. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
  478. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
  479. package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
  480. package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
  481. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
  482. package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
  483. package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
  484. package/src/plugins/defaults/memory/tools.test.ts +1 -1
  485. package/src/plugins/defaults/memory/tools.ts +1 -1
  486. package/src/plugins/defaults/memory/v1/README.md +5 -0
  487. package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
  488. package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
  489. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
  490. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
  491. package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
  492. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
  493. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
  494. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
  495. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
  496. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
  497. package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
  498. package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
  499. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
  500. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
  501. package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
  502. package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
  503. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
  504. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
  505. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
  506. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
  507. package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
  508. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
  509. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
  510. package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
  511. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
  512. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
  513. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
  514. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
  515. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
  516. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
  517. package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
  518. package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
  519. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
  520. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
  521. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
  522. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
  523. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
  524. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
  525. package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
  526. package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
  527. package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
  528. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
  529. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
  530. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
  531. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
  532. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  533. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  534. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
  535. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
  536. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
  537. package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
  538. package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
  539. package/src/plugins/defaults/memory/v2/activation.ts +30 -163
  540. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
  541. package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
  542. package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
  543. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
  544. package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
  545. package/src/plugins/defaults/memory/v2/injection.ts +36 -26
  546. package/src/plugins/defaults/memory/v2/migration.ts +2 -2
  547. package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
  548. package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
  549. package/src/plugins/defaults/memory/v2/router.ts +38 -15
  550. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
  551. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
  552. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
  553. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
  554. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
  555. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
  556. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
  557. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
  558. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
  559. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
  560. package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
  561. package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
  562. package/src/plugins/defaults/memory/v3/card.ts +25 -9
  563. package/src/plugins/defaults/memory/v3/edge.ts +52 -18
  564. package/src/plugins/defaults/memory/v3/gate.ts +4 -4
  565. package/src/plugins/defaults/memory/v3/injector.ts +10 -3
  566. package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
  567. package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
  568. package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
  569. package/src/plugins/defaults/memory/v3/prune.ts +40 -16
  570. package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
  571. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
  572. package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
  573. package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
  574. package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
  575. package/src/plugins/defaults/memory/v3/types.ts +4 -1
  576. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
  577. package/src/plugins/defaults/memory/validation.ts +1 -1
  578. package/src/plugins/defaults/memory/worker.ts +2 -1
  579. package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
  580. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
  581. package/src/plugins/types.ts +2 -2
  582. package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
  583. package/src/providers/anthropic/client.ts +15 -6
  584. package/src/providers/content-block-schema.ts +26 -0
  585. package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
  586. package/src/providers/inference/adapter-factory.ts +6 -0
  587. package/src/providers/inference/connections.ts +30 -14
  588. package/src/providers/model-catalog.ts +77 -0
  589. package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
  590. package/src/providers/openai/chat-completions-provider.ts +65 -17
  591. package/src/providers/openai/input-audio.ts +76 -0
  592. package/src/providers/openrouter/client.ts +0 -2
  593. package/src/providers/platform-proxy/constants.ts +4 -0
  594. package/src/providers/poolside/client.ts +42 -0
  595. package/src/providers/registry.ts +40 -8
  596. package/src/providers/retry.ts +2 -0
  597. package/src/providers/types.ts +39 -1
  598. package/src/providers/vercel-ai-gateway/client.ts +0 -2
  599. package/src/runtime/AGENTS.md +7 -5
  600. package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
  601. package/src/runtime/__tests__/question-resolution.test.ts +111 -0
  602. package/src/runtime/access-request-helper.ts +7 -15
  603. package/src/runtime/assistant-event-hub.ts +43 -31
  604. package/src/runtime/assistant-event-publish-options.ts +31 -0
  605. package/src/runtime/assistant-event.ts +19 -30
  606. package/src/runtime/assistant-stream-state.ts +4 -4
  607. package/src/runtime/channel-approvals.ts +0 -25
  608. package/src/runtime/channel-readiness-service.ts +99 -40
  609. package/src/runtime/channel-retry-sweep.ts +38 -15
  610. package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
  611. package/src/runtime/guardian-reply-router.ts +108 -0
  612. package/src/runtime/http-server.ts +8 -0
  613. package/src/runtime/http-types.ts +2 -2
  614. package/src/runtime/process-role.ts +42 -0
  615. package/src/runtime/question-request-guardian-bridge.ts +184 -0
  616. package/src/runtime/question-resolution.ts +153 -0
  617. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
  618. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
  619. package/src/runtime/routes/acp-routes.ts +2 -2
  620. package/src/runtime/routes/bookmark-routes.ts +3 -15
  621. package/src/runtime/routes/canned-message-complete.ts +2 -2
  622. package/src/runtime/routes/consolidation-routes.ts +8 -2
  623. package/src/runtime/routes/conversation-list-routes.ts +3 -19
  624. package/src/runtime/routes/conversation-management-routes.ts +1 -5
  625. package/src/runtime/routes/conversation-query-routes.ts +52 -8
  626. package/src/runtime/routes/conversation-routes.ts +36 -22
  627. package/src/runtime/routes/credential-request-routes.ts +0 -1
  628. package/src/runtime/routes/filing-routes.ts +7 -7
  629. package/src/runtime/routes/global-search-routes.ts +1 -1
  630. package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
  631. package/src/runtime/routes/image-generation-routes.ts +12 -9
  632. package/src/runtime/routes/inbound-message-handler.ts +17 -0
  633. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
  634. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
  635. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
  636. package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
  637. package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
  638. package/src/runtime/routes/index.ts +2 -0
  639. package/src/runtime/routes/lifecycle-routes.ts +199 -0
  640. package/src/runtime/routes/platform-routes.ts +3 -8
  641. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
  642. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
  643. package/src/runtime/routes/question-routes.ts +34 -87
  644. package/src/runtime/routes/secret-routes.ts +11 -1
  645. package/src/runtime/routes/settings-routes.ts +8 -18
  646. package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
  647. package/src/runtime/routes/workspace-routes.test.ts +7 -4
  648. package/src/runtime/slack-reply-session.test.ts +12 -12
  649. package/src/runtime/slack-reply-session.ts +17 -17
  650. package/src/runtime/sync/sync-publisher.test.ts +7 -5
  651. package/src/runtime/tool-grant-request-helper.ts +4 -0
  652. package/src/schedule/schedule-store.ts +70 -0
  653. package/src/schedule/scheduler.ts +27 -0
  654. package/src/security/AGENTS.md +1 -1
  655. package/src/security/credential-key.ts +17 -0
  656. package/src/security/secret-ingress.ts +14 -105
  657. package/src/security/secret-patterns.ts +8 -139
  658. package/src/security/secret-scanner.ts +8 -3
  659. package/src/security/store-path-override.ts +6 -16
  660. package/src/sequence/store.ts +8 -0
  661. package/src/signals/emit-event.ts +5 -10
  662. package/src/signals/event-stream.ts +20 -10
  663. package/src/subagent/manager.ts +76 -25
  664. package/src/subagent/notify.ts +8 -0
  665. package/src/subagent/types.ts +13 -3
  666. package/src/telegram/__tests__/webhook-health.test.ts +442 -0
  667. package/src/telegram/webhook-health.ts +478 -0
  668. package/src/telemetry/AGENTS.md +6 -0
  669. package/src/telemetry/memory-corpus-size.test.ts +129 -0
  670. package/src/telemetry/memory-corpus-size.ts +184 -0
  671. package/src/telemetry/memory-tier-reporter.test.ts +67 -2
  672. package/src/telemetry/memory-tier-reporter.ts +30 -3
  673. package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
  674. package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
  675. package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
  676. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
  677. package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
  678. package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
  679. package/src/tools/acp/abort.ts +21 -1
  680. package/src/tools/acp/context.ts +5 -5
  681. package/src/tools/acp/spawn.test.ts +15 -5
  682. package/src/tools/acp/spawn.ts +26 -3
  683. package/src/tools/acp/status.ts +20 -1
  684. package/src/tools/acp/steer.test.ts +20 -0
  685. package/src/tools/acp/steer.ts +23 -2
  686. package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
  687. package/src/tools/ask-question/ask-question-tool.ts +68 -92
  688. package/src/tools/browser/browser-screencast.ts +6 -6
  689. package/src/tools/calls/call-end.ts +24 -3
  690. package/src/tools/calls/call-start.ts +35 -11
  691. package/src/tools/calls/call-status.ts +20 -1
  692. package/src/tools/document/document-comment-tool.test.ts +49 -0
  693. package/src/tools/document/document-comment-tool.ts +45 -6
  694. package/src/tools/document/document-tool.ts +142 -24
  695. package/src/tools/executor.ts +27 -13
  696. package/src/tools/filesystem/edit.ts +62 -60
  697. package/src/tools/filesystem/list.ts +36 -29
  698. package/src/tools/filesystem/read.ts +56 -39
  699. package/src/tools/filesystem/write.ts +44 -38
  700. package/src/tools/followups/followup_create.ts +41 -12
  701. package/src/tools/followups/followup_list.ts +34 -6
  702. package/src/tools/followups/followup_resolve.ts +26 -4
  703. package/src/tools/host-filesystem/edit.ts +50 -60
  704. package/src/tools/host-filesystem/read.ts +45 -39
  705. package/src/tools/host-filesystem/write.ts +31 -36
  706. package/src/tools/host-terminal/host-shell.ts +76 -62
  707. package/src/tools/policy-context.ts +27 -10
  708. package/src/tools/schedule/create.ts +76 -33
  709. package/src/tools/schedule/delete.ts +21 -2
  710. package/src/tools/schedule/list.ts +25 -3
  711. package/src/tools/schedule/update.ts +105 -48
  712. package/src/tools/shared/filesystem/path-policy.ts +246 -40
  713. package/src/tools/shared/zod-tool-schema.ts +117 -0
  714. package/src/tools/subagent/abort.ts +12 -4
  715. package/src/tools/subagent/consult-deadline.ts +9 -3
  716. package/src/tools/subagent/message.ts +21 -5
  717. package/src/tools/subagent/notify-parent.ts +44 -23
  718. package/src/tools/subagent/read.ts +15 -4
  719. package/src/tools/subagent/resolve.ts +26 -4
  720. package/src/tools/subagent/spawn.ts +37 -13
  721. package/src/tools/subagent/status.ts +12 -4
  722. package/src/tools/system/request-permission.ts +35 -26
  723. package/src/tools/terminal/shell.ts +68 -55
  724. package/src/tools/tool-approval-handler.ts +327 -53
  725. package/src/tools/tool-input-schemas.ts +85 -0
  726. package/src/tools/tool-types.ts +7 -0
  727. package/src/tools/types.ts +8 -0
  728. package/src/tools/workflows/manage-workflows.ts +30 -2
  729. package/src/tools/workflows/run-workflow.test.ts +54 -2
  730. package/src/tools/workflows/run-workflow.ts +32 -4
  731. package/src/util/fs-symlinks.ts +30 -0
  732. package/src/util/log-redact.ts +7 -3
  733. package/src/vellum-assistant-namespace.d.ts +80 -0
  734. package/src/watcher/watcher-store.ts +8 -0
  735. package/src/workflows/leaf-runner.test.ts +104 -2
  736. package/src/workflows/leaf-runner.ts +31 -6
  737. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
  738. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
  739. package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
  740. package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
  741. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
  742. package/src/workspace/migrations/registry.ts +4 -0
  743. package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
  744. package/src/__tests__/secret-patterns.test.ts +0 -27
  745. package/src/config/__tests__/proc-to-skills.test.ts +0 -21
  746. package/src/config/memory-tier.test.ts +0 -44
  747. package/src/daemon/message-types/acp.ts +0 -20
  748. package/src/daemon/message-types/apps.ts +0 -11
  749. package/src/daemon/message-types/background-tools.ts +0 -14
  750. package/src/daemon/message-types/bookmarks.ts +0 -13
  751. package/src/daemon/message-types/contacts.ts +0 -13
  752. package/src/daemon/message-types/document-comments.ts +0 -14
  753. package/src/daemon/message-types/documents.ts +0 -13
  754. package/src/daemon/message-types/home.ts +0 -15
  755. package/src/daemon/message-types/host-bash.ts +0 -12
  756. package/src/daemon/message-types/host-cu.ts +0 -10
  757. package/src/daemon/message-types/host-file.ts +0 -12
  758. package/src/daemon/message-types/host-transfer.ts +0 -12
  759. package/src/daemon/message-types/integrations.ts +0 -90
  760. package/src/daemon/message-types/memory.ts +0 -10
  761. package/src/daemon/message-types/schedules.ts +0 -14
  762. package/src/daemon/message-types/settings.ts +0 -17
  763. package/src/daemon/message-types/subagents.ts +0 -63
  764. package/src/daemon/message-types/upgrades.ts +0 -14
  765. package/src/daemon/message-types/workflows.ts +0 -25
  766. package/src/daemon/message-types/workspace.ts +0 -137
  767. package/src/live-voice/ack-phrases.ts +0 -58
  768. package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
  769. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
  770. package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
  771. package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
  772. package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
  773. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  774. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
  775. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
  776. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
@@ -1,4 +1,14 @@
1
- import { desc, eq, lt, sql } from "drizzle-orm";
1
+ import {
2
+ and,
3
+ desc,
4
+ eq,
5
+ gt,
6
+ inArray,
7
+ isNotNull,
8
+ lt,
9
+ notInArray,
10
+ sql,
11
+ } from "drizzle-orm";
2
12
  import { v4 as uuid } from "uuid";
3
13
 
4
14
  import { getDb } from "../persistence/db-connection.js";
@@ -25,7 +35,8 @@ export type HeartbeatSkipReason =
25
35
  | "overlap"
26
36
  | "pre_first_user_message"
27
37
  | "max_consecutive_runs"
28
- | "max_daily_runs";
38
+ | "max_daily_runs"
39
+ | "quiesced";
29
40
 
30
41
  export interface HeartbeatRunRecord {
31
42
  id: string;
@@ -271,7 +282,19 @@ export function countRecentConsecutiveRuns(maxToCheck: number): number {
271
282
  }
272
283
 
273
284
  /**
274
- * List heartbeat runs ordered by `scheduledFor` descending.
285
+ * Statuses excluded from run history: scheduler bookkeeping rows, not runs.
286
+ * `pending` is the not-yet-fired next scheduled run (surfaced separately as
287
+ * "next run"), and `superseded` rows are pending rows replaced by a timer
288
+ * reset — a guardian message resets the heartbeat timer, so an active chat
289
+ * day leaves dozens of them behind without a single heartbeat firing.
290
+ */
291
+ const BOOKKEEPING_STATUSES: HeartbeatRunStatus[] = ["pending", "superseded"];
292
+
293
+ /**
294
+ * List heartbeat run history ordered by `scheduledFor` descending.
295
+ * Bookkeeping rows ({@link BOOKKEEPING_STATUSES}) are excluded — every
296
+ * returned row is a run that executed, was skipped by a guard (with its
297
+ * `skipReason`), or was missed while the daemon was down.
275
298
  * When `before` is set, only runs with `scheduledFor` strictly older than it
276
299
  * are returned (cursor for paginating into history).
277
300
  */
@@ -280,16 +303,70 @@ export function listHeartbeatRuns(
280
303
  before?: number,
281
304
  ): HeartbeatRunRecord[] {
282
305
  const db = getDb();
306
+ const historyOnly = notInArray(heartbeatRuns.status, BOOKKEEPING_STATUSES);
283
307
  const rows = db
284
308
  .select()
285
309
  .from(heartbeatRuns)
286
- .where(before != null ? lt(heartbeatRuns.scheduledFor, before) : undefined)
310
+ .where(
311
+ before != null
312
+ ? and(lt(heartbeatRuns.scheduledFor, before), historyOnly)
313
+ : historyOnly,
314
+ )
287
315
  .orderBy(desc(heartbeatRuns.scheduledFor))
288
316
  .limit(limit)
289
317
  .all();
290
318
  return rows.map(parseRow);
291
319
  }
292
320
 
321
+ /** Terminal statuses of runs that actually executed. */
322
+ const EXECUTED_STATUSES: HeartbeatRunStatus[] = ["ok", "error", "timeout"];
323
+
324
+ /**
325
+ * Epoch-ms timestamp of the most recent heartbeat run that actually executed
326
+ * (reached `ok`, `error`, or `timeout`), or null when none exists. Uses
327
+ * `finishedAt`, falling back to `startedAt` for rows finalized by a crash
328
+ * sweep without one.
329
+ */
330
+ export function getLastHeartbeatRunAt(): number | null {
331
+ const db = getDb();
332
+ const row = db
333
+ .select({
334
+ lastRunAt: sql<
335
+ number | null
336
+ >`max(coalesce(${heartbeatRuns.finishedAt}, ${heartbeatRuns.startedAt}))`,
337
+ })
338
+ .from(heartbeatRuns)
339
+ .where(inArray(heartbeatRuns.status, EXECUTED_STATUSES))
340
+ .get();
341
+ return row?.lastRunAt ?? null;
342
+ }
343
+
344
+ /**
345
+ * Heartbeat runs currently `running`, capped to those started within
346
+ * `maxAgeMs`. The age bound matters: a run orphaned by a crash keeps its
347
+ * `running` status until a later boot's stale sweep relabels it, and an
348
+ * unbounded read would let that phantom row hold a drain open indefinitely.
349
+ */
350
+ export function listRunningHeartbeatRuns(
351
+ maxAgeMs: number,
352
+ ): Array<{ runId: string; startedAt: number }> {
353
+ const db = getDb();
354
+ const cutoff = Date.now() - maxAgeMs;
355
+ return db
356
+ .select({ runId: heartbeatRuns.id, startedAt: heartbeatRuns.startedAt })
357
+ .from(heartbeatRuns)
358
+ .where(
359
+ and(
360
+ eq(heartbeatRuns.status, "running"),
361
+ isNotNull(heartbeatRuns.startedAt),
362
+ gt(heartbeatRuns.startedAt, cutoff),
363
+ ),
364
+ )
365
+ .orderBy(desc(heartbeatRuns.startedAt))
366
+ .limit(20)
367
+ .all() as Array<{ runId: string; startedAt: number }>;
368
+ }
369
+
293
370
  // ---------------------------------------------------------------------------
294
371
  // Internal helpers
295
372
  // ---------------------------------------------------------------------------
@@ -11,6 +11,7 @@ import {
11
11
  shouldLogDiskPressureBackgroundSkip,
12
12
  } from "../daemon/disk-pressure-background-gate.js";
13
13
  import { emitNotificationSignal } from "../notifications/emit-signal.js";
14
+ import { isLifecycleQuiesced } from "../persistence/lifecycle-quiesce.js";
14
15
  import {
15
16
  GUARDIAN_PERSONA_TEMPLATE,
16
17
  resolveGuardianPersona,
@@ -29,6 +30,7 @@ import {
29
30
  countCompletedHeartbeatRuns,
30
31
  countCompletedRunsToday,
31
32
  countRecentConsecutiveRuns,
33
+ getLastHeartbeatRunAt,
32
34
  insertPendingHeartbeatRun,
33
35
  markStaleRunningAsError,
34
36
  markStaleRunsAsMissed,
@@ -168,8 +170,23 @@ export class HeartbeatService {
168
170
  HeartbeatService.instance = this;
169
171
  }
170
172
 
171
- /** Epoch-ms timestamp of the last completed heartbeat run. */
173
+ /**
174
+ * Epoch-ms timestamp of the last completed heartbeat run. The in-memory
175
+ * field only covers runs completed in this process's lifetime, so when it
176
+ * is unset the value is rehydrated from run history — a daemon restart
177
+ * must not blank "last run" while completed runs exist in the database.
178
+ */
172
179
  get lastRunAt(): number | null {
180
+ if (this._lastRunAt == null) {
181
+ try {
182
+ this._lastRunAt = getLastHeartbeatRunAt();
183
+ } catch (err) {
184
+ // DB unavailable (e.g. migrations still settling) — report unknown
185
+ // and retry on the next read.
186
+ log.debug({ err }, "Failed to read last heartbeat run from history");
187
+ return null;
188
+ }
189
+ }
173
190
  return this._lastRunAt;
174
191
  }
175
192
 
@@ -486,6 +503,20 @@ export class HeartbeatService {
486
503
  return false;
487
504
  }
488
505
 
506
+ // Drain guard: while a quiesce lease is active (a client is waiting for
507
+ // background work to finish before stopping the assistant), do not start
508
+ // new beats. Recorded as a skipped run so run history explains the gap.
509
+ if (!force && isLifecycleQuiesced()) {
510
+ log.info("Heartbeat skipped — quiesce lease active");
511
+ if (runId) {
512
+ skipHeartbeatRun(runId, "quiesced");
513
+ }
514
+ if (!this.cronMode) {
515
+ this.scheduleNextRun(config.intervalMs);
516
+ }
517
+ return false;
518
+ }
519
+
489
520
  // Warm-pool guard: skip heartbeats until the user has actually
490
521
  // interacted with the assistant. Heartbeats run the LLM against the
491
522
  // guardian persona, which doesn't exist in a fresh warm-pool image —
@@ -35,7 +35,9 @@ mock.module("../../runtime/assistant-event-hub.js", () => ({
35
35
  // hub's real shape has more fields. Tests never call them.
36
36
  subscribe: () => () => {},
37
37
  },
38
- broadcastMessage: async () => {},
38
+ broadcastMessage: (message: unknown, conversationId?: string) => {
39
+ void publishSpy({ message, conversationId });
40
+ },
39
41
  }));
40
42
 
41
43
  // Dynamic import so the module resolves after the mock above is in
@@ -717,11 +719,7 @@ describe("feed-writer", () => {
717
719
  }),
718
720
  );
719
721
 
720
- const count = await bulkSetFeedItemStatus(
721
- ["new"],
722
- "seen",
723
- ["n1", "n3"],
724
- );
722
+ const count = await bulkSetFeedItemStatus(["new"], "seen", ["n1", "n3"]);
725
723
  expect(count).toBe(2);
726
724
 
727
725
  const decoded = readFileJson();
@@ -734,7 +732,9 @@ describe("feed-writer", () => {
734
732
  test("ids scope with no matching ids returns 0", async () => {
735
733
  await appendFeedItem(makeItem({ id: "n1", status: "new" }));
736
734
 
737
- const count = await bulkSetFeedItemStatus(["new"], "seen", ["nonexistent"]);
735
+ const count = await bulkSetFeedItemStatus(["new"], "seen", [
736
+ "nonexistent",
737
+ ]);
738
738
  expect(count).toBe(0);
739
739
 
740
740
  const decoded = readFileJson();
@@ -26,6 +26,9 @@ mock.module("../suggested-prompts.js", () => ({
26
26
  const publishSpy = mock<(event: unknown) => Promise<void>>(async () => {});
27
27
  mock.module("../../runtime/assistant-event-hub.js", () => ({
28
28
  assistantEventHub: { publish: publishSpy },
29
+ broadcastMessage: (message: unknown) => {
30
+ void publishSpy(message);
31
+ },
29
32
  }));
30
33
 
31
34
  mock.module("../../runtime/assistant-event.js", () => ({
@@ -61,6 +61,7 @@ mock.module("../../runtime/assistant-event.js", () => ({
61
61
 
62
62
  mock.module("../../runtime/assistant-event-hub.js", () => ({
63
63
  assistantEventHub: { publish: async () => {} },
64
+ broadcastMessage: () => {},
64
65
  }));
65
66
 
66
67
  const { getSuggestedPrompts, refreshAssistantSuggestedPrompts } =
@@ -37,8 +37,7 @@
37
37
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
38
38
  import { join } from "node:path";
39
39
 
40
- import { buildAssistantEvent } from "../runtime/assistant-event.js";
41
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
40
+ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
42
41
  import { getLogger } from "../util/logger.js";
43
42
  import { getDataDir } from "../util/platform.js";
44
43
  import {
@@ -523,15 +522,9 @@ function compareFeedItems(a: FeedItem, b: FeedItem): number {
523
522
  * writer coalescing loop.
524
523
  */
525
524
  function publishHomeFeedUpdated(updatedAt: string, newItemCount: number): void {
526
- assistantEventHub
527
- .publish(
528
- buildAssistantEvent({
529
- type: "home_feed_updated",
530
- updatedAt,
531
- newItemCount,
532
- }),
533
- )
534
- .catch((err) => {
535
- log.warn({ err }, "Failed to publish home_feed_updated event");
536
- });
525
+ broadcastMessage({
526
+ type: "home_feed_updated",
527
+ updatedAt,
528
+ newItemCount,
529
+ });
537
530
  }
@@ -14,8 +14,7 @@
14
14
  * (4 hours each) bound how often a regeneration can happen.
15
15
  */
16
16
 
17
- import { buildAssistantEvent } from "../runtime/assistant-event.js";
18
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
17
+ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
19
18
  import { getLogger } from "../util/logger.js";
20
19
  import { refreshPersonalizedGreeting } from "./home-greeting.js";
21
20
  import { refreshAssistantSuggestedPrompts } from "./suggested-prompts.js";
@@ -34,13 +33,11 @@ async function revalidateAll(): Promise<void> {
34
33
  return;
35
34
  }
36
35
 
37
- await assistantEventHub.publish(
38
- buildAssistantEvent({
39
- type: "home_feed_updated",
40
- updatedAt: new Date().toISOString(),
41
- newItemCount: 0,
42
- }),
43
- );
36
+ broadcastMessage({
37
+ type: "home_feed_updated",
38
+ updatedAt: new Date().toISOString(),
39
+ newItemCount: 0,
40
+ });
44
41
  }
45
42
 
46
43
  /**
@@ -25,8 +25,7 @@ import { getGuardianDelivery } from "../contacts/guardian-delivery-reader.js";
25
25
  import { listConnections } from "../oauth/oauth-store.js";
26
26
  import { countConversations as countConversationsDb } from "../persistence/conversation-queries.js";
27
27
  import { resolveGuardianPersonaPath } from "../prompts/persona-resolver.js";
28
- import { buildAssistantEvent } from "../runtime/assistant-event.js";
29
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
28
+ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
30
29
  import type { OnboardingContext } from "../types/onboarding-context.js";
31
30
  import { getLogger } from "../util/logger.js";
32
31
  import {
@@ -316,16 +315,10 @@ export async function writeRelationshipState(): Promise<void> {
316
315
  * just landed on disk.
317
316
  */
318
317
  function publishRelationshipStateUpdated(updatedAt: string): void {
319
- assistantEventHub
320
- .publish(
321
- buildAssistantEvent({
322
- type: "relationship_state_updated",
323
- updatedAt,
324
- }),
325
- )
326
- .catch((err) => {
327
- log.warn({ err }, "Failed to publish relationship_state_updated event");
328
- });
318
+ broadcastMessage({
319
+ type: "relationship_state_updated",
320
+ updatedAt,
321
+ });
329
322
  }
330
323
 
331
324
  /**
@@ -16,13 +16,9 @@ import {
16
16
  getMemoryCheckpoint,
17
17
  setMemoryCheckpoint,
18
18
  } from "../persistence/checkpoints.js";
19
- import { buildAssistantEvent } from "../runtime/assistant-event.js";
20
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
21
- import { getLogger } from "../util/logger.js";
19
+ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
22
20
  import type { SuggestedPrompt } from "./feed-types.js";
23
21
 
24
- const log = getLogger("suggested-prompts-cache");
25
-
26
22
  const LLM_CACHE_TTL_MS = 4 * 60 * 60 * 1000; // 4 hours
27
23
 
28
24
  const CHECKPOINT_KEY_JSON = "home:suggested_prompts:json";
@@ -74,18 +70,9 @@ export function invalidateAssistantSuggestedPromptsCache(): void {
74
70
  } catch {
75
71
  // Invalidation failure is non-fatal — the TTL still bounds staleness.
76
72
  }
77
- assistantEventHub
78
- .publish(
79
- buildAssistantEvent({
80
- type: "home_feed_updated",
81
- updatedAt: new Date().toISOString(),
82
- newItemCount: 0,
83
- }),
84
- )
85
- .catch((err) => {
86
- log.warn(
87
- { err },
88
- "Failed to publish home_feed_updated after prompt cache invalidation",
89
- );
90
- });
73
+ broadcastMessage({
74
+ type: "home_feed_updated",
75
+ updatedAt: new Date().toISOString(),
76
+ newItemCount: 0,
77
+ });
91
78
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Tests the side-process → daemon publish forwarder. It calls the daemon's
3
+ * `/events/publish` IPC route with the event envelope, and is best-effort: a
4
+ * transport failure is logged, never thrown.
5
+ */
6
+
7
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
8
+
9
+ import type { AssistantEventEnvelope } from "../../api/index.js";
10
+
11
+ interface IpcCall {
12
+ method: string;
13
+ params?: Record<string, unknown>;
14
+ }
15
+ const ipcCalls: IpcCall[] = [];
16
+ let ipcResult: { ok: boolean; error?: string } = { ok: true };
17
+
18
+ mock.module("../cli-client.js", () => ({
19
+ cliIpcCall: async (method: string, params?: Record<string, unknown>) => {
20
+ ipcCalls.push({ method, params });
21
+ return ipcResult;
22
+ },
23
+ }));
24
+
25
+ const { EVENTS_PUBLISH_IPC_METHOD, forwardEventPublishToDaemon } =
26
+ await import("../events-publish-client.js");
27
+
28
+ function event(): AssistantEventEnvelope {
29
+ return {
30
+ id: "e1",
31
+ conversationId: "c1",
32
+ emittedAt: "2026-01-01T00:00:00.000Z",
33
+ message: {
34
+ type: "sync_changed",
35
+ } as unknown as AssistantEventEnvelope["message"],
36
+ };
37
+ }
38
+
39
+ beforeEach(() => {
40
+ ipcCalls.length = 0;
41
+ ipcResult = { ok: true };
42
+ });
43
+
44
+ describe("forwardEventPublishToDaemon", () => {
45
+ test("calls the /events/publish route with the event (and options when present)", async () => {
46
+ await forwardEventPublishToDaemon(event(), { excludeClientId: "tab-1" });
47
+ expect(ipcCalls).toHaveLength(1);
48
+ expect(ipcCalls[0].method).toBe(EVENTS_PUBLISH_IPC_METHOD);
49
+ expect(ipcCalls[0].params).toEqual({
50
+ body: { event: event(), options: { excludeClientId: "tab-1" } },
51
+ });
52
+ });
53
+
54
+ test("passes undefined options through when none are given", async () => {
55
+ await forwardEventPublishToDaemon(event(), undefined);
56
+ expect(ipcCalls[0].params).toEqual({
57
+ body: { event: event(), options: undefined },
58
+ });
59
+ });
60
+
61
+ test("does not throw when the IPC transport fails", async () => {
62
+ ipcResult = { ok: false, error: "connect failed" };
63
+ await expect(
64
+ forwardEventPublishToDaemon(event(), undefined),
65
+ ).resolves.toBeUndefined();
66
+ });
67
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Client transport for forwarding an event publish to the daemon.
3
+ *
4
+ * The daemon owns the event hub and the client connections it fans out to. A
5
+ * side process (a sidecar worker, the route host) that publishes to its *own*
6
+ * in-process hub reaches no SSE subscriber, so it must hand the event to the
7
+ * daemon instead. This module is that hand-off: it calls the daemon's
8
+ * `/events/publish` IPC route ({@link EVENTS_PUBLISH_IPC_METHOD}), which
9
+ * republishes the event on the daemon's real hub.
10
+ *
11
+ * The method-name constant lives here (not in the route module) so callers can
12
+ * import it without pulling in the route handler's dependency graph.
13
+ */
14
+
15
+ import type { AssistantEventEnvelope } from "../api/index.js";
16
+ import type { AssistantEventPublishOptions } from "../runtime/assistant-event-publish-options.js";
17
+ import { getLogger } from "../util/logger.js";
18
+ import { cliIpcCall } from "./cli-client.js";
19
+
20
+ const log = getLogger("events-publish-client");
21
+
22
+ /** IPC method name — the raw publish transport other processes call. */
23
+ export const EVENTS_PUBLISH_IPC_METHOD = "/events/publish";
24
+
25
+ /**
26
+ * Forward an event publish to the daemon over IPC. Best-effort: a transport
27
+ * failure is logged, not thrown — a dropped UI-invalidation must never surface
28
+ * as a handler error (mirroring the local hub, whose subscriber failures are
29
+ * isolated from the publisher).
30
+ */
31
+ export async function forwardEventPublishToDaemon(
32
+ event: AssistantEventEnvelope,
33
+ options: AssistantEventPublishOptions | undefined,
34
+ ): Promise<void> {
35
+ const result = await cliIpcCall(EVENTS_PUBLISH_IPC_METHOD, {
36
+ body: { event, options },
37
+ });
38
+ if (!result.ok) {
39
+ log.warn(
40
+ { err: result.error, eventType: event.message?.type },
41
+ "Failed to forward event publish to the daemon",
42
+ );
43
+ }
44
+ }
@@ -29,13 +29,13 @@ mock.module("../../../runtime/sync/resource-sync-events.js", () => ({
29
29
  },
30
30
  }));
31
31
 
32
+ import type { AssistantEventEnvelope } from "../../../api/index.js";
32
33
  import type { EventHandlerState } from "../../../daemon/conversation-agent-loop-handlers.js";
33
34
  import { DB_MIGRATION_READINESS_EXEMPT_OPERATIONS } from "../../../daemon/daemon-readiness.js";
34
35
  import {
35
36
  registerInflightTurn,
36
37
  unregisterInflightTurn,
37
38
  } from "../../../daemon/inflight-turn-registry.js";
38
- import type { AssistantEvent } from "../../../runtime/assistant-event.js";
39
39
  import {
40
40
  _resetStreamStateForTesting,
41
41
  stampAndBuffer,
@@ -50,7 +50,7 @@ function stampEvent(): void {
50
50
  stampAndBuffer({
51
51
  conversationId: "conv-x",
52
52
  message: { type: "assistant_text_delta", text: "x" },
53
- } as unknown as AssistantEvent);
53
+ } as unknown as AssistantEventEnvelope);
54
54
  }
55
55
 
56
56
  describe("conversation-sync IPC route", () => {
@@ -1,10 +1,8 @@
1
1
  import { afterEach, describe, expect, test } from "bun:test";
2
2
 
3
+ import { EVENTS_PUBLISH_IPC_METHOD } from "../../../ipc/events-publish-client.js";
3
4
  import { assistantEventHub } from "../../../runtime/assistant-event-hub.js";
4
- import {
5
- EVENTS_PUBLISH_IPC_METHOD,
6
- handleEventsPublish,
7
- } from "../events-ipc-routes.js";
5
+ import { handleEventsPublish } from "../events-ipc-routes.js";
8
6
 
9
7
  describe(`${EVENTS_PUBLISH_IPC_METHOD} IPC route`, () => {
10
8
  const disposers: Array<() => void> = [];
@@ -39,17 +37,48 @@ describe(`${EVENTS_PUBLISH_IPC_METHOD} IPC route`, () => {
39
37
  test("publishes a full event envelope onto the daemon hub", async () => {
40
38
  const received = subscribe();
41
39
 
40
+ const message = {
41
+ type: "generation_cancelled",
42
+ conversationId: "conv-events-test",
43
+ };
42
44
  const result = await handleEventsPublish({
43
- body: { event: fullEvent({ type: "test_event", value: 42 }) },
45
+ body: { event: fullEvent(message) },
44
46
  });
45
47
 
46
48
  expect(result).toEqual({ ok: true });
47
49
  expect(received).toHaveLength(1);
48
50
  expect((received[0] as { id: string }).id).toBe("evt-1");
49
- expect((received[0] as { message: unknown }).message).toEqual({
50
- type: "test_event",
51
- value: 42,
51
+ expect((received[0] as { message: unknown }).message).toEqual(message);
52
+ });
53
+
54
+ test("stamps a forwarded conversation-scoped event with a seq for replay", async () => {
55
+ const received = subscribe();
56
+
57
+ // A forwarded event arrives unstamped (the worker that produced it has seq
58
+ // stamping disabled). The daemon boundary must assign a `seq` so the event
59
+ // takes a slot in the SSE replay ring and reconnecting clients see it in
60
+ // order, rather than a gap.
61
+ const event = fullEvent({
62
+ type: "generation_cancelled",
63
+ conversationId: "conv-events-test",
52
64
  });
65
+ expect((event as { seq?: number }).seq).toBeUndefined();
66
+
67
+ await handleEventsPublish({ body: { event } });
68
+
69
+ expect(received).toHaveLength(1);
70
+ expect(typeof (received[0] as { seq?: unknown }).seq).toBe("number");
71
+ });
72
+
73
+ test("rejects a message that is not a known event type", async () => {
74
+ const received = subscribe();
75
+
76
+ await expect(
77
+ handleEventsPublish({
78
+ body: { event: fullEvent({ type: "not_a_real_event" }) },
79
+ }),
80
+ ).rejects.toThrow();
81
+ expect(received).toHaveLength(0);
53
82
  });
54
83
 
55
84
  test("rejects an incomplete envelope (missing id)", async () => {
@@ -60,7 +89,7 @@ describe(`${EVENTS_PUBLISH_IPC_METHOD} IPC route`, () => {
60
89
  body: {
61
90
  event: {
62
91
  emittedAt: "2026-07-21T00:00:00.000Z",
63
- message: { type: "test_event" },
92
+ message: { type: "generation_cancelled" },
64
93
  },
65
94
  },
66
95
  }),
@@ -23,47 +23,27 @@
23
23
  import { z } from "zod";
24
24
 
25
25
  import { AssistantEventEnvelopeSchema } from "../../api/index.js";
26
- import {
27
- HOST_PROXY_CAPABILITIES,
28
- INTERFACE_IDS,
29
- } from "../../channels/types.js";
30
- import type { ServerMessage } from "../../daemon/message-protocol.js";
31
26
  import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
27
+ import { AssistantEventPublishOptionsSchema } from "../../runtime/assistant-event-publish-options.js";
28
+ import { stampAndBuffer } from "../../runtime/assistant-stream-state.js";
32
29
  import type { RouteHandlerArgs } from "../../runtime/routes/types.js";
33
-
34
- /** IPC method name — the raw publish transport other processes call. */
35
- export const EVENTS_PUBLISH_IPC_METHOD = "/events/publish";
36
-
37
- /**
38
- * The event envelope reuses the shared wire schema's transport fields (`id`,
39
- * `emittedAt`, `conversationId`, `seq`) and overrides only `message`: the hub
40
- * publishes runtime `ServerMessage`-typed events, whose union is defined
41
- * separately from the api schema's message union, so the override yields a
42
- * value assignable to `assistantEventHub.publish` without a cast.
43
- */
44
- const EventEnvelopeSchema = AssistantEventEnvelopeSchema.extend({
45
- message: z.custom<ServerMessage>(
46
- (value) => value != null && typeof value === "object",
47
- ),
48
- });
49
-
50
- /** Publish targeting/suppression options — see the hub's `publish`. */
51
- const PublishOptionsSchema = z.object({
52
- targetCapability: z.enum(HOST_PROXY_CAPABILITIES).optional(),
53
- targetClientId: z.string().optional(),
54
- targetInterfaceId: z.enum(INTERFACE_IDS).optional(),
55
- excludeClientId: z.string().optional(),
56
- });
30
+ import { EVENTS_PUBLISH_IPC_METHOD } from "../events-publish-client.js";
57
31
 
58
32
  const EventsPublishParamsSchema = z.object({
59
- event: EventEnvelopeSchema,
60
- options: PublishOptionsSchema.optional(),
33
+ event: AssistantEventEnvelopeSchema,
34
+ options: AssistantEventPublishOptionsSchema.optional(),
61
35
  });
62
36
 
63
37
  export async function handleEventsPublish({
64
38
  body = {},
65
39
  }: RouteHandlerArgs): Promise<{ ok: true }> {
66
40
  const { event, options } = EventsPublishParamsSchema.parse(body);
41
+ // A forwarded event comes from a process where seq stamping is disabled
42
+ // (a worker), so it arrives with no `seq` and was never buffered for SSE
43
+ // replay. The daemon is the seq authority, so stamp + buffer here — at the
44
+ // transport boundary, before fanout — exactly as `broadcastMessage` does on
45
+ // the in-daemon path, so reconnecting clients replay it in order.
46
+ stampAndBuffer(event, { targeting: options });
67
47
  await assistantEventHub.publish(event, options);
68
48
  return { ok: true };
69
49
  }