@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
@@ -12,29 +12,22 @@
12
12
  * {@link registerDefaultPlugins}. Registration is idempotent so repeat
13
13
  * calls (e.g. during integration tests) do not throw.
14
14
  * 2. Walks {@link getRegisteredPlugins} in registration order.
15
- * 3. For each plugin, consults `manifest.requiresFlag` against
16
- * {@link isAssistantFeatureFlagEnabled}. If any listed flag is disabled,
17
- * the plugin is skipped wholesale — no `init()`, no tool/route
18
- * contributions, no entry in the shutdown hook, and the plugin is also
19
- * dropped from the hook registry via {@link unregisterPlugin} so none of its
20
- * hooks participate in the turn lifecycle. This is the primary mechanism for
21
- * shipping experimental plugins behind a feature flag.
22
- * 4. Validates the config block under `plugins.<name>` against
15
+ * 3. Validates the config block under `plugins.<name>` against
23
16
  * `manifest.config` if the manifest supplies a parser-like validator
24
17
  * (Zod schemas with `.parse()` are supported; anything else is passed
25
18
  * through untouched).
26
- * 5. Creates a per-plugin writable data directory on demand and exposes it via
19
+ * 4. Creates a per-plugin writable data directory on demand and exposes it via
27
20
  * {@link InitContext.pluginStorageDir}. For user plugins this is
28
21
  * `<pluginDir>/data/`; for default plugins it is
29
22
  * `<workspaceDir>/plugins-data/<plugin>/`.
30
- * 6. For each surviving plugin, registers its contributed tools and routes
23
+ * 5. For each surviving plugin, registers its contributed tools and routes
31
24
  * into their global registries via {@link registerPluginTools} and
32
25
  * {@link registerSkillRoute}. Contributions land BEFORE `init()` so
33
26
  * the plugin's hook can observe a registry where its own model-visible
34
27
  * surface is already wired — useful for plugins that want to attach
35
28
  * metadata, warm caches, or otherwise interact with their own
36
29
  * contributions during initialization.
37
- * 7. Awaits `plugin.init(ctx)` sequentially. An init failure is contained to
30
+ * 6. Awaits `plugin.init(ctx)` sequentially. An init failure is contained to
38
31
  * the offending plugin: its already-registered tools and routes are rolled
39
32
  * back, it is dropped from the registry, the failure is logged, and
40
33
  * bootstrap continues with the remaining plugins. A single plugin's failure
@@ -43,28 +36,24 @@
43
36
  * history repair, title generation) — so the daemon comes up with the
44
37
  * failing plugin absent rather than blacking out the whole plugin layer.
45
38
  *
46
- * A single shutdown hook is registered via
47
- * {@link registerShutdownHook} that walks the plugin list in **reverse
48
- * registration order**. Only plugins that actually initialized (i.e. were
49
- * not skipped by the feature-flag gate) appear in that walk. For each such
50
- * plugin it first unregisters the contributed tools (so `onShutdown()`
51
- * observes a clean model-visible surface) and then awaits the optional
52
- * `onShutdown()`. Per-plugin shutdown failures are logged and swallowed —
53
- * the hook registry already swallows hook-level throws, but we log at the
54
- * plugin level so the plugin name is attributed.
39
+ * Plugin `shutdown` hooks fire through the unified `runHook(HOOKS.SHUTDOWN, …)`
40
+ * pipeline that the daemon shutdown handler runs — the same path every other
41
+ * lifecycle hook uses; this module does not register a shutdown hook of its own.
42
+ * Surfaces (tools/routes/injectors) are not unregistered at daemon shutdown:
43
+ * the process is exiting, so that in-memory registry state is discarded anyway.
44
+ * Surfaces are only torn down when a single plugin is rolled back after a failed
45
+ * bring-up, via {@link teardownPlugin}.
55
46
  */
56
47
 
57
48
  import { existsSync, mkdirSync } from "node:fs";
58
49
  import { join } from "node:path";
59
50
 
60
- import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
61
51
  import { getConfig } from "../config/loader.js";
62
52
  import type { AssistantConfig } from "../config/schema.js";
63
53
  import { HOOKS } from "../plugin-api/constants.js";
64
54
  import {
65
55
  getAllDefaultPlugins,
66
56
  registerDefaultPluginInjectors,
67
- registerDefaultPluginJobHandlers,
68
57
  registerDefaultPluginPersistenceHooks,
69
58
  registerDefaultPlugins,
70
59
  } from "../plugins/defaults/index.js";
@@ -72,10 +61,6 @@ import {
72
61
  registerPluginInjectors,
73
62
  unregisterPluginInjectors,
74
63
  } from "../plugins/injector-registry.js";
75
- import {
76
- registerPluginJobHandlers,
77
- unregisterPluginJobHandlers,
78
- } from "../plugins/job-handler-registry.js";
79
64
  import { getRegisteredPlugins, unregisterPlugin } from "../plugins/registry.js";
80
65
  import {
81
66
  type Plugin,
@@ -95,7 +80,6 @@ import {
95
80
  import { getLogger } from "../util/logger.js";
96
81
  import { getWorkspaceDir, getWorkspacePluginsDir } from "../util/platform.js";
97
82
  import { APP_VERSION } from "../version.js";
98
- import { registerShutdownHook } from "./shutdown-registry.js";
99
83
 
100
84
  const log = getLogger("plugins-bootstrap");
101
85
 
@@ -152,16 +136,6 @@ function ensurePluginStorageDir(pluginName: string): string {
152
136
  return dir;
153
137
  }
154
138
 
155
- function getDisabledPluginFlag(
156
- plugin: Plugin,
157
- config: AssistantConfig,
158
- ): string | undefined {
159
- for (const flagKey of plugin.manifest.requiresFlag ?? []) {
160
- if (!isAssistantFeatureFlagEnabled(flagKey, config)) return flagKey;
161
- }
162
- return undefined;
163
- }
164
-
165
139
  /**
166
140
  * Bring the plugin layer up during daemon startup. Runs the full sequence in
167
141
  * the one order the rest of the system depends on:
@@ -190,8 +164,8 @@ export async function initializePlugins(): Promise<void> {
190
164
  }
191
165
 
192
166
  /**
193
- * Run every registered plugin's `init()` hook sequentially and install a
194
- * reverse-order shutdown hook. See the module docstring for full semantics.
167
+ * Run every registered plugin's `init()` hook sequentially. See the module
168
+ * docstring for full lifecycle semantics (including how `shutdown` hooks fire).
195
169
  *
196
170
  * Returns once every plugin has been processed. A plugin whose `init()` throws
197
171
  * is rolled back, dropped from the registry, and logged; bootstrap continues
@@ -222,17 +196,13 @@ export async function bootstrapPlugins(): Promise<void> {
222
196
  // register while disabled.
223
197
  registerDefaultPluginInjectors();
224
198
 
225
- // Register the default plugins' background-job handlers up front, the
226
- // job-handler analog of the injector registration above. The general job
227
- // worker's `registerMemoryJobHandlers` forwards the registry union into the
228
- // worker dispatch table; pre-registering here keeps the daemon path symmetric
229
- // with tools/routes/injectors (the standalone worker self-registers instead).
230
- registerDefaultPluginJobHandlers();
231
-
232
199
  // Install the memory feature's persistence-lifecycle handlers into the
233
200
  // persistence seam up front, so the layer below memory can drive memory
234
201
  // side effects (message indexing) without importing memory internals.
235
- // Symmetric with the injector/job-handler registration above.
202
+ // Symmetric with the injector registration above. (Background-job handlers
203
+ // are not registered here: the memory plugin registers its own directly in
204
+ // its `init` hook, and the daemon registers the host's non-plugin handlers in
205
+ // `lifecycle.ts`.)
236
206
  registerDefaultPluginPersistenceHooks();
237
207
 
238
208
  // Combine the canonical default plugins with any plugins registered via
@@ -253,36 +223,8 @@ export async function bootstrapPlugins(): Promise<void> {
253
223
 
254
224
  const assistantConfig = getConfig();
255
225
 
256
- // Plugins that passed `requiresFlag` gating and therefore need the full
257
- // init → contribute → shutdown lifecycle. Plugins skipped by the flag gate
258
- // are omitted from this list so the shutdown hook below never tears down
259
- // capabilities that were never wired up in the first place. Each entry
260
- // carries the opaque route handles returned by `registerSkillRoute` so
261
- // teardown can key on identity rather than regex-pattern text — two plugins
262
- // registering the same pattern would otherwise step on each other's routes
263
- // during shutdown, violating the "no traffic hits a plugin handler during
264
- // onShutdown" invariant.
265
- const activePlugins: ActivePlugin[] = [];
266
-
267
- // Shutdown context is identical for every plugin in this boot — construct
268
- // once and reuse across the per-plugin teardown and the normal shutdown
269
- // hook below. Only `assistantVersion` is exposed today; future additions
270
- // live on {@link ShutdownContext}.
271
- const shutdownContext: ShutdownContext = {
272
- assistantVersion: APP_VERSION,
273
- };
274
-
275
226
  for (const plugin of plugins) {
276
227
  const name = plugin.manifest.name;
277
- const disabledFlag = getDisabledPluginFlag(plugin, assistantConfig);
278
- if (disabledFlag !== undefined) {
279
- log.info(
280
- { plugin: name, flag: disabledFlag },
281
- `skipping plugin ${name}: feature flag ${disabledFlag} is disabled`,
282
- );
283
- unregisterPlugin(name);
284
- continue;
285
- }
286
228
 
287
229
  // Check for the .disabled sentinel. Both default and user plugins
288
230
  // can be disabled by creating a `.disabled` file at
@@ -294,12 +236,12 @@ export async function bootstrapPlugins(): Promise<void> {
294
236
  // and drops a `.disabled` file inside it. Runs before init so no
295
237
  // tools or routes from the disabled plugin are ever wired.
296
238
  //
297
- // Unlike the feature-flag path above, we do NOT call
298
- // `unregisterPlugin(name)` here. The plugin's hooks stay in the hook
299
- // registry and are filtered at read time by `isPluginDisabled` in
300
- // `getHooksFor`. This means `assistant plugins enable <name>` takes
301
- // effect on the next turn without a restart the hooks are already
302
- // registered, they just need the sentinel removed to be included.
239
+ // We do NOT call `unregisterPlugin(name)` here. The plugin's hooks
240
+ // stay in the hook registry and are filtered at read time by
241
+ // `isPluginDisabled` in `getHooksFor`. This means `assistant plugins
242
+ // enable <name>` takes effect on the next turn without a restart —
243
+ // the hooks are already registered, they just need the sentinel
244
+ // removed to be included.
303
245
  const disabledSentinelPath = join(
304
246
  getWorkspacePluginsDir(),
305
247
  name,
@@ -314,7 +256,7 @@ export async function bootstrapPlugins(): Promise<void> {
314
256
  }
315
257
 
316
258
  try {
317
- activePlugins.push(await initializePlugin(plugin, assistantConfig));
259
+ await initializePlugin(plugin, assistantConfig);
318
260
  } catch (err) {
319
261
  // Contain the failure to this plugin. `initializePlugin` already rolled
320
262
  // back its own partial tool/route contributions, so we just drop
@@ -330,27 +272,6 @@ export async function bootstrapPlugins(): Promise<void> {
330
272
  );
331
273
  }
332
274
  }
333
-
334
- // Shutdown hook — walks plugins in REVERSE registration order. We snapshot
335
- // only the plugins that actually initialized so later registrations (if
336
- // any) don't end up being torn down by this hook, and plugins skipped by
337
- // `requiresFlag` gating do not appear in the tear-down list. Subsequent
338
- // bootstraps (hot-reload) would register their own hook.
339
- //
340
- // For each plugin we:
341
- // 1. Unregister contributed HTTP routes so incoming requests stop hitting
342
- // the plugin's handlers before its state is torn down.
343
- // 2. Unregister contributed tools so the model-visible tool surface is
344
- // cleared before `onShutdown()` runs.
345
- // 3. Call `onShutdown()` (if defined) so the plugin can release resources
346
- // (background tasks, timers, connections) with its tools and routes
347
- // already removed.
348
- const shutdownSnapshot: ActivePlugin[] = [...activePlugins];
349
- registerShutdownHook("plugins", async (reason) => {
350
- for (let i = shutdownSnapshot.length - 1; i >= 0; i--) {
351
- await teardownPlugin(shutdownSnapshot[i]!, reason, shutdownContext);
352
- }
353
- });
354
275
  }
355
276
 
356
277
  /**
@@ -422,14 +343,6 @@ async function initializePlugin(
422
343
  );
423
344
  }
424
345
 
425
- if (plugin.jobHandlers && plugin.jobHandlers.length > 0) {
426
- registerPluginJobHandlers(name, plugin.jobHandlers);
427
- log.info(
428
- { plugin: name, count: plugin.jobHandlers.length },
429
- "plugin job handlers registered",
430
- );
431
- }
432
-
433
346
  if (plugin.hooks?.[HOOKS.INIT]) {
434
347
  try {
435
348
  await plugin.hooks[HOOKS.INIT](initContext);
@@ -449,45 +362,50 @@ async function initializePlugin(
449
362
  return { plugin, routeHandles };
450
363
  } catch (err) {
451
364
  if (initCompleted) {
452
- await teardownPlugin({ plugin, routeHandles }, "bootstrap-failed", {
453
- assistantVersion: APP_VERSION,
454
- });
365
+ await teardownPlugin(
366
+ { plugin, routeHandles },
367
+ { assistantVersion: APP_VERSION, reason: "disable" },
368
+ );
455
369
  } else {
456
370
  for (const handle of routeHandles) {
457
371
  unregisterSkillRoute(handle);
458
372
  }
459
373
  unregisterPluginTools(name);
460
374
  unregisterPluginInjectors(name);
461
- unregisterPluginJobHandlers(name);
462
375
  }
463
376
  throw err;
464
377
  }
465
378
  }
466
379
 
467
380
  /**
468
- * Tear down a single fully-initialized plugin: unregister routes, unregister
469
- * tools, then invoke `onShutdown()` if present. Every step swallows errors and
470
- * logs with plugin attribution so one bad plugin can't block teardown of the
471
- * rest.
381
+ * Unregister every initialized plugin's contributed routes and tools in reverse
382
+ * registration order, clearing the model-visible surface before the shutdown
383
+ * handler dispatches `shutdown` hooks via `runHook(HOOKS.SHUTDOWN, …)`. Reads
384
+ * the snapshot captured by the most recent {@link bootstrapPlugins} run; a
385
+ * no-op when no plugins initialized. Called by the daemon shutdown handler.
386
+ */
387
+ /**
388
+ * Tear down a single fully-initialized plugin: unregister its model-visible
389
+ * surfaces (contributed HTTP routes — keyed by the opaque handles retained at
390
+ * registration time, since pattern text is not a stable key when two owners
391
+ * register the same regex — plus its tools and runtime injectors), then invoke
392
+ * its optional `shutdown` hook with the tools/routes already gone. Every step
393
+ * swallows errors and logs with plugin attribution so one bad plugin can't
394
+ * block teardown.
472
395
  *
473
- * Shared between the normal shutdown hook and the bootstrap error path; both
474
- * consume plugins that already cleared every contribution step.
396
+ * Used by the bootstrap-failure rollback path. The normal daemon shutdown path
397
+ * does not unregister surfaces (the process is exiting, so that in-memory state
398
+ * is discarded anyway); it only fires `shutdown` hooks through the unified
399
+ * `runHook(HOOKS.SHUTDOWN, …)` pipeline.
475
400
  */
476
401
  async function teardownPlugin(
477
402
  active: ActivePlugin,
478
- reason: string,
479
403
  shutdownContext: ShutdownContext,
480
404
  ): Promise<void> {
481
405
  const { plugin, routeHandles } = active;
482
406
  const name = plugin.manifest.name;
407
+ const { reason } = shutdownContext;
483
408
 
484
- // Unregister model-visible surfaces before invoking `onShutdown()` so the
485
- // plugin's onShutdown hook observes a registry state where its tools and
486
- // routes are already gone. `unregisterPluginTools` is a no-op when the
487
- // plugin never contributed tools, so we don't need to guard on
488
- // `plugin.tools` here. Route unregistration keys on the opaque handles
489
- // retained at registration time — pattern text is not a stable key because
490
- // two owners can legitimately register the same regex.
491
409
  for (const handle of routeHandles) {
492
410
  try {
493
411
  unregisterSkillRoute(handle);
@@ -509,16 +427,11 @@ async function teardownPlugin(
509
427
  }
510
428
 
511
429
  unregisterPluginInjectors(name);
512
- unregisterPluginJobHandlers(name);
513
430
 
514
431
  if (plugin.hooks?.[HOOKS.SHUTDOWN]) {
515
432
  try {
516
433
  await plugin.hooks[HOOKS.SHUTDOWN](shutdownContext);
517
434
  } catch (err) {
518
- // Swallow — we want every plugin's shutdown to get a chance to run
519
- // even when an earlier one throws. The outer runShutdownHooks already
520
- // logs at hook level, but the plugin-name attribution here is what
521
- // operators read first.
522
435
  log.warn(
523
436
  { err, plugin: name, reason },
524
437
  "plugin shutdown hook failed (continuing with remaining plugins)",
@@ -38,7 +38,7 @@ await initializeDb();
38
38
 
39
39
  function resetTables(): void {
40
40
  const sqlite = getSqlite();
41
- sqlite.run("DELETE FROM assistant_ingress_invites");
41
+ sqlite.run("DELETE FROM a2a_invites");
42
42
  sqlite.run("DELETE FROM assistant_contact_metadata");
43
43
  sqlite.run("DELETE FROM contact_channels");
44
44
  sqlite.run("DELETE FROM contacts");
@@ -26,19 +26,31 @@ import {
26
26
  } from "../../../contacts/contact-store.js";
27
27
  import { getSqlite } from "../../../persistence/db-connection.js";
28
28
  import { initializeDb } from "../../../persistence/db-init.js";
29
- import { findById } from "../../../persistence/invite-store.js";
30
29
  import { completeA2AInvite, createA2AInvite } from "../config-a2a.js";
31
30
 
32
31
  await initializeDb();
33
32
 
34
33
  function resetTables(): void {
35
34
  const sqlite = getSqlite();
36
- sqlite.run("DELETE FROM assistant_ingress_invites");
35
+ sqlite.run("DELETE FROM a2a_invites");
37
36
  sqlite.run("DELETE FROM assistant_contact_metadata");
38
37
  sqlite.run("DELETE FROM contact_channels");
39
38
  sqlite.run("DELETE FROM contacts");
40
39
  }
41
40
 
41
+ interface A2aInviteRow {
42
+ id: string;
43
+ contact_id: string;
44
+ status: string;
45
+ use_count: number;
46
+ }
47
+
48
+ function getInviteRow(id: string): A2aInviteRow | null {
49
+ return getSqlite()
50
+ .prepare("SELECT * FROM a2a_invites WHERE id = ?")
51
+ .get(id) as A2aInviteRow | null;
52
+ }
53
+
42
54
  function setConfig(opts: {
43
55
  a2aEnabled?: boolean;
44
56
  publicBaseUrl?: string;
@@ -92,10 +104,10 @@ describe("completeA2AInvite", () => {
92
104
  expect(result.error).toBeUndefined();
93
105
 
94
106
  // Verify the placeholder contact was promoted
95
- const invite = findById(created.inviteId!);
107
+ const invite = getInviteRow(created.inviteId!);
96
108
  expect(invite).not.toBeNull();
97
109
 
98
- const contact = getContact(invite!.contactId);
110
+ const contact = getContact(invite!.contact_id);
99
111
  expect(contact).not.toBeNull();
100
112
  expect(contact!.displayName).toBe("Acceptor Bot");
101
113
  expect(contact!.channels).toHaveLength(1);
@@ -116,8 +128,8 @@ describe("completeA2AInvite", () => {
116
128
  });
117
129
  expect(result.success).toBe(true);
118
130
 
119
- const invite = findById(created.inviteId!);
120
- const contact = getContact(invite!.contactId);
131
+ const invite = getInviteRow(created.inviteId!);
132
+ const contact = getContact(invite!.contact_id);
121
133
  expect(contact!.channels[0]!.address).toBe("upper-case-id-123");
122
134
  });
123
135
 
@@ -130,8 +142,8 @@ describe("completeA2AInvite", () => {
130
142
  });
131
143
  expect(result.success).toBe(true);
132
144
 
133
- const invite = findById(created.inviteId!);
134
- const metadata = getAssistantContactMetadata(invite!.contactId);
145
+ const invite = getInviteRow(created.inviteId!);
146
+ const metadata = getAssistantContactMetadata(invite!.contact_id);
135
147
  expect(metadata).not.toBeNull();
136
148
  expect(metadata!.species).toBe("vellum");
137
149
  expect(metadata!.metadata).toEqual({
@@ -159,10 +171,10 @@ describe("completeA2AInvite", () => {
159
171
  // The invite was just created with 0 hours expiry, so expiresAt ~= now
160
172
  // Manually expire it by updating the DB
161
173
  const sqlite = getSqlite();
162
- sqlite.run(
163
- "UPDATE assistant_ingress_invites SET expires_at = ? WHERE id = ?",
164
- [Date.now() - 1000, created.inviteId!],
165
- );
174
+ sqlite.run("UPDATE a2a_invites SET expires_at = ? WHERE id = ?", [
175
+ Date.now() - 1000,
176
+ created.inviteId!,
177
+ ]);
166
178
 
167
179
  const result = completeA2AInvite({
168
180
  token: created.token!,
@@ -238,8 +250,8 @@ describe("completeA2AInvite", () => {
238
250
  expect(result.error).toContain("public base URL");
239
251
 
240
252
  // Verify the invite was NOT consumed
241
- const invite = findById(created.inviteId!);
253
+ const invite = getInviteRow(created.inviteId!);
242
254
  expect(invite!.status).toBe("active");
243
- expect(invite!.useCount).toBe(0);
255
+ expect(invite!.use_count).toBe(0);
244
256
  });
245
257
  });
@@ -23,19 +23,33 @@ import {
23
23
  import { getContact } from "../../../contacts/contact-store.js";
24
24
  import { getSqlite } from "../../../persistence/db-connection.js";
25
25
  import { initializeDb } from "../../../persistence/db-init.js";
26
- import { findById } from "../../../persistence/invite-store.js";
27
26
  import { createA2AInvite, getA2AConfig } from "../config-a2a.js";
28
27
 
29
28
  await initializeDb();
30
29
 
31
30
  function resetTables(): void {
32
31
  const sqlite = getSqlite();
33
- sqlite.run("DELETE FROM assistant_ingress_invites");
32
+ sqlite.run("DELETE FROM a2a_invites");
34
33
  sqlite.run("DELETE FROM assistant_contact_metadata");
35
34
  sqlite.run("DELETE FROM contact_channels");
36
35
  sqlite.run("DELETE FROM contacts");
37
36
  }
38
37
 
38
+ interface A2aInviteRow {
39
+ id: string;
40
+ contact_id: string;
41
+ status: string;
42
+ max_uses: number;
43
+ use_count: number;
44
+ expires_at: number;
45
+ }
46
+
47
+ function getInviteRow(id: string): A2aInviteRow | null {
48
+ return getSqlite()
49
+ .prepare("SELECT * FROM a2a_invites WHERE id = ?")
50
+ .get(id) as A2aInviteRow | null;
51
+ }
52
+
39
53
  function setConfig(opts: {
40
54
  a2aEnabled?: boolean;
41
55
  publicBaseUrl?: string;
@@ -75,15 +89,14 @@ describe("createA2AInvite", () => {
75
89
  expect(result.error).toBeUndefined();
76
90
  });
77
91
 
78
- test("creates invite in DB with source_channel=a2a, status=active, max_uses=1", () => {
92
+ test("creates invite in a2a_invites with status=active, max_uses=1", () => {
79
93
  const result = createA2AInvite({});
80
94
  expect(result.inviteId).toBeDefined();
81
95
 
82
- const invite = findById(result.inviteId!);
96
+ const invite = getInviteRow(result.inviteId!);
83
97
  expect(invite).not.toBeNull();
84
- expect(invite!.sourceChannel).toBe("a2a");
85
98
  expect(invite!.status).toBe("active");
86
- expect(invite!.maxUses).toBe(1);
99
+ expect(invite!.max_uses).toBe(1);
87
100
  });
88
101
 
89
102
  test("auto-enables A2A if not already on", () => {
@@ -101,10 +114,10 @@ describe("createA2AInvite", () => {
101
114
  const result = createA2AInvite({});
102
115
  expect(result.inviteId).toBeDefined();
103
116
 
104
- const invite = findById(result.inviteId!);
117
+ const invite = getInviteRow(result.inviteId!);
105
118
  expect(invite).not.toBeNull();
106
119
 
107
- const contact = getContact(invite!.contactId);
120
+ const contact = getContact(invite!.contact_id);
108
121
  expect(contact).not.toBeNull();
109
122
  expect(contact!.displayName).toBe("Pending A2A invite");
110
123
  expect(contact!.channels).toHaveLength(0);
@@ -128,13 +141,13 @@ describe("createA2AInvite", () => {
128
141
  const after = Date.now();
129
142
  expect(result.success).toBe(true);
130
143
 
131
- const invite = findById(result.inviteId!);
144
+ const invite = getInviteRow(result.inviteId!);
132
145
  expect(invite).not.toBeNull();
133
146
 
134
147
  const expectedMinMs = before + 24 * 60 * 60 * 1000;
135
148
  const expectedMaxMs = after + 24 * 60 * 60 * 1000;
136
- expect(invite!.expiresAt).toBeGreaterThanOrEqual(expectedMinMs);
137
- expect(invite!.expiresAt).toBeLessThanOrEqual(expectedMaxMs);
149
+ expect(invite!.expires_at).toBeGreaterThanOrEqual(expectedMinMs);
150
+ expect(invite!.expires_at).toBeLessThanOrEqual(expectedMaxMs);
138
151
  });
139
152
 
140
153
  test("default expiry is 72 hours", () => {
@@ -143,12 +156,12 @@ describe("createA2AInvite", () => {
143
156
  const after = Date.now();
144
157
  expect(result.success).toBe(true);
145
158
 
146
- const invite = findById(result.inviteId!);
159
+ const invite = getInviteRow(result.inviteId!);
147
160
  expect(invite).not.toBeNull();
148
161
 
149
162
  const expectedMinMs = before + 72 * 60 * 60 * 1000;
150
163
  const expectedMaxMs = after + 72 * 60 * 60 * 1000;
151
- expect(invite!.expiresAt).toBeGreaterThanOrEqual(expectedMinMs);
152
- expect(invite!.expiresAt).toBeLessThanOrEqual(expectedMaxMs);
164
+ expect(invite!.expires_at).toBeGreaterThanOrEqual(expectedMinMs);
165
+ expect(invite!.expires_at).toBeLessThanOrEqual(expectedMaxMs);
153
166
  });
154
167
  });
@@ -92,7 +92,6 @@ mock.module("../../../ipc/gateway-client.js", () => ({
92
92
 
93
93
  mock.module("../../../runtime/channel-verification-service.js", () => ({
94
94
  getGuardianBinding: () => mockBinding,
95
- revokeBinding: () => true,
96
95
  revokePendingSessions: () => {},
97
96
  createOutboundSession: () => ({
98
97
  sessionId: "sess",
@@ -129,10 +128,6 @@ function channel(overrides: Partial<ContactChannel> = {}): ContactChannel {
129
128
  address: "user-123",
130
129
  isPrimary: true,
131
130
  externalChatId: "chat-123",
132
- inviteId: null,
133
- lastSeenAt: null,
134
- interactionCount: 0,
135
- lastInteraction: null,
136
131
  updatedAt: null,
137
132
  createdAt: 0,
138
133
  ...overrides,
@@ -26,12 +26,11 @@ import {
26
26
  } from "../../contacts/contact-store.js";
27
27
  import type { VellumAssistantMetadata } from "../../contacts/types.js";
28
28
  import { getPublicBaseUrl } from "../../inbound/public-ingress-urls.js";
29
- import { getDb } from "../../persistence/db-connection.js";
30
29
  import {
31
- claimA2AInvite,
32
- createInvite,
33
- hashToken,
34
- } from "../../persistence/invite-store.js";
30
+ claimA2aInvite,
31
+ createA2aInvite,
32
+ } from "../../persistence/a2a-invite-store.js";
33
+ import { getDb } from "../../persistence/db-connection.js";
35
34
  import { assistantContactMetadata } from "../../persistence/schema/index.js";
36
35
  import type { HttpErrorResponse } from "../../runtime/http-errors.js";
37
36
  import { getLogger } from "../../util/logger.js";
@@ -157,8 +156,7 @@ export function createA2AInvite(params: {
157
156
 
158
157
  // 4. Create the invite
159
158
  const expiresInMs = (params.expiresInHours ?? 72) * 60 * 60 * 1000;
160
- const { invite, rawToken } = createInvite({
161
- sourceChannel: "a2a",
159
+ const { invite, rawToken } = createA2aInvite({
162
160
  contactId: contact.id,
163
161
  maxUses: 1,
164
162
  expiresInMs,
@@ -197,9 +195,8 @@ export function completeA2AInvite(params: {
197
195
  };
198
196
  }
199
197
 
200
- const tokenHash = hashToken(params.token);
201
- const claimResult = claimA2AInvite({
202
- tokenHash,
198
+ const claimResult = claimA2aInvite({
199
+ token: params.token,
203
200
  redeemedByExternalUserId: params.acceptor.assistantId,
204
201
  });
205
202
 
@@ -219,8 +216,6 @@ export function completeA2AInvite(params: {
219
216
  {
220
217
  type: "a2a",
221
218
  address: params.acceptor.assistantId.toLowerCase(),
222
- status: "active",
223
- policy: "allow",
224
219
  },
225
220
  ],
226
221
  });
@@ -283,8 +278,6 @@ export function redeemA2AInvite(params: {
283
278
  {
284
279
  type: "a2a",
285
280
  address: params.sender.assistantId.toLowerCase(),
286
- status: "active",
287
- policy: "allow",
288
281
  },
289
282
  ],
290
283
  });
@@ -34,7 +34,6 @@ import {
34
34
  getGuardianBinding,
35
35
  getPendingSession,
36
36
  isGuardianBoundForChannel,
37
- revokeBinding,
38
37
  revokePendingSessions,
39
38
  updateSessionDelivery,
40
39
  } from "../../runtime/channel-verification-service.js";
@@ -263,19 +262,12 @@ export async function revokeVerificationForChannel(
263
262
  if (!parsed.ok) {
264
263
  throw new Error("mark_channel_revoked relay returned ok: false");
265
264
  }
266
- // The gateway dual-write already set the assistant channel to "revoked",
267
- // so the later revokeGuardianBinding lookup (active-only) finds nothing
268
- // and won't fire the invalidation. Emit it here so open client views
269
- // stop showing the channel as active.
265
+ // Emit the invalidation so open client views stop showing the channel
266
+ // as active after the gateway dual-writes it to "revoked".
270
267
  notifyContactsChanged();
271
268
  }
272
269
  }
273
270
 
274
- // The guardian binding is assistant-owned state the gateway relay does not
275
- // manage; tear it down here. The contact-change invalidation is emitted
276
- // explicitly above on relay success.
277
- revokeBinding(assistantId, resolvedChannel);
278
-
279
271
  return {
280
272
  success: true,
281
273
  bound: false,
@@ -16,7 +16,9 @@ export interface ConversationSearchParams {
16
16
  }
17
17
 
18
18
  /** Search conversations and return results (no transport dependency). */
19
- export function performConversationSearch(params: ConversationSearchParams) {
19
+ export async function performConversationSearch(
20
+ params: ConversationSearchParams,
21
+ ) {
20
22
  // Treat "*" as a list-all wildcard — FTS treats it as a literal character.
21
23
  if (params.query.trim() === "*") {
22
24
  const rows = listConversations(params.limit);