@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f

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 (866) hide show
  1. package/ARCHITECTURE.md +94 -91
  2. package/Dockerfile +5 -16
  3. package/README.md +7 -10
  4. package/bun.lock +0 -4
  5. package/docs/architecture/security.md +20 -20
  6. package/docs/stt-provider-onboarding.md +4 -5
  7. package/docs/trusted-contact-access.md +7 -7
  8. package/eslint-rules/cli-no-daemon-internals.js +4 -0
  9. package/eslint.config.mjs +7 -1
  10. package/knip.json +0 -1
  11. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
  13. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
  14. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
  15. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
  17. package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
  18. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
  19. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
  21. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
  22. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
  23. package/openapi.yaml +1073 -225
  24. package/package.json +1 -4
  25. package/scripts/test.sh +35 -13
  26. package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
  27. package/src/__tests__/acp-session.test.ts +4 -1
  28. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
  29. package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
  30. package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
  31. package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
  32. package/src/__tests__/app-source-watcher.test.ts +11 -0
  33. package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
  34. package/src/__tests__/assistant-attachments.test.ts +62 -4
  35. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
  36. package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
  37. package/src/__tests__/attachments-store.test.ts +3 -0
  38. package/src/__tests__/background-shell-bash.test.ts +34 -0
  39. package/src/__tests__/background-shell-host-bash.test.ts +12 -0
  40. package/src/__tests__/background-tool-registry.test.ts +97 -0
  41. package/src/__tests__/background-tool-routes.test.ts +72 -1
  42. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  43. package/src/__tests__/btw-routes.test.ts +57 -3
  44. package/src/__tests__/call-controller.test.ts +474 -84
  45. package/src/__tests__/call-domain.test.ts +48 -1
  46. package/src/__tests__/call-pointer-messages.test.ts +57 -19
  47. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
  48. package/src/__tests__/call-routes-http.test.ts +15 -14
  49. package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
  50. package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
  51. package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
  52. package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
  53. package/src/__tests__/call-setup-flow.test.ts +311 -0
  54. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
  55. package/src/__tests__/channel-guardian.test.ts +4 -7
  56. package/src/__tests__/channel-readiness-service.test.ts +0 -6
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
  58. package/src/__tests__/channel-retry-sweep.test.ts +76 -64
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
  60. package/src/__tests__/clear-all-lexical.test.ts +90 -0
  61. package/src/__tests__/compactor-media-strip.test.ts +177 -0
  62. package/src/__tests__/config-loader-backfill.test.ts +5 -5
  63. package/src/__tests__/config-schema.test.ts +17 -0
  64. package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
  65. package/src/__tests__/contacts-relay-reads.test.ts +188 -23
  66. package/src/__tests__/contacts-tools.test.ts +42 -1
  67. package/src/__tests__/contacts-write.test.ts +181 -0
  68. package/src/__tests__/context-search-conversations-source.test.ts +220 -81
  69. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  70. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  71. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  72. package/src/__tests__/conversation-agent-loop.test.ts +39 -0
  73. package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
  74. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
  75. package/src/__tests__/conversation-clear-safety.test.ts +0 -1
  76. package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
  77. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
  78. package/src/__tests__/conversation-disk-view.test.ts +1 -0
  79. package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
  80. package/src/__tests__/conversation-error.test.ts +0 -18
  81. package/src/__tests__/conversation-fork-crud.test.ts +67 -0
  82. package/src/__tests__/conversation-history-web-search.test.ts +7 -137
  83. package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
  84. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
  85. package/src/__tests__/conversation-process-callsite.test.ts +37 -0
  86. package/src/__tests__/conversation-queue.test.ts +149 -0
  87. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
  88. package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
  89. package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
  90. package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
  91. package/src/__tests__/conversation-skill-tools.test.ts +73 -0
  92. package/src/__tests__/conversation-wipe.test.ts +20 -5
  93. package/src/__tests__/credential-prompt-route.test.ts +69 -0
  94. package/src/__tests__/credential-security-invariants.test.ts +1 -3
  95. package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
  96. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
  97. package/src/__tests__/edit-propagation.test.ts +56 -2
  98. package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
  99. package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
  100. package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
  101. package/src/__tests__/guardian-question-mode.test.ts +57 -0
  102. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  103. package/src/__tests__/guardian-wait-controller.test.ts +619 -0
  104. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
  105. package/src/__tests__/heic-fixture.ts +55 -0
  106. package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
  107. package/src/__tests__/http-conversation-lineage.test.ts +6 -1
  108. package/src/__tests__/image-conversion.test.ts +170 -0
  109. package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
  110. package/src/__tests__/introduction-card-resolver.test.ts +354 -0
  111. package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
  112. package/src/__tests__/invite-routes-http.test.ts +246 -420
  113. package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
  114. package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
  115. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
  116. package/src/__tests__/list-messages-attachments.test.ts +159 -0
  117. package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
  118. package/src/__tests__/list-messages-queued.test.ts +25 -0
  119. package/src/__tests__/managed-store.test.ts +129 -1
  120. package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
  121. package/src/__tests__/media-stream-output.test.ts +350 -19
  122. package/src/__tests__/media-stream-server-integration.test.ts +943 -169
  123. package/src/__tests__/media-stream-stt-session.test.ts +498 -1
  124. package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
  125. package/src/__tests__/model-intents.test.ts +1 -1
  126. package/src/__tests__/mtime-cache.test.ts +19 -0
  127. package/src/__tests__/non-member-access-request.test.ts +349 -3
  128. package/src/__tests__/notification-decision-fallback.test.ts +104 -8
  129. package/src/__tests__/notification-decision-strategy.test.ts +57 -8
  130. package/src/__tests__/onboarding-template-contract.test.ts +27 -43
  131. package/src/__tests__/openai-provider.test.ts +33 -0
  132. package/src/__tests__/openai-responses-provider.test.ts +40 -0
  133. package/src/__tests__/persistence-layering-guard.test.ts +29 -20
  134. package/src/__tests__/persona-resolver.test.ts +56 -2
  135. package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
  136. package/src/__tests__/phone.test.ts +1 -15
  137. package/src/__tests__/plugin-bootstrap.test.ts +25 -196
  138. package/src/__tests__/plugin-disabled-state.test.ts +33 -0
  139. package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
  140. package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
  141. package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
  142. package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
  143. package/src/__tests__/plugin-pipeline.test.ts +63 -1
  144. package/src/__tests__/plugin-route-contribution.test.ts +62 -115
  145. package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
  146. package/src/__tests__/plugin-types.test.ts +0 -1
  147. package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
  148. package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
  149. package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
  150. package/src/__tests__/public-ingress-urls.test.ts +0 -48
  151. package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
  152. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
  153. package/src/__tests__/resolve-trust-class.test.ts +28 -10
  154. package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
  155. package/src/__tests__/schedule-retry.test.ts +38 -14
  156. package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
  157. package/src/__tests__/schedule-routes.test.ts +14 -6
  158. package/src/__tests__/schedule-store.test.ts +3 -1
  159. package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
  160. package/src/__tests__/scheduler-recurrence.test.ts +57 -107
  161. package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
  162. package/src/__tests__/scheduler-wake.test.ts +13 -23
  163. package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
  164. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  165. package/src/__tests__/shell-observability.test.ts +1 -0
  166. package/src/__tests__/skill-boundary-guard.test.ts +3 -4
  167. package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
  168. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
  169. package/src/__tests__/skill-script-runner-host.test.ts +53 -0
  170. package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
  171. package/src/__tests__/skill-tool-factory.test.ts +73 -1
  172. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
  173. package/src/__tests__/slack-inbound-verification.test.ts +36 -0
  174. package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
  175. package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
  176. package/src/__tests__/stt-hints.test.ts +2 -256
  177. package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
  178. package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
  179. package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
  180. package/src/__tests__/subagent-persistence.test.ts +122 -0
  181. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  182. package/src/__tests__/subagent-terminal-message.test.ts +99 -0
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
  184. package/src/__tests__/system-prompt.test.ts +17 -118
  185. package/src/__tests__/task-scheduler.test.ts +68 -89
  186. package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
  187. package/src/__tests__/telephony-tts-guard.test.ts +538 -0
  188. package/src/__tests__/title-generate-hook.test.ts +16 -0
  189. package/src/__tests__/tool-approval-handler.test.ts +87 -1
  190. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
  191. package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
  192. package/src/__tests__/trust-context-guards.test.ts +21 -10
  193. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
  194. package/src/__tests__/twilio-provider.test.ts +17 -17
  195. package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
  196. package/src/__tests__/twilio-routes.test.ts +257 -387
  197. package/src/__tests__/twilio-validation.test.ts +1 -1
  198. package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
  199. package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
  200. package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
  201. package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
  202. package/src/__tests__/voice-quality.test.ts +2 -2
  203. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
  204. package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
  205. package/src/__tests__/voice-session-bridge.test.ts +1 -10
  206. package/src/__tests__/workspace-git-service.test.ts +1 -1
  207. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
  208. package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
  209. package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
  210. package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
  211. package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
  212. package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
  213. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
  214. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
  215. package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
  216. package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
  217. package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
  218. package/src/acp/__tests__/session-manager.test.ts +6 -0
  219. package/src/acp/agent-process.test.ts +116 -0
  220. package/src/acp/agent-process.ts +71 -0
  221. package/src/acp/auto-install.ts +12 -8
  222. package/src/acp/failure-error.test.ts +109 -0
  223. package/src/acp/failure-error.ts +111 -0
  224. package/src/acp/prepare-agent-env.ts +0 -12
  225. package/src/acp/resolve-agent.test.ts +6 -45
  226. package/src/acp/resolve-agent.ts +2 -4
  227. package/src/acp/session-manager.test.ts +312 -0
  228. package/src/acp/session-manager.ts +102 -46
  229. package/src/agent/ax-tree-compaction.test.ts +4 -1
  230. package/src/agent/image-optimize.ts +17 -127
  231. package/src/agent/loop.ts +45 -192
  232. package/src/api/events/background-tool-completed.test.ts +51 -0
  233. package/src/api/events/background-tool-completed.ts +29 -0
  234. package/src/api/events/background-tool-started.test.ts +36 -0
  235. package/src/api/events/background-tool-started.ts +28 -0
  236. package/src/api/events/conversation-error.ts +0 -1
  237. package/src/api/events/open-panel.ts +33 -0
  238. package/src/api/events/subagent-status-changed.ts +4 -1
  239. package/src/api/index.ts +19 -0
  240. package/src/api/responses/conversation-message.ts +34 -0
  241. package/src/approvals/guardian-decision-primitive.ts +74 -24
  242. package/src/approvals/guardian-request-resolvers.ts +450 -122
  243. package/src/apps/app-store.ts +1 -0
  244. package/src/apps/shared-app-links-store.ts +1 -0
  245. package/src/avatar/identity-avatar.ts +3 -7
  246. package/src/background-wake/wake-intent-hooks.test.ts +1 -1
  247. package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
  248. package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
  249. package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
  250. package/src/calls/call-controller.ts +134 -48
  251. package/src/calls/call-domain.ts +18 -42
  252. package/src/calls/call-pointer-messages.ts +51 -67
  253. package/src/calls/call-setup-flow-types.ts +76 -0
  254. package/src/calls/call-setup-flow.ts +1743 -0
  255. package/src/calls/call-speech-output.ts +87 -23
  256. package/src/calls/call-store.ts +4 -0
  257. package/src/calls/call-transport.ts +22 -36
  258. package/src/calls/fish-audio-client.ts +3 -0
  259. package/src/calls/gateway-invite-reader.ts +98 -0
  260. package/src/calls/guardian-wait-controller.ts +451 -0
  261. package/src/calls/media-stream-audio-transcode.ts +82 -2
  262. package/src/calls/media-stream-output.ts +142 -36
  263. package/src/calls/media-stream-server.ts +297 -178
  264. package/src/calls/media-stream-stt-session.ts +393 -50
  265. package/src/calls/media-turn-detector.ts +4 -6
  266. package/src/calls/relay-access-wait.ts +3 -4
  267. package/src/calls/relay-setup-router.ts +22 -43
  268. package/src/calls/relay-verification.ts +17 -24
  269. package/src/calls/resolve-call-tts-provider.ts +96 -29
  270. package/src/calls/stt-hints.ts +24 -87
  271. package/src/calls/telephony-credential-preflight.ts +159 -0
  272. package/src/calls/telephony-tts-capability.ts +183 -0
  273. package/src/calls/tts-call-strategy.ts +18 -20
  274. package/src/calls/twilio-provider.ts +3 -2
  275. package/src/calls/twilio-routes.ts +47 -351
  276. package/src/calls/types.ts +5 -3
  277. package/src/calls/voice-ingress-preflight.ts +9 -0
  278. package/src/calls/voice-quality.ts +13 -18
  279. package/src/calls/voice-session-bridge.ts +25 -35
  280. package/src/channels/__tests__/types.test.ts +28 -0
  281. package/src/channels/channel-verification-sessions.ts +7 -2
  282. package/src/channels/config.ts +0 -42
  283. package/src/channels/slack-thread-store.ts +12 -0
  284. package/src/channels/types.ts +23 -0
  285. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
  286. package/src/cli/commands/__tests__/schedules.test.ts +83 -34
  287. package/src/cli/commands/__tests__/status.test.ts +42 -2
  288. package/src/cli/commands/contacts.ts +2 -2
  289. package/src/cli/commands/credentials.ts +17 -0
  290. package/src/cli/commands/monitoring.ts +191 -0
  291. package/src/cli/commands/schedules-worker.ts +175 -0
  292. package/src/cli/commands/schedules.ts +169 -43
  293. package/src/cli/commands/status.ts +12 -1
  294. package/src/cli/commands/tools.ts +5 -1
  295. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
  296. package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
  297. package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
  298. package/src/cli/lib/search-plugins.ts +6 -0
  299. package/src/cli/lib/toggle-plugin.ts +21 -2
  300. package/src/cli/program.ts +3 -1
  301. package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
  302. package/src/config/acp-defaults.test.ts +0 -10
  303. package/src/config/acp-defaults.ts +0 -6
  304. package/src/config/bundled-skills/acp/SKILL.md +13 -45
  305. package/src/config/bundled-skills/acp/TOOLS.json +3 -3
  306. package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
  307. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
  308. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
  309. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
  310. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  311. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
  312. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
  313. package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
  314. package/src/config/call-site-defaults.ts +0 -2
  315. package/src/config/feature-flag-registry.json +16 -8
  316. package/src/config/loader.ts +11 -0
  317. package/src/config/schema.ts +9 -1
  318. package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
  319. package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
  320. package/src/config/schemas/call-site-catalog.ts +0 -12
  321. package/src/config/schemas/calls.ts +8 -0
  322. package/src/config/schemas/elevenlabs.ts +1 -1
  323. package/src/config/schemas/llm.ts +0 -2
  324. package/src/config/schemas/memory-v2.ts +1 -1
  325. package/src/config/schemas/memory-v3.ts +82 -0
  326. package/src/config/schemas/monitoring.ts +61 -0
  327. package/src/config/schemas/schedules.ts +35 -0
  328. package/src/config/seed-inference-profiles.ts +2 -2
  329. package/src/config/skills-plugin-filter.test.ts +96 -0
  330. package/src/config/skills.ts +26 -0
  331. package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
  332. package/src/contacts/canonical-guardian-store.ts +5 -0
  333. package/src/contacts/contact-store.ts +81 -35
  334. package/src/contacts/contacts-write.ts +50 -25
  335. package/src/contacts/member-write-relay.ts +115 -31
  336. package/src/contacts/types.ts +0 -8
  337. package/src/context/compactor.ts +29 -15
  338. package/src/context/outbound-sanitize.ts +202 -0
  339. package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
  340. package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
  341. package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
  342. package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
  343. package/src/daemon/abort-watchdog.ts +7 -0
  344. package/src/daemon/app-source-watcher.ts +9 -0
  345. package/src/daemon/assistant-attachments.ts +42 -0
  346. package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
  347. package/src/daemon/conversation-agent-loop.ts +61 -68
  348. package/src/daemon/conversation-error.ts +1 -15
  349. package/src/daemon/conversation-history.ts +32 -236
  350. package/src/daemon/conversation-initial-prompt.ts +77 -0
  351. package/src/daemon/conversation-lifecycle.ts +25 -1
  352. package/src/daemon/conversation-messaging.ts +2 -2
  353. package/src/daemon/conversation-plugin-scope.ts +38 -0
  354. package/src/daemon/conversation-process.ts +50 -14
  355. package/src/daemon/conversation-runtime-assembly.ts +36 -6
  356. package/src/daemon/conversation-skill-tools.ts +19 -3
  357. package/src/daemon/conversation-store.ts +3 -3
  358. package/src/daemon/conversation-surfaces.ts +171 -0
  359. package/src/daemon/conversation-tool-setup.test.ts +95 -0
  360. package/src/daemon/conversation-tool-setup.ts +116 -1
  361. package/src/daemon/conversation-turn-finalize.ts +211 -0
  362. package/src/daemon/conversation.ts +92 -1
  363. package/src/daemon/disk-pressure-policy.ts +2 -1
  364. package/src/daemon/event-loop-watchdog.ts +22 -6
  365. package/src/daemon/external-plugins-bootstrap.ts +47 -134
  366. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
  367. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
  368. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
  369. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
  370. package/src/daemon/handlers/config-a2a.ts +7 -14
  371. package/src/daemon/handlers/config-channels.ts +2 -10
  372. package/src/daemon/handlers/conversation-history.ts +3 -1
  373. package/src/daemon/handlers/conversations.ts +0 -52
  374. package/src/daemon/handlers/shared.ts +4 -24
  375. package/src/daemon/handlers/skills.ts +4 -1
  376. package/src/daemon/host-cu-proxy.ts +1 -1
  377. package/src/daemon/lifecycle.ts +59 -472
  378. package/src/daemon/message-protocol.ts +3 -3
  379. package/src/daemon/message-provenance.ts +12 -14
  380. package/src/daemon/message-types/background-tools.ts +28 -0
  381. package/src/daemon/message-types/contacts.ts +2 -10
  382. package/src/daemon/message-types/conversations.ts +10 -0
  383. package/src/daemon/message-types/integrations.ts +2 -0
  384. package/src/daemon/message-types/surfaces.ts +1 -0
  385. package/src/daemon/message-types/sync.ts +1 -0
  386. package/src/daemon/pointer-conversation-trust.ts +23 -9
  387. package/src/daemon/pointer-turn-runner.ts +174 -0
  388. package/src/daemon/providers-setup.ts +16 -0
  389. package/src/daemon/shutdown-handlers.ts +139 -47
  390. package/src/daemon/skill-memory-refresh.ts +2 -2
  391. package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
  392. package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
  393. package/src/daemon/tool-setup-types.ts +8 -0
  394. package/src/daemon/trust-context.ts +21 -6
  395. package/src/daemon/turn-latency-tracker.test.ts +93 -0
  396. package/src/daemon/turn-latency-tracker.ts +38 -0
  397. package/src/daemon/wake-conversation-ops.ts +10 -8
  398. package/src/documents/document-comments-store.test.ts +7 -1
  399. package/src/documents/document-comments-store.ts +8 -0
  400. package/src/documents/document-store.ts +15 -0
  401. package/src/export/__tests__/transcript-formatter.test.ts +11 -0
  402. package/src/export/transcript-formatter.ts +49 -67
  403. package/src/home/__tests__/feed-writer.test.ts +247 -1
  404. package/src/home/conversation-starter-checkpoints.ts +1 -0
  405. package/src/home/feed-writer.ts +61 -0
  406. package/src/home/job-handlers/conversation-starters.ts +1 -0
  407. package/src/hooks/hook-loader.ts +12 -0
  408. package/src/hooks/registry.ts +32 -4
  409. package/src/inbound/public-ingress-urls.ts +0 -17
  410. package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
  411. package/src/ipc/assistant-server.ts +28 -7
  412. package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
  413. package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
  414. package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
  415. package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
  416. package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
  417. package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
  418. package/src/ipc/routes/db-proxy.ts +5 -2
  419. package/src/ipc/routes/invite-ipc-routes.ts +53 -39
  420. package/src/jobs/worker.ts +9 -2
  421. package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
  422. package/src/live-voice/live-voice-archive.ts +5 -0
  423. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
  424. package/src/messaging/providers/channel-transport.ts +6 -0
  425. package/src/messaging/providers/index.ts +3 -0
  426. package/src/messaging/providers/slack/api.test.ts +49 -1
  427. package/src/messaging/providers/slack/api.ts +110 -0
  428. package/src/messaging/providers/slack/send.test.ts +85 -0
  429. package/src/messaging/providers/slack/send.ts +100 -28
  430. package/src/messaging/providers/slack/transport.ts +7 -13
  431. package/src/messaging/providers/whatsapp/send.ts +29 -9
  432. package/src/monitoring/__tests__/control.test.ts +235 -0
  433. package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
  434. package/src/monitoring/control.ts +105 -0
  435. package/src/monitoring/resource-sampler.ts +258 -0
  436. package/src/monitoring/sample-ring-buffer.ts +108 -0
  437. package/src/monitoring/worker.ts +94 -0
  438. package/src/notifications/README.md +1 -1
  439. package/src/notifications/access-request-copy.ts +94 -23
  440. package/src/notifications/adapters/slack.ts +89 -21
  441. package/src/notifications/approval-card-builder.ts +33 -18
  442. package/src/notifications/approval-card-data.ts +48 -15
  443. package/src/notifications/broadcaster.ts +25 -16
  444. package/src/notifications/decision-engine.ts +131 -32
  445. package/src/notifications/guardian-question-mode.ts +58 -10
  446. package/src/permissions/approval-policy.ts +8 -1
  447. package/src/permissions/checker.ts +2 -0
  448. package/src/permissions/gateway-threshold-reader.ts +7 -6
  449. package/src/permissions/ipc-risk-types.ts +1 -0
  450. package/src/permissions/secret-prompter.ts +11 -3
  451. package/src/permissions/types.ts +2 -2
  452. package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
  453. package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
  454. package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
  455. package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
  456. package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
  457. package/src/persistence/a2a-invite-store.ts +205 -0
  458. package/src/persistence/attachments-store.ts +94 -10
  459. package/src/persistence/checkpoints.ts +45 -0
  460. package/src/persistence/conversation-crud.ts +453 -260
  461. package/src/persistence/conversation-display-order-migration.ts +8 -2
  462. package/src/persistence/conversation-group-migration.test.ts +8 -0
  463. package/src/persistence/conversation-group-migration.ts +9 -0
  464. package/src/persistence/conversation-queries.ts +244 -125
  465. package/src/persistence/conversation-row-batch-delete.ts +9 -5
  466. package/src/persistence/conversation-search-lexical.ts +49 -0
  467. package/src/persistence/db-async-query.ts +42 -0
  468. package/src/persistence/db-connection.ts +13 -0
  469. package/src/persistence/delivery-channels.ts +0 -82
  470. package/src/persistence/delivery-crud.ts +27 -6
  471. package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
  472. package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
  473. package/src/persistence/embeddings/embedding-identity.ts +17 -5
  474. package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
  475. package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
  476. package/src/persistence/embeddings/qdrant-client.ts +81 -5
  477. package/src/persistence/group-crud.ts +13 -1
  478. package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
  479. package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
  480. package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
  481. package/src/persistence/job-handlers/cleanup.ts +57 -9
  482. package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
  483. package/src/persistence/job-handlers/message-lexical.ts +251 -0
  484. package/src/persistence/jobs-store.ts +102 -8
  485. package/src/persistence/jobs-worker.ts +68 -28
  486. package/src/persistence/llm-request-log-store.ts +35 -19
  487. package/src/persistence/llm-usage-store.ts +11 -0
  488. package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
  489. package/src/persistence/memory-lifecycle-hooks.ts +55 -1
  490. package/src/persistence/migrations/028-call-session-mode.ts +1 -1
  491. package/src/persistence/migrations/116-messages-fts.ts +8 -1
  492. package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
  493. package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
  494. package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
  495. package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
  496. package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
  497. package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
  498. package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
  499. package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
  500. package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
  501. package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
  502. package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
  503. package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
  504. package/src/persistence/raw-query.ts +50 -11
  505. package/src/persistence/schema/a2a.ts +14 -0
  506. package/src/persistence/schema/contacts.ts +0 -62
  507. package/src/persistence/schema/conversation-groups.ts +12 -0
  508. package/src/persistence/schema/conversations.ts +2 -0
  509. package/src/persistence/schema/documents.ts +65 -0
  510. package/src/persistence/schema/guardian.ts +4 -0
  511. package/src/persistence/schema/index.ts +4 -0
  512. package/src/persistence/schema/memory-injection.ts +62 -0
  513. package/src/persistence/schema/workflows.ts +55 -0
  514. package/src/persistence/slow-query-log.ts +437 -0
  515. package/src/persistence/slow-sync-log.ts +204 -0
  516. package/src/persistence/steps.ts +16 -0
  517. package/src/persistence/subagent-store.ts +125 -0
  518. package/src/persistence/worker-control.ts +45 -238
  519. package/src/plugin-api/event-hub-facade.ts +172 -0
  520. package/src/plugin-api/index.ts +9 -1
  521. package/src/plugin-api/types.ts +40 -9
  522. package/src/plugins/defaults/default-plugin-names.ts +60 -0
  523. package/src/plugins/defaults/index.ts +19 -29
  524. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
  525. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
  526. package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
  527. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
  528. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
  530. package/src/plugins/defaults/memory/config.ts +11 -0
  531. package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
  532. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
  533. package/src/plugins/defaults/memory/embeddings.ts +77 -0
  534. package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
  535. package/src/plugins/defaults/memory/frontmatter.ts +50 -0
  536. package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
  537. package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
  538. package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
  539. package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
  540. package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
  541. package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
  542. package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
  543. package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
  544. package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
  545. package/src/plugins/defaults/memory/graph/tools.ts +1 -1
  546. package/src/plugins/defaults/memory/hooks/init.ts +31 -5
  547. package/src/plugins/defaults/memory/indexer.ts +2 -3
  548. package/src/plugins/defaults/memory/injectors.ts +2 -2
  549. package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
  550. package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
  551. package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
  552. package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
  553. package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
  554. package/src/plugins/defaults/memory/job-handlers.ts +13 -12
  555. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
  556. package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
  557. package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
  558. package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
  559. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
  560. package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
  561. package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
  562. package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
  563. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
  564. package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
  565. package/src/plugins/defaults/memory/search/semantic.ts +2 -2
  566. package/src/plugins/defaults/memory/startup.ts +244 -0
  567. package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
  568. package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
  570. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
  571. package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
  572. package/src/plugins/defaults/memory/v2/activation.ts +2 -4
  573. package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
  574. package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
  575. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
  576. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
  577. package/src/plugins/defaults/memory/v2/migration.ts +2 -5
  578. package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
  579. package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
  580. package/src/plugins/defaults/memory/v2/router.ts +5 -5
  581. package/src/plugins/defaults/memory/v2/sim.ts +2 -4
  582. package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
  583. package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
  584. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
  585. package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
  586. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
  587. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
  588. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
  589. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
  590. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
  591. package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
  592. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
  593. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
  594. package/src/plugins/defaults/memory/v3/card.ts +1 -4
  595. package/src/plugins/defaults/memory/v3/dense.ts +60 -25
  596. package/src/plugins/defaults/memory/v3/edge.ts +1 -1
  597. package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
  598. package/src/plugins/defaults/memory/v3/gate.ts +158 -0
  599. package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
  600. package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
  601. package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
  602. package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
  603. package/src/plugins/defaults/memory/v3/prune.ts +2 -2
  604. package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
  605. package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
  606. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
  607. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
  608. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
  609. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  610. package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
  611. package/src/plugins/injector-registry.ts +13 -2
  612. package/src/plugins/mtime-cache.ts +36 -47
  613. package/src/plugins/pipeline.ts +15 -1
  614. package/src/plugins/types.ts +14 -23
  615. package/src/prompts/__tests__/system-prompt.test.ts +170 -32
  616. package/src/prompts/persona-resolver.ts +13 -9
  617. package/src/prompts/system-prompt.ts +30 -9
  618. package/src/prompts/templates/BOOTSTRAP.md +16 -119
  619. package/src/prompts/templates/SOUL.md +43 -13
  620. package/src/prompts/templates/system-sections.ts +32 -27
  621. package/src/prompts/templates/users/default.md +19 -0
  622. package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
  623. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
  624. package/src/providers/model-intents.ts +2 -2
  625. package/src/providers/openai/chat-completions-provider.ts +14 -1
  626. package/src/providers/openai/responses-provider.ts +18 -0
  627. package/src/providers/placeholder-sentinels.ts +18 -8
  628. package/src/providers/retry.ts +1 -0
  629. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
  630. package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
  631. package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
  632. package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
  633. package/src/providers/speech-to-text/provider-catalog.ts +0 -89
  634. package/src/providers/speech-to-text/resolve.ts +55 -0
  635. package/src/providers/tool-progress-events.test.ts +50 -0
  636. package/src/providers/tool-progress-events.ts +99 -0
  637. package/src/providers/types.ts +1 -1
  638. package/src/providers/vellum-model-routing.test.ts +51 -0
  639. package/src/providers/vellum-model-routing.ts +84 -0
  640. package/src/runtime/AGENTS.md +5 -4
  641. package/src/runtime/__tests__/agent-wake.test.ts +158 -1
  642. package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
  643. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
  644. package/src/runtime/access-request-helper.ts +154 -3
  645. package/src/runtime/actor-trust-resolver.ts +7 -21
  646. package/src/runtime/agent-wake.ts +41 -1
  647. package/src/runtime/assistant-event.ts +86 -12
  648. package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
  649. package/src/runtime/channel-approval-types.ts +52 -2
  650. package/src/runtime/channel-approvals.ts +23 -8
  651. package/src/runtime/channel-invite-transport.ts +2 -2
  652. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  653. package/src/runtime/channel-readiness-service.ts +3 -5
  654. package/src/runtime/channel-retry-sweep.ts +18 -24
  655. package/src/runtime/channel-verification-service.ts +9 -11
  656. package/src/runtime/finalize-event-delivery.ts +30 -16
  657. package/src/runtime/guardian-action-service.ts +10 -11
  658. package/src/runtime/guardian-reply-router.ts +122 -21
  659. package/src/runtime/http-server.ts +44 -101
  660. package/src/runtime/introduction-policy.test.ts +214 -0
  661. package/src/runtime/introduction-policy.ts +284 -0
  662. package/src/runtime/invite-service.ts +104 -361
  663. package/src/runtime/local-actor-identity.test.ts +38 -0
  664. package/src/runtime/local-actor-identity.ts +14 -0
  665. package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
  666. package/src/runtime/middleware/rate-limiter.ts +30 -0
  667. package/src/runtime/middleware/twilio-validation.ts +5 -7
  668. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
  669. package/src/runtime/migrations/origin-mode.ts +6 -6
  670. package/src/runtime/pre-first-message-gate.ts +1 -0
  671. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
  672. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
  673. package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
  674. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
  675. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
  676. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
  677. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
  678. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
  679. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
  680. package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
  681. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
  682. package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
  683. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
  684. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
  685. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
  686. package/src/runtime/routes/acp-routes.ts +15 -3
  687. package/src/runtime/routes/app-management-routes.ts +4 -7
  688. package/src/runtime/routes/approval-routes.ts +4 -0
  689. package/src/runtime/routes/attachment-routes.ts +54 -3
  690. package/src/runtime/routes/avatar-routes.ts +0 -4
  691. package/src/runtime/routes/background-tool-routes.ts +34 -5
  692. package/src/runtime/routes/btw-routes.ts +32 -4
  693. package/src/runtime/routes/channel-route-shared.ts +18 -14
  694. package/src/runtime/routes/channel-verification-routes.ts +0 -3
  695. package/src/runtime/routes/contact-routes.ts +298 -117
  696. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  697. package/src/runtime/routes/conversation-management-routes.ts +74 -37
  698. package/src/runtime/routes/conversation-query-routes.ts +5 -2
  699. package/src/runtime/routes/conversation-routes.ts +222 -82
  700. package/src/runtime/routes/conversations-import-routes.ts +8 -1
  701. package/src/runtime/routes/credential-prompt-routes.ts +20 -5
  702. package/src/runtime/routes/debug-routes.ts +1 -0
  703. package/src/runtime/routes/documents-routes.ts +5 -2
  704. package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
  705. package/src/runtime/routes/global-search-routes.ts +2 -1
  706. package/src/runtime/routes/guardian-approval-interception.ts +51 -0
  707. package/src/runtime/routes/home-feed-routes.ts +60 -1
  708. package/src/runtime/routes/identity-routes.ts +4 -87
  709. package/src/runtime/routes/inbound-message-handler.ts +82 -41
  710. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
  711. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
  712. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
  713. package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
  714. package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
  715. package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
  716. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
  717. package/src/runtime/routes/index.ts +6 -0
  718. package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
  719. package/src/runtime/routes/internal-twilio-routes.ts +0 -15
  720. package/src/runtime/routes/messages-lexical-routes.ts +75 -0
  721. package/src/runtime/routes/migration-routes.ts +69 -6
  722. package/src/runtime/routes/monitoring-routes.ts +237 -0
  723. package/src/runtime/routes/plugins-routes.ts +329 -8
  724. package/src/runtime/routes/schedule-routes.ts +49 -8
  725. package/src/runtime/routes/schedule-worker-routes.ts +210 -0
  726. package/src/runtime/routes/secret-routes.ts +1 -1
  727. package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
  728. package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
  729. package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
  730. package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
  731. package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
  732. package/src/runtime/services/analyze-conversation.ts +14 -4
  733. package/src/runtime/services/conversation-serializer.ts +5 -0
  734. package/src/runtime/slack-no-response.ts +47 -0
  735. package/src/runtime/slack-reply-session.test.ts +633 -0
  736. package/src/runtime/slack-reply-session.ts +382 -0
  737. package/src/runtime/slack-task-progress.ts +95 -0
  738. package/src/runtime/sync/resource-sync-events.ts +25 -0
  739. package/src/runtime/tool-grant-request-helper.ts +17 -1
  740. package/src/runtime/trust-class.test.ts +141 -0
  741. package/src/runtime/trust-class.ts +121 -0
  742. package/src/runtime/trust-verdict-consumer.ts +7 -6
  743. package/src/schedule/__tests__/run-script.test.ts +21 -0
  744. package/src/schedule/__tests__/worker-control.test.ts +241 -0
  745. package/src/schedule/run-script.ts +13 -6
  746. package/src/schedule/schedule-usage-store.ts +1 -0
  747. package/src/schedule/scheduler.ts +178 -127
  748. package/src/schedule/worker-control.ts +118 -0
  749. package/src/schedule/worker.ts +131 -0
  750. package/src/skills/__tests__/categories-cache.test.ts +38 -0
  751. package/src/skills/categories-cache.ts +40 -5
  752. package/src/skills/managed-store.ts +41 -6
  753. package/src/skills/validate-input.ts +47 -0
  754. package/src/stt/types.ts +5 -9
  755. package/src/subagent/manager.ts +267 -39
  756. package/src/subagent/types.ts +6 -2
  757. package/src/subagent/validate-allowlists.ts +65 -0
  758. package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
  759. package/src/telemetry/watchdog-direct-emit.ts +89 -0
  760. package/src/tools/acp/list-agents.test.ts +0 -6
  761. package/src/tools/background-tool-registry.ts +61 -0
  762. package/src/tools/document/document-comment-tool.test.ts +4 -0
  763. package/src/tools/host-terminal/host-shell.test.ts +397 -0
  764. package/src/tools/host-terminal/host-shell.ts +203 -14
  765. package/src/tools/skills/find-similar-skills.test.ts +152 -1
  766. package/src/tools/skills/find-similar-skills.ts +30 -4
  767. package/src/tools/skills/load.ts +36 -0
  768. package/src/tools/skills/scaffold-managed.ts +66 -34
  769. package/src/tools/skills/skill-script-runner.ts +17 -0
  770. package/src/tools/skills/skill-tool-factory.ts +5 -1
  771. package/src/tools/terminal/safe-env.ts +3 -0
  772. package/src/tools/terminal/shell.test.ts +177 -0
  773. package/src/tools/terminal/shell.ts +98 -4
  774. package/src/tools/tool-approval-handler.ts +106 -29
  775. package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
  776. package/src/tools/types.ts +29 -17
  777. package/src/tools/ui-surface/definitions.ts +3 -1
  778. package/src/tts/__tests__/provider-adapters.test.ts +37 -0
  779. package/src/tts/__tests__/provider-catalog.test.ts +21 -0
  780. package/src/tts/provider-catalog.ts +40 -9
  781. package/src/tts/providers/fish-audio-provider.ts +19 -10
  782. package/src/tts/types.ts +3 -4
  783. package/src/util/__tests__/process-tree.test.ts +10 -2
  784. package/src/util/__tests__/text-spacing.test.ts +53 -0
  785. package/src/util/cgroup-memory.ts +142 -0
  786. package/src/util/image-conversion.ts +281 -0
  787. package/src/util/phone.ts +1 -8
  788. package/src/util/platform.ts +33 -0
  789. package/src/util/process-tree.ts +10 -2
  790. package/src/util/text-spacing.ts +53 -0
  791. package/src/util/worker-process.ts +271 -0
  792. package/src/workflows/journal-store.ts +16 -1
  793. package/src/workflows/library.test.ts +35 -20
  794. package/src/workflows/library.ts +105 -66
  795. package/src/workspace/git-service.ts +1 -0
  796. package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
  797. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
  798. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
  799. package/src/workspace/migrations/118-seed-now-md.ts +64 -0
  800. package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
  801. package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
  802. package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
  803. package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
  804. package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
  805. package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
  806. package/src/workspace/migrations/registry.ts +12 -0
  807. package/drizzle/0000_dizzy_maggott.sql +0 -301
  808. package/drizzle/meta/0000_snapshot.json +0 -1933
  809. package/drizzle/meta/_journal.json +0 -13
  810. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
  811. package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
  812. package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
  813. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
  814. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
  815. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
  816. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
  817. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
  818. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
  819. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
  820. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
  821. package/src/__tests__/invite-redemption-service.test.ts +0 -1180
  822. package/src/__tests__/invite-service-ipc.test.ts +0 -350
  823. package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
  824. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
  825. package/src/__tests__/relay-server.test.ts +0 -6153
  826. package/src/__tests__/telephony-stt-routing.test.ts +0 -329
  827. package/src/__tests__/voice-invite-redemption.test.ts +0 -702
  828. package/src/calls/relay-server.ts +0 -2463
  829. package/src/calls/telephony-stt-routing.ts +0 -145
  830. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
  831. package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
  832. package/src/daemon/daemon-skill-host.ts +0 -262
  833. package/src/daemon/message-types/meet.ts +0 -143
  834. package/src/daemon/shutdown-registry.ts +0 -40
  835. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
  836. package/src/ipc/__tests__/skill-server.test.ts +0 -182
  837. package/src/ipc/skill-ipc-types.ts +0 -54
  838. package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
  839. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
  840. package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
  841. package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
  842. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
  843. package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
  844. package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
  845. package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
  846. package/src/ipc/skill-routes/config.ts +0 -47
  847. package/src/ipc/skill-routes/events.ts +0 -147
  848. package/src/ipc/skill-routes/identity.ts +0 -21
  849. package/src/ipc/skill-routes/index.ts +0 -37
  850. package/src/ipc/skill-routes/log.ts +0 -40
  851. package/src/ipc/skill-routes/memory.ts +0 -92
  852. package/src/ipc/skill-routes/platform.ts +0 -39
  853. package/src/ipc/skill-routes/providers.ts +0 -162
  854. package/src/ipc/skill-routes/registries.ts +0 -338
  855. package/src/ipc/skill-server.ts +0 -831
  856. package/src/ipc/skill-socket-path.ts +0 -20
  857. package/src/jobs/register-job-handlers.ts +0 -74
  858. package/src/persistence/invite-store.ts +0 -481
  859. package/src/plugins/job-handler-registry.ts +0 -94
  860. package/src/providers/cache-control.ts +0 -26
  861. package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
  862. package/src/runtime/invite-redemption-service.ts +0 -828
  863. package/src/runtime/invite-redemption-templates.ts +0 -46
  864. package/src/runtime/runtime-mode.ts +0 -40
  865. package/src/runtime/slack-dm-text-delivery.ts +0 -177
  866. package/src/util/voice-code.ts +0 -31
@@ -156,6 +156,7 @@ function recordUsageCostAt(
156
156
  { estimatedCostUsd, pricingStatus: "priced" },
157
157
  );
158
158
  rawRun(
159
+ "test:setUsageCreatedAt",
159
160
  "UPDATE llm_usage_events SET created_at = ? WHERE id = ?",
160
161
  createdAt,
161
162
  event.id,
@@ -174,6 +175,7 @@ function setScheduleRunWindow({
174
175
  status?: "ok" | "error" | "running";
175
176
  }) {
176
177
  rawRun(
178
+ "test:setCronRunWindow",
177
179
  "UPDATE cron_runs SET status = ?, started_at = ?, finished_at = ?, duration_ms = ?, created_at = ? WHERE id = ?",
178
180
  status,
179
181
  startedAt,
@@ -804,6 +806,7 @@ describe("schedule and heartbeat run metadata", () => {
804
806
  const runId = await createScheduleRun(job.id, conversation.id);
805
807
  await completeScheduleRun(runId, { status: "ok" });
806
808
  rawRun(
809
+ "test:setCronRunTimes",
807
810
  "UPDATE cron_runs SET started_at = ?, finished_at = ?, duration_ms = ?, created_at = ? WHERE id = ?",
808
811
  1000,
809
812
  2000,
@@ -849,6 +852,7 @@ describe("schedule and heartbeat run metadata", () => {
849
852
  });
850
853
  const archivedAt = 3000;
851
854
  rawRun(
855
+ "test:archiveConversation",
852
856
  "UPDATE conversations SET archived_at = ? WHERE id = ?",
853
857
  archivedAt,
854
858
  conversation.id,
@@ -926,6 +930,7 @@ describe("schedule and heartbeat run metadata", () => {
926
930
  const runId = insertPendingHeartbeatRun(900);
927
931
  startHeartbeatRun(runId);
928
932
  rawRun(
933
+ "test:setHeartbeatRunOk",
929
934
  "UPDATE heartbeat_runs SET status = 'ok', scheduled_for = ?, started_at = ?, finished_at = ?, duration_ms = ?, conversation_id = ?, created_at = ? WHERE id = ?",
930
935
  900,
931
936
  1000,
@@ -966,6 +971,7 @@ describe("schedule and heartbeat run metadata", () => {
966
971
  });
967
972
  const runId = insertPendingHeartbeatRun(1000);
968
973
  rawRun(
974
+ "test:setHeartbeatRunRunning",
969
975
  "UPDATE heartbeat_runs SET status = 'running', finished_at = NULL, conversation_id = ?, created_at = ? WHERE id = ?",
970
976
  conversation.id,
971
977
  1000,
@@ -1160,7 +1166,7 @@ describe("POST /schedules — create", () => {
1160
1166
  async function postCreate(body: Record<string, unknown>) {
1161
1167
  const route = findRoute("schedules", "POST");
1162
1168
  return (await route.handler({ body })) as {
1163
- schedules: Array<{ id: string; inferenceProfile: string | null }>;
1169
+ schedule: { id: string; inferenceProfile: string | null };
1164
1170
  };
1165
1171
  }
1166
1172
 
@@ -1171,7 +1177,7 @@ describe("POST /schedules — create", () => {
1171
1177
  expression: "0 9 * * *",
1172
1178
  message: "good morning",
1173
1179
  });
1174
- expect(result.schedules).toHaveLength(1);
1180
+ expect(result.schedule.id).toBeDefined();
1175
1181
  const job = listSchedules()[0];
1176
1182
  expect(job.name).toBe("Morning ping");
1177
1183
  expect(job.mode).toBe("execute");
@@ -1241,7 +1247,7 @@ describe("POST /schedules — create", () => {
1241
1247
  expect(job.description).toBe("Description fallback");
1242
1248
  });
1243
1249
 
1244
- test("rejects modes other than execute/workflow", async () => {
1250
+ test("rejects modes other than execute/workflow/script", async () => {
1245
1251
  await expect(
1246
1252
  postCreate({
1247
1253
  name: "x",
@@ -1250,7 +1256,9 @@ describe("POST /schedules — create", () => {
1250
1256
  message: "hi",
1251
1257
  mode: "notify",
1252
1258
  }),
1253
- ).rejects.toThrow("Only 'execute' and 'workflow' modes are supported");
1259
+ ).rejects.toThrow(
1260
+ "Only 'execute', 'script', and 'workflow' modes are supported",
1261
+ );
1254
1262
  });
1255
1263
 
1256
1264
  test("rejects an unparseable expression", async () => {
@@ -1327,7 +1335,7 @@ describe("POST /schedules — create", () => {
1327
1335
  message: "write the digest",
1328
1336
  inferenceProfile: "cost-optimized",
1329
1337
  });
1330
- expect(result.schedules[0].inferenceProfile).toBe("cost-optimized");
1338
+ expect(result.schedule.inferenceProfile).toBe("cost-optimized");
1331
1339
  expect(listSchedules()[0].inferenceProfile).toBe("cost-optimized");
1332
1340
  });
1333
1341
 
@@ -1338,7 +1346,7 @@ describe("POST /schedules — create", () => {
1338
1346
  expression: "0 9 * * *",
1339
1347
  message: "hi",
1340
1348
  });
1341
- expect(result.schedules[0].inferenceProfile).toBeNull();
1349
+ expect(result.schedule.inferenceProfile).toBeNull();
1342
1350
  });
1343
1351
 
1344
1352
  test("rejects an unknown inferenceProfile", async () => {
@@ -55,7 +55,9 @@ async function waitFor(predicate: () => boolean): Promise<void> {
55
55
  // predicate holds, so a larger budget costs nothing when events flow.
56
56
  const deadline = Date.now() + 2000;
57
57
  while (Date.now() < deadline) {
58
- if (predicate()) return;
58
+ if (predicate()) {
59
+ return;
60
+ }
59
61
  await new Promise((resolve) => setTimeout(resolve, 5));
60
62
  }
61
63
  throw new Error("Timed out waiting for schedule-store event");
@@ -89,6 +89,18 @@ mock.module("../daemon/disk-pressure-background-gate.js", () => ({
89
89
  shouldLogDiskPressureBackgroundSkip: () => true,
90
90
  }));
91
91
 
92
+ const mockProcessMessage = mock((..._args: unknown[]) => Promise.resolve());
93
+ mock.module("../daemon/process-message.js", () => ({
94
+ processMessage: mockProcessMessage,
95
+ }));
96
+
97
+ const mockEmitNotificationSignal = mock((..._args: unknown[]) =>
98
+ Promise.resolve(),
99
+ );
100
+ mock.module("../notifications/emit-signal.js", () => ({
101
+ emitNotificationSignal: mockEmitNotificationSignal,
102
+ }));
103
+
92
104
  import { getDb } from "../persistence/db-connection.js";
93
105
  import { initializeDb } from "../persistence/db-init.js";
94
106
  import { createSchedule } from "../schedule/schedule-store.js";
@@ -104,6 +116,8 @@ function rawDb(): import("bun:sqlite").Database {
104
116
  describe("scheduler disk pressure gate", () => {
105
117
  beforeEach(() => {
106
118
  locked = true;
119
+ mockProcessMessage.mockClear();
120
+ mockEmitNotificationSignal.mockClear();
107
121
  const db = getDb();
108
122
  db.run("DELETE FROM cron_runs");
109
123
  db.run("DELETE FROM cron_jobs");
@@ -122,14 +136,11 @@ describe("scheduler disk pressure gate", () => {
122
136
  nextRunAt: dueAt,
123
137
  });
124
138
 
125
- const processMessage = mock(() => Promise.resolve());
126
- const notify = mock(() => Promise.resolve());
127
-
128
- const processed = await runScheduleOnce(processMessage, notify);
139
+ const processed = await runScheduleOnce();
129
140
 
130
141
  expect(processed).toBe(0);
131
- expect(processMessage).not.toHaveBeenCalled();
132
- expect(notify).not.toHaveBeenCalled();
142
+ expect(mockProcessMessage).not.toHaveBeenCalled();
143
+ expect(mockEmitNotificationSignal).not.toHaveBeenCalled();
133
144
 
134
145
  const row = rawDb()
135
146
  .query("SELECT status, next_run_at FROM cron_jobs WHERE id = ?")
@@ -50,6 +50,25 @@ mock.module("../runtime/background-job-runner.js", () => ({
50
50
  },
51
51
  }));
52
52
 
53
+ // The scheduler dispatches reuse/task-path messages through `processMessage`;
54
+ // route them to a per-test delegate so tests can capture those calls.
55
+ let processMessageImpl: (
56
+ conversationId: string,
57
+ message: string,
58
+ ) => Promise<void> = async () => {};
59
+ mock.module("../daemon/process-message.js", () => ({
60
+ processMessage: (conversationId: string, message: string) =>
61
+ processMessageImpl(conversationId, message),
62
+ }));
63
+
64
+ // Notify-mode firings go through `emitNotificationSignal`; capture them.
65
+ const notifySignalCalls: Array<Record<string, unknown>> = [];
66
+ mock.module("../notifications/emit-signal.js", () => ({
67
+ emitNotificationSignal: async (payload: Record<string, unknown>) => {
68
+ notifySignalCalls.push(payload);
69
+ },
70
+ }));
71
+
53
72
  import { getDb } from "../persistence/db-connection.js";
54
73
  import { initializeDb } from "../persistence/db-init.js";
55
74
  import {
@@ -138,6 +157,8 @@ describe("scheduler RRULE execution", () => {
138
157
  db.run("DELETE FROM conversations");
139
158
  onRunBackgroundJobPrompt = null;
140
159
  runBackgroundJobShouldFail = false;
160
+ processMessageImpl = async () => {};
161
+ notifySignalCalls.length = 0;
141
162
  });
142
163
 
143
164
  test("RRULE schedule fires and creates cron_runs entry", async () => {
@@ -163,10 +184,7 @@ describe("scheduler RRULE execution", () => {
163
184
  processedMessages.push({ conversationId, message: prompt });
164
185
  };
165
186
 
166
- const scheduler = startScheduler(
167
- async () => {},
168
- () => {},
169
- );
187
+ const scheduler = startScheduler();
170
188
  await new Promise((resolve) => setTimeout(resolve, 500));
171
189
  scheduler.stop();
172
190
 
@@ -201,12 +219,12 @@ describe("scheduler RRULE execution", () => {
201
219
  const directCalls: { conversationId: string; message: string }[] = [];
202
220
  let onMessage: (() => void) | undefined;
203
221
  const messageReceived = new Promise<void>((r) => (onMessage = r));
204
- const processMessage = async (conversationId: string, message: string) => {
222
+ processMessageImpl = async (conversationId, message) => {
205
223
  directCalls.push({ conversationId, message });
206
224
  onMessage?.();
207
225
  };
208
226
 
209
- const scheduler = startScheduler(processMessage, () => {});
227
+ const scheduler = startScheduler();
210
228
  // The run_task path involves a dynamic import which can take >50ms in CI,
211
229
  // exceeding the patched setTimeout delay. Await the actual callback instead
212
230
  // of relying on a fixed timeout.
@@ -271,10 +289,7 @@ describe("scheduler RRULE execution", () => {
271
289
  };
272
290
 
273
291
  // First tick: the expired schedule should fire its final due run
274
- const scheduler1 = startScheduler(
275
- async () => {},
276
- () => {},
277
- );
292
+ const scheduler1 = startScheduler();
278
293
  await new Promise((resolve) => setTimeout(resolve, 500));
279
294
  scheduler1.stop();
280
295
 
@@ -294,10 +309,7 @@ describe("scheduler RRULE execution", () => {
294
309
 
295
310
  // Second tick: the disabled schedule must NOT fire again
296
311
  processedMessages.length = 0;
297
- const scheduler2 = startScheduler(
298
- async () => {},
299
- () => {},
300
- );
312
+ const scheduler2 = startScheduler();
301
313
  await new Promise((resolve) => setTimeout(resolve, 500));
302
314
  scheduler2.stop();
303
315
 
@@ -327,10 +339,7 @@ describe("scheduler RRULE execution", () => {
327
339
  processedMessages.push({ conversationId, message: prompt });
328
340
  };
329
341
 
330
- const scheduler = startScheduler(
331
- async () => {},
332
- () => {},
333
- );
342
+ const scheduler = startScheduler();
334
343
  await new Promise((resolve) => setTimeout(resolve, 500));
335
344
  scheduler.stop();
336
345
 
@@ -385,10 +394,7 @@ describe("scheduler RRULE execution", () => {
385
394
  // Force the schedule to be due
386
395
  forceScheduleDue(schedule.id);
387
396
 
388
- const scheduler = startScheduler(
389
- async () => {},
390
- () => {},
391
- );
397
+ const scheduler = startScheduler();
392
398
  await new Promise((resolve) => setTimeout(resolve, 500));
393
399
  scheduler.stop();
394
400
 
@@ -437,10 +443,7 @@ describe("scheduler RRULE execution", () => {
437
443
  processedMessages.push(prompt);
438
444
  };
439
445
 
440
- const scheduler = startScheduler(
441
- async () => {},
442
- () => {},
443
- );
446
+ const scheduler = startScheduler();
444
447
  await new Promise((resolve) => setTimeout(resolve, 500));
445
448
  scheduler.stop();
446
449
 
@@ -516,10 +519,7 @@ describe("scheduler RRULE execution", () => {
516
519
  processedMessages.push(prompt);
517
520
  };
518
521
 
519
- const scheduler = startScheduler(
520
- async () => {},
521
- () => {},
522
- );
522
+ const scheduler = startScheduler();
523
523
  await new Promise((resolve) => setTimeout(resolve, 500));
524
524
  scheduler.stop();
525
525
 
@@ -557,8 +557,7 @@ describe("scheduler RRULE execution", () => {
557
557
  forceScheduleDue(schedule.id);
558
558
  const forcedDueAt = getSchedule(schedule.id)!.nextRunAt;
559
559
 
560
- const processMessage = async () => {};
561
- const scheduler = startScheduler(processMessage, () => {});
560
+ const scheduler = startScheduler();
562
561
  await new Promise((resolve) => setTimeout(resolve, 500));
563
562
  scheduler.stop();
564
563
 
@@ -589,10 +588,7 @@ describe("scheduler RRULE execution", () => {
589
588
  processedMessages.push({ conversationId, message: prompt });
590
589
  };
591
590
 
592
- const scheduler = startScheduler(
593
- async () => {},
594
- () => {},
595
- );
591
+ const scheduler = startScheduler();
596
592
  await new Promise((resolve) => setTimeout(resolve, 500));
597
593
  scheduler.stop();
598
594
 
@@ -623,32 +619,19 @@ describe("scheduler RRULE execution", () => {
623
619
 
624
620
  expect(getSchedule(schedule.id)!.status).toBe("active");
625
621
 
626
- const notifyCalls: Array<{
627
- id: string;
628
- label: string;
629
- message: string;
630
- routingIntent: string;
631
- routingHints: Record<string, unknown>;
632
- }> = [];
633
- const notifyScheduleOneShot = (payload: {
634
- id: string;
635
- label: string;
636
- message: string;
637
- routingIntent: string;
638
- routingHints: Record<string, unknown>;
639
- }) => {
640
- notifyCalls.push(payload);
641
- };
642
-
643
- const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
622
+ const scheduler = startScheduler();
644
623
  await new Promise((resolve) => setTimeout(resolve, 500));
645
624
  scheduler.stop();
646
625
 
647
- expect(notifyCalls).toHaveLength(1);
648
- expect(notifyCalls[0]).toEqual({
649
- id: schedule.id,
650
- label: "One-shot notify",
651
- message: "Notify about this",
626
+ expect(notifySignalCalls).toHaveLength(1);
627
+ expect(notifySignalCalls[0]).toMatchObject({
628
+ sourceEventName: "schedule.notify",
629
+ sourceContextId: schedule.id,
630
+ contextPayload: {
631
+ scheduleId: schedule.id,
632
+ label: "One-shot notify",
633
+ message: "Notify about this",
634
+ },
652
635
  routingIntent: "multi_channel",
653
636
  routingHints: { channel: "slack" },
654
637
  });
@@ -671,10 +654,7 @@ describe("scheduler RRULE execution", () => {
671
654
 
672
655
  runBackgroundJobShouldFail = true;
673
656
 
674
- const scheduler = startScheduler(
675
- async () => {},
676
- () => {},
677
- );
657
+ const scheduler = startScheduler();
678
658
  await new Promise((resolve) => setTimeout(resolve, 500));
679
659
  scheduler.stop();
680
660
 
@@ -699,32 +679,19 @@ describe("scheduler RRULE execution", () => {
699
679
 
700
680
  forceScheduleDue(schedule.id);
701
681
 
702
- const notifyCalls: Array<{
703
- id: string;
704
- label: string;
705
- message: string;
706
- routingIntent: string;
707
- routingHints: Record<string, unknown>;
708
- }> = [];
709
- const notifyScheduleOneShot = (payload: {
710
- id: string;
711
- label: string;
712
- message: string;
713
- routingIntent: string;
714
- routingHints: Record<string, unknown>;
715
- }) => {
716
- notifyCalls.push(payload);
717
- };
718
-
719
- const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
682
+ const scheduler = startScheduler();
720
683
  await new Promise((resolve) => setTimeout(resolve, 500));
721
684
  scheduler.stop();
722
685
 
723
- expect(notifyCalls).toHaveLength(1);
724
- expect(notifyCalls[0]).toEqual({
725
- id: schedule.id,
726
- label: "Recurring notify",
727
- message: "Recurring notification",
686
+ expect(notifySignalCalls).toHaveLength(1);
687
+ expect(notifySignalCalls[0]).toMatchObject({
688
+ sourceEventName: "schedule.notify",
689
+ sourceContextId: schedule.id,
690
+ contextPayload: {
691
+ scheduleId: schedule.id,
692
+ label: "Recurring notify",
693
+ message: "Recurring notification",
694
+ },
728
695
  routingIntent: "single_channel",
729
696
  routingHints: { preferred: "email" },
730
697
  });
@@ -752,30 +719,13 @@ describe("scheduler RRULE execution", () => {
752
719
  },
753
720
  });
754
721
 
755
- const notifyCalls: Array<{
756
- id: string;
757
- label: string;
758
- message: string;
759
- routingIntent: string;
760
- routingHints: Record<string, unknown>;
761
- }> = [];
762
- const notifyScheduleOneShot = (payload: {
763
- id: string;
764
- label: string;
765
- message: string;
766
- routingIntent: string;
767
- routingHints: Record<string, unknown>;
768
- }) => {
769
- notifyCalls.push(payload);
770
- };
771
-
772
- const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
722
+ const scheduler = startScheduler();
773
723
  await new Promise((resolve) => setTimeout(resolve, 500));
774
724
  scheduler.stop();
775
725
 
776
- expect(notifyCalls).toHaveLength(1);
777
- expect(notifyCalls[0].routingIntent).toBe("all_channels");
778
- expect(notifyCalls[0].routingHints).toEqual({
726
+ expect(notifySignalCalls).toHaveLength(1);
727
+ expect(notifySignalCalls[0].routingIntent).toBe("all_channels");
728
+ expect(notifySignalCalls[0].routingHints).toEqual({
779
729
  requestedByUser: true,
780
730
  channelMentions: ["telegram", "slack"],
781
731
  priority: "high",
@@ -86,9 +86,28 @@ mock.module("../runtime/background-job-runner.js", () => ({
86
86
  },
87
87
  }));
88
88
 
89
+ // The scheduler's reuse path dispatches into the existing conversation through
90
+ // `processMessage`; capture those calls into the same shared log as the
91
+ // fresh-bootstrap runner so assertions don't need to know which path ran.
92
+ const captureProcessedMessage = async (
93
+ conversationId: string,
94
+ message: string,
95
+ ): Promise<void> => {
96
+ processedMessages.push({ conversationId, message });
97
+ };
98
+ let processMessageImpl: (
99
+ conversationId: string,
100
+ message: string,
101
+ ) => Promise<void> = captureProcessedMessage;
102
+ mock.module("../daemon/process-message.js", () => ({
103
+ processMessage: (conversationId: string, message: string) =>
104
+ processMessageImpl(conversationId, message),
105
+ }));
106
+
89
107
  import { deleteConversation } from "../persistence/conversation-crud.js";
90
108
  import { getDb } from "../persistence/db-connection.js";
91
109
  import { initializeDb } from "../persistence/db-init.js";
110
+ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
92
111
  import { createSchedule, getScheduleRuns } from "../schedule/schedule-store.js";
93
112
  import { startScheduler } from "../schedule/scheduler.js";
94
113
 
@@ -148,6 +167,7 @@ describe("scheduler conversation reuse", () => {
148
167
  db.run("DELETE FROM messages");
149
168
  db.run("DELETE FROM conversations");
150
169
  processedMessages.length = 0;
170
+ processMessageImpl = captureProcessedMessage;
151
171
  runBackgroundJobOptions.length = 0;
152
172
  runBackgroundJobShouldFail = false;
153
173
  runBackgroundJobBootstrapFails = false;
@@ -173,11 +193,7 @@ describe("scheduler conversation reuse", () => {
173
193
  // WHEN the schedule fires for the first time
174
194
  forceScheduleDue(schedule.id);
175
195
 
176
- const processMessage = async (conversationId: string, message: string) => {
177
- processedMessages.push({ conversationId, message });
178
- };
179
-
180
- const scheduler1 = startScheduler(processMessage, () => {});
196
+ const scheduler1 = startScheduler();
181
197
  await new Promise((resolve) => setTimeout(resolve, 500));
182
198
  scheduler1.stop();
183
199
 
@@ -196,7 +212,7 @@ describe("scheduler conversation reuse", () => {
196
212
  forceScheduleDue(schedule.id);
197
213
  processedMessages.length = 0;
198
214
 
199
- const scheduler2 = startScheduler(processMessage, () => {});
215
+ const scheduler2 = startScheduler();
200
216
  await new Promise((resolve) => setTimeout(resolve, 500));
201
217
  scheduler2.stop();
202
218
 
@@ -233,11 +249,7 @@ describe("scheduler conversation reuse", () => {
233
249
  // WHEN the schedule fires for the first time
234
250
  forceScheduleDue(schedule.id);
235
251
 
236
- const processMessage = async (conversationId: string, message: string) => {
237
- processedMessages.push({ conversationId, message });
238
- };
239
-
240
- const scheduler1 = startScheduler(processMessage, () => {});
252
+ const scheduler1 = startScheduler();
241
253
  await new Promise((resolve) => setTimeout(resolve, 500));
242
254
  scheduler1.stop();
243
255
 
@@ -249,7 +261,7 @@ describe("scheduler conversation reuse", () => {
249
261
  forceScheduleDue(schedule.id);
250
262
  processedMessages.length = 0;
251
263
 
252
- const scheduler2 = startScheduler(processMessage, () => {});
264
+ const scheduler2 = startScheduler();
253
265
  await new Promise((resolve) => setTimeout(resolve, 500));
254
266
  scheduler2.stop();
255
267
 
@@ -277,11 +289,7 @@ describe("scheduler conversation reuse", () => {
277
289
  // WHEN the schedule fires for the first time
278
290
  forceScheduleDue(schedule.id);
279
291
 
280
- const processMessage = async (conversationId: string, message: string) => {
281
- processedMessages.push({ conversationId, message });
282
- };
283
-
284
- const scheduler1 = startScheduler(processMessage, () => {});
292
+ const scheduler1 = startScheduler();
285
293
  await new Promise((resolve) => setTimeout(resolve, 500));
286
294
  scheduler1.stop();
287
295
 
@@ -292,7 +300,7 @@ describe("scheduler conversation reuse", () => {
292
300
  forceScheduleDue(schedule.id);
293
301
  processedMessages.length = 0;
294
302
 
295
- const scheduler2 = startScheduler(processMessage, () => {});
303
+ const scheduler2 = startScheduler();
296
304
  await new Promise((resolve) => setTimeout(resolve, 500));
297
305
  scheduler2.stop();
298
306
 
@@ -320,11 +328,7 @@ describe("scheduler conversation reuse", () => {
320
328
 
321
329
  forceScheduleDue(schedule.id);
322
330
 
323
- const processMessage = async (conversationId: string, message: string) => {
324
- processedMessages.push({ conversationId, message });
325
- };
326
-
327
- const scheduler1 = startScheduler(processMessage, () => {});
331
+ const scheduler1 = startScheduler();
328
332
  await new Promise((resolve) => setTimeout(resolve, 500));
329
333
  scheduler1.stop();
330
334
 
@@ -338,7 +342,7 @@ describe("scheduler conversation reuse", () => {
338
342
  forceScheduleDue(schedule.id);
339
343
  processedMessages.length = 0;
340
344
 
341
- const scheduler2 = startScheduler(processMessage, () => {});
345
+ const scheduler2 = startScheduler();
342
346
  await new Promise((resolve) => setTimeout(resolve, 500));
343
347
  scheduler2.stop();
344
348
 
@@ -364,11 +368,7 @@ describe("scheduler conversation reuse", () => {
364
368
  });
365
369
 
366
370
  // WHEN the schedule fires
367
- const processMessage = async (conversationId: string, message: string) => {
368
- processedMessages.push({ conversationId, message });
369
- };
370
-
371
- const scheduler = startScheduler(processMessage, () => {});
371
+ const scheduler = startScheduler();
372
372
  await new Promise((resolve) => setTimeout(resolve, 500));
373
373
  scheduler.stop();
374
374
 
@@ -403,12 +403,12 @@ describe("scheduler conversation reuse", () => {
403
403
  forceScheduleDue(schedule.id);
404
404
 
405
405
  let shouldFail = false;
406
- const processMessage = async (conversationId: string, message: string) => {
406
+ processMessageImpl = async (conversationId, message) => {
407
407
  processedMessages.push({ conversationId, message });
408
408
  if (shouldFail) throw new Error("Simulated failure");
409
409
  };
410
410
 
411
- const scheduler1 = startScheduler(processMessage, () => {});
411
+ const scheduler1 = startScheduler();
412
412
  await new Promise((resolve) => setTimeout(resolve, 500));
413
413
  scheduler1.stop();
414
414
 
@@ -420,7 +420,7 @@ describe("scheduler conversation reuse", () => {
420
420
  processedMessages.length = 0;
421
421
  shouldFail = true;
422
422
 
423
- const scheduler2 = startScheduler(processMessage, () => {});
423
+ const scheduler2 = startScheduler();
424
424
  await new Promise((resolve) => setTimeout(resolve, 500));
425
425
  scheduler2.stop();
426
426
 
@@ -434,7 +434,7 @@ describe("scheduler conversation reuse", () => {
434
434
  processedMessages.length = 0;
435
435
  shouldFail = false;
436
436
 
437
- const scheduler3 = startScheduler(processMessage, () => {});
437
+ const scheduler3 = startScheduler();
438
438
  await new Promise((resolve) => setTimeout(resolve, 500));
439
439
  scheduler3.stop();
440
440
 
@@ -453,6 +453,7 @@ describe("scheduler talk-mode runner option propagation", () => {
453
453
  db.run("DELETE FROM messages");
454
454
  db.run("DELETE FROM conversations");
455
455
  processedMessages.length = 0;
456
+ processMessageImpl = captureProcessedMessage;
456
457
  runBackgroundJobOptions.length = 0;
457
458
  runBackgroundJobShouldFail = false;
458
459
  runBackgroundJobBootstrapFails = false;
@@ -470,8 +471,7 @@ describe("scheduler talk-mode runner option propagation", () => {
470
471
  });
471
472
  forceScheduleDue(schedule.id);
472
473
 
473
- const processMessage = async () => {};
474
- const scheduler = startScheduler(processMessage, () => {});
474
+ const scheduler = startScheduler();
475
475
  await new Promise((resolve) => setTimeout(resolve, 500));
476
476
  scheduler.stop();
477
477
 
@@ -495,8 +495,7 @@ describe("scheduler talk-mode runner option propagation", () => {
495
495
  });
496
496
  forceScheduleDue(schedule.id);
497
497
 
498
- const processMessage = async () => {};
499
- const scheduler = startScheduler(processMessage, () => {});
498
+ const scheduler = startScheduler();
500
499
  await new Promise((resolve) => setTimeout(resolve, 500));
501
500
  scheduler.stop();
502
501
 
@@ -524,8 +523,7 @@ describe("scheduler talk-mode runner option propagation", () => {
524
523
  forceScheduleDue(schedule.id);
525
524
  runBackgroundJobBootstrapFails = true;
526
525
 
527
- const processMessage = async () => {};
528
- const scheduler = startScheduler(processMessage, () => {});
526
+ const scheduler = startScheduler();
529
527
  await new Promise((resolve) => setTimeout(resolve, 500));
530
528
  scheduler.stop();
531
529
 
@@ -554,15 +552,22 @@ describe("scheduler talk-mode runner option propagation", () => {
554
552
  scheduleJobId: string;
555
553
  title: string;
556
554
  }> = [];
557
- const processMessage = async () => {};
558
- const scheduler = startScheduler(
559
- processMessage,
560
- () => {},
561
- undefined,
562
- (info) => sseCalls.push(info),
563
- );
555
+ const subscription = assistantEventHub.subscribe({
556
+ type: "process",
557
+ callback: (event) => {
558
+ if (event.message.type === "schedule_conversation_created") {
559
+ sseCalls.push({
560
+ conversationId: event.message.conversationId,
561
+ scheduleJobId: event.message.scheduleJobId,
562
+ title: event.message.title,
563
+ });
564
+ }
565
+ },
566
+ });
567
+ const scheduler = startScheduler();
564
568
  await new Promise((resolve) => setTimeout(resolve, 500));
565
569
  scheduler.stop();
570
+ subscription.dispose();
566
571
 
567
572
  expect(sseCalls).toHaveLength(1);
568
573
  expect(sseCalls[0]).toMatchObject({