@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
@@ -22,7 +22,6 @@
22
22
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
23
23
  import { join } from "node:path";
24
24
 
25
- import { registerShutdownHook } from "../daemon/shutdown-registry.js";
26
25
  import {
27
26
  clearPluginHooks,
28
27
  collectUserHooks,
@@ -35,7 +34,7 @@ import {
35
34
  runShutdownHook,
36
35
  WORKSPACE_HOOKS_OWNER,
37
36
  } from "../hooks/hook-loader.js";
38
- import type { HookFunction, ShutdownContext } from "../plugin-api/types.js";
37
+ import type { HookFunction, ShutdownReason } from "../plugin-api/types.js";
39
38
  import {
40
39
  registerPluginTools,
41
40
  unregisterPluginTools,
@@ -178,12 +177,21 @@ const disabledPluginDirs = new Set<string>();
178
177
  * workspace hooks. Refreshes plugin discovery first, then delegates the actual
179
178
  * hook resolution to the hook loader. Plugin hooks run in install-date order,
180
179
  * the workspace hook runs last.
180
+ *
181
+ * `effectiveEnabledPlugins` carries the per-chat plugin scope: when non-null,
182
+ * user plugins outside the set are skipped (standalone workspace hooks always
183
+ * run). `null`/omitted means no per-chat restriction.
181
184
  */
182
185
  export async function getUserHooksFor<TCtx = unknown>(
183
186
  hookName: string,
187
+ effectiveEnabledPlugins?: Set<string> | null,
184
188
  ): Promise<HookFunction<TCtx>[]> {
185
189
  await scanPlugins();
186
- return collectUserHooks<TCtx>(hookName, discoveredPluginDirs);
190
+ return collectUserHooks<TCtx>(
191
+ hookName,
192
+ discoveredPluginDirs,
193
+ effectiveEnabledPlugins,
194
+ );
187
195
  }
188
196
 
189
197
  // ─── Tool cache ──────────────────────────────────────────────────────────────
@@ -320,7 +328,7 @@ async function scanPlugins(): Promise<void> {
320
328
  const manifest = await parsePluginManifest(pluginDir);
321
329
  const pluginName = manifest?.name ?? entry;
322
330
  if (discoveredPluginDirs.has(pluginDir)) {
323
- await deactivatePlugin(pluginName);
331
+ await deactivatePlugin(pluginName, "disable");
324
332
  await evictPlugin(pluginDir, pluginName);
325
333
  }
326
334
  if (!disabledPluginDirs.has(pluginDir)) {
@@ -351,7 +359,7 @@ async function scanPlugins(): Promise<void> {
351
359
  // Deactivate and evict cache entries for deleted plugins.
352
360
  for (const [pluginDir, pluginName] of discoveredPluginDirs) {
353
361
  if (!currentDirs.has(pluginDir)) {
354
- await deactivatePlugin(pluginName);
362
+ await deactivatePlugin(pluginName, "uninstall");
355
363
  await evictPlugin(pluginDir, pluginName);
356
364
  }
357
365
  }
@@ -422,8 +430,10 @@ async function evictAll(): Promise<void> {
422
430
 
423
431
  /**
424
432
  * Plugins (and the workspace-hooks pseudo-owner) fully activated (tools
425
- * registered + `init` hook run) within this process, in activation order. The
426
- * process shutdown hook walks this list in reverse to tear everything down.
433
+ * registered + `init` hook run) within this process, in activation order. A
434
+ * runtime uninstall/disable tears a single entry down via
435
+ * {@link deactivatePlugin}; at daemon shutdown the owners' `shutdown` hooks
436
+ * fire through the unified `runHook(HOOKS.SHUTDOWN)` pipeline.
427
437
  */
428
438
  const activatedPlugins: Array<{ name: string }> = [];
429
439
 
@@ -436,16 +446,12 @@ const activatedPlugins: Array<{ name: string }> = [];
436
446
  */
437
447
  const activatedNames = new Set<string>();
438
448
 
439
- const shutdownContext: ShutdownContext = {
440
- assistantVersion: APP_VERSION,
441
- };
442
-
443
449
  /**
444
450
  * Activate a single discovered plugin: pre-import its hooks, register its tools
445
451
  * into the global tool registry, and run its `init` hook. Idempotent — a plugin
446
452
  * already activated (or mid-activation) is skipped. Never throws; per-surface
447
453
  * failures are logged and the plugin still counts as activated so the shutdown
448
- * hook tears down whatever came up (mirrors boot semantics).
454
+ * teardown handles whatever came up (mirrors boot semantics).
449
455
  *
450
456
  * Called from `scanPlugins`, which runs both at boot and on every subsequent
451
457
  * scan — so a plugin whose files appear at runtime (installed via the CLI or
@@ -491,12 +497,16 @@ async function activatePlugin(
491
497
  }
492
498
 
493
499
  /**
494
- * Deactivate a plugin whose directory was removed or disabled at runtime:
495
- * unregister its tools and run its `shutdown` hook. Must run *before*
496
- * `evictPlugin` clears the hook cache, since the shutdown hook is read from it.
497
- * Idempotent a plugin that was never activated is a no-op.
500
+ * Deactivate a plugin whose directory was removed (`uninstall`) or disabled
501
+ * (`disable`) at runtime: unregister its tools and run its `shutdown` hook with
502
+ * the matching {@link ShutdownReason}. Must run *before* `evictPlugin` clears
503
+ * the hook cache, since the shutdown hook is read from it. Idempotent — a plugin
504
+ * that was never activated is a no-op.
498
505
  */
499
- async function deactivatePlugin(pluginName: string): Promise<void> {
506
+ async function deactivatePlugin(
507
+ pluginName: string,
508
+ reason: ShutdownReason,
509
+ ): Promise<void> {
500
510
  if (!activatedNames.has(pluginName)) return;
501
511
  activatedNames.delete(pluginName);
502
512
  const idx = activatedPlugins.findIndex((p) => p.name === pluginName);
@@ -513,7 +523,11 @@ async function deactivatePlugin(pluginName: string): Promise<void> {
513
523
  );
514
524
  }
515
525
 
516
- await runShutdownHook(pluginName, shutdownContext, "plugin-removed");
526
+ await runShutdownHook(
527
+ pluginName,
528
+ { assistantVersion: APP_VERSION, reason },
529
+ reason,
530
+ );
517
531
  }
518
532
 
519
533
  // ─── Boot population ─────────────────────────────────────────────────────────
@@ -521,8 +535,10 @@ async function deactivatePlugin(pluginName: string): Promise<void> {
521
535
  /**
522
536
  * Populate the caches at boot by scanning the plugins directory once (which
523
537
  * imports surfaces, registers tools, and runs `init` hooks via `activatePlugin`
524
- * inside `scanPlugins`), activating standalone workspace hooks, and installing
525
- * the process shutdown hook.
538
+ * inside `scanPlugins`) and activating standalone workspace hooks. At daemon
539
+ * shutdown these owners' `shutdown` hooks fire through the unified
540
+ * `runHook(HOOKS.SHUTDOWN)` pipeline; a runtime uninstall/disable tears a single
541
+ * owner down via {@link deactivatePlugin}.
526
542
  *
527
543
  * This replaces the old `loadExternalPlugin` → `registerPlugin` →
528
544
  * `bootstrapPlugins` path for user plugins. Instead of registering whole
@@ -555,33 +571,6 @@ export async function populateCacheAtBoot(
555
571
  await runInitHook(WORKSPACE_HOOKS_OWNER);
556
572
  activatedPlugins.push({ name: WORKSPACE_HOOKS_OWNER });
557
573
  }
558
-
559
- // Register a single shutdown hook that walks all activated owners in reverse
560
- // order, unregistering tools and running shutdown hooks. It reads the live
561
- // `activatedPlugins` array at teardown time, so plugins activated after boot
562
- // (runtime installs) are torn down too.
563
- registerShutdownHook("user-plugins", async (reason) => {
564
- for (let i = activatedPlugins.length - 1; i >= 0; i--) {
565
- const entry = activatedPlugins[i];
566
- if (entry === undefined) continue;
567
- const { name } = entry;
568
-
569
- // Unregister tools before running shutdown so onShutdown sees a
570
- // clean model-visible surface. (No-op for the workspace-hooks owner,
571
- // which registers no tools.)
572
- try {
573
- unregisterPluginTools(name);
574
- } catch (err) {
575
- log.warn(
576
- { err, plugin: name, reason },
577
- "user plugin tool unregister failed (continuing)",
578
- );
579
- }
580
-
581
- // Run the `shutdown` hook if present.
582
- await runShutdownHook(name, shutdownContext, reason);
583
- }
584
- });
585
574
  }
586
575
 
587
576
  // ─── Test hooks ──────────────────────────────────────────────────────────────
@@ -107,6 +107,12 @@ function cloneHookValue<T>(value: T, seen = new WeakMap<object, unknown>()): T {
107
107
  * successfully committed context. The final context after the chain settles is
108
108
  * returned.
109
109
  *
110
+ * When `initialCtx` carries a `conversationId`, it is passed to
111
+ * {@link getHooksFor}, which resolves the conversation's per-chat plugin scope
112
+ * (memory, then DB) and skips a hook whose contributing plugin is outside the
113
+ * effective set. Contexts without a `conversationId` impose no restriction —
114
+ * every globally-enabled plugin's hook runs.
115
+ *
110
116
  * @param name The hook identifier — pick one from {@link HOOKS}.
111
117
  * @param initialCtx Context the first hook receives.
112
118
  * @returns The final context after the chain settles. Same reference as
@@ -116,9 +122,10 @@ export async function runHook<TCtx>(
116
122
  name: HookName,
117
123
  initialCtx: TCtx,
118
124
  ): Promise<TCtx> {
125
+ const conversationId = extractConversationId(initialCtx);
119
126
  let hooks: HookFunction<TCtx>[];
120
127
  try {
121
- hooks = await getHooksFor<TCtx>(name);
128
+ hooks = await getHooksFor<TCtx>(name, { conversationId });
122
129
  } catch (err) {
123
130
  log.error(
124
131
  { err, hookName: name },
@@ -146,3 +153,10 @@ export async function runHook<TCtx>(
146
153
  }
147
154
  return active;
148
155
  }
156
+
157
+ /** The `conversationId` off a hook context, when it carries one as a string. */
158
+ function extractConversationId(ctx: unknown): string | undefined {
159
+ const conversationId = (ctx as { conversationId?: unknown } | null)
160
+ ?.conversationId;
161
+ return typeof conversationId === "string" ? conversationId : undefined;
162
+ }
@@ -48,13 +48,6 @@ export interface PluginManifest {
48
48
  * own version at load time.
49
49
  */
50
50
  version: string;
51
- /**
52
- * Assistant feature-flag keys that must all be enabled for this plugin to
53
- * activate. Checked by `bootstrapPlugins` via `isAssistantFeatureFlagEnabled`
54
- * — if any listed flag is disabled, the plugin is skipped entirely for the
55
- * boot (no `init()`, no tool/route/skill contributions, no shutdown hook).
56
- */
57
- requiresFlag?: string[];
58
51
  /**
59
52
  * Zod-compatible validator (or any parser-like object) for the plugin's
60
53
  * config block under `plugins.<name>`. Typed as `unknown` here — concrete
@@ -71,6 +64,7 @@ export type {
71
64
  HookFunction,
72
65
  InitContext,
73
66
  ShutdownContext,
67
+ ShutdownReason,
74
68
  } from "../plugin-api/types.js";
75
69
 
76
70
  // ─── Memory-graph result ─────────────────────────────────────────────────────
@@ -143,6 +137,13 @@ export interface TurnContext {
143
137
  readonly timestamp?: string;
144
138
  /** Human-readable interface label (e.g. "vellum", "telegram"). */
145
139
  readonly interfaceName?: string;
140
+ /**
141
+ * Client OS surface ("web" | "ios" | "macos"), reported independently of
142
+ * the transport interface. Rendered as the `client_os:` line so the model
143
+ * knows the platform even though the web/iOS/macOS apps share one `"web"`
144
+ * transport interface.
145
+ */
146
+ readonly clientOs?: string;
146
147
  /** Channel label gating response-discretion guidance in `<turn_context>`. */
147
148
  readonly channelName?: string;
148
149
  /**
@@ -335,13 +336,12 @@ export interface Injector {
335
336
  export type PluginRouteRegistration = SkillRoute;
336
337
 
337
338
  /**
338
- * A single background-job-handler contribution: a job `type` string paired with
339
- * the {@link JobHandler} that processes it. Plugins contribute these via the
340
- * `jobHandlers` field; bootstrap registers them into the global job-handler
341
- * registry, and the general job worker's registration entry
342
- * (`jobs/register-job-handlers.ts`) forwards the union into the worker dispatch
343
- * table. `type` must be globally unique across every plugin — dispatch is a
344
- * keyed lookup. See `plugins/job-handler-registry.ts`.
339
+ * A single background-job-handler entry: a job `type` string paired with the
340
+ * {@link JobHandler} that processes it. The memory plugin's handler list
341
+ * (`plugins/defaults/memory/job-handlers.ts`) is an array of these, registered
342
+ * directly into the worker's dispatch table from the plugin's `init` hook.
343
+ * `type` must be globally unique across every registered handler — dispatch is a
344
+ * keyed lookup.
345
345
  */
346
346
  export interface JobHandlerEntry {
347
347
  /** The job-queue type string this handler processes (globally unique). */
@@ -400,15 +400,6 @@ export interface Plugin {
400
400
  * injectors sharing an `order`. See `plugins/injector-registry.ts`.
401
401
  */
402
402
  injectors?: readonly Injector[];
403
- /**
404
- * Background-job handlers contributed to the general job worker. Bootstrap
405
- * registers these into the global job-handler registry before `init()` runs,
406
- * symmetric with `tools`/`routes`/`injectors`; the general worker's
407
- * registration entry (`jobs/register-job-handlers.ts`) forwards the union into
408
- * the worker dispatch table. Each `type` must be globally unique across every
409
- * plugin. See `plugins/job-handler-registry.ts`.
410
- */
411
- jobHandlers?: readonly JobHandlerEntry[];
412
403
  }
413
404
 
414
405
  // ─── Errors ──────────────────────────────────────────────────────────────────
@@ -8,7 +8,7 @@
8
8
 
9
9
  import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
10
  import { join } from "node:path";
11
- import { beforeEach, describe, expect, mock, test } from "bun:test";
11
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
12
12
 
13
13
  const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
14
14
 
@@ -125,50 +125,188 @@ describe("buildSystemPrompt — persona override", () => {
125
125
  });
126
126
  });
127
127
 
128
- describe("buildSystemPrompt — hasNoClient pin", () => {
129
- // Marker unique to the `{{^hasNoClient}}` branch of 05-access-preference:
130
- // host fallbacks only render when a client is connected.
131
- const WITH_CLIENT_MARKER = "`host_bash` with CLIs";
128
+ describe("buildSystemPrompt — default persona trust-class guardrail", () => {
129
+ // Marker strings from the bundled users/default.md template.
130
+ const GUARDRAIL = "Protect your guardian's privacy";
131
+ const TRUSTED_GREETING = "You're talking with a trusted contact";
132
+ const STRANGER_GREETING = "You're talking with someone you don't recognize";
133
+
134
+ const templatesDir = join(import.meta.dirname!, "..", "templates");
135
+ let priorAuthEnv: string | undefined;
132
136
 
133
137
  beforeEach(() => {
134
- mkdirSync(TEST_DIR, { recursive: true });
138
+ // Captured so the DISABLE_HTTP_AUTH regression test below can restore it.
139
+ priorAuthEnv = process.env.DISABLE_HTTP_AUTH;
140
+
141
+ mkdirSync(join(TEST_DIR, "users"), { recursive: true });
142
+ // Render the real shipped template, not a sentinel.
143
+ copyFileSync(
144
+ join(templatesDir, "users", "default.md"),
145
+ join(TEST_DIR, "users", "default.md"),
146
+ );
147
+ });
148
+
149
+ afterEach(() => {
150
+ if (priorAuthEnv === undefined) delete process.env.DISABLE_HTTP_AUTH;
151
+ else process.env.DISABLE_HTTP_AUTH = priorAuthEnv;
135
152
  });
136
153
 
137
- test("hasNoClient renders divergent access-preference text", () => {
138
- expect(buildSystemPrompt({ hasNoClient: false })).toContain(
139
- WITH_CLIENT_MARKER,
154
+ test("stranger (unknown) sees the guardrail and the stranger greeting", () => {
155
+ const result = buildSystemPrompt({
156
+ trustContext: { sourceChannel: "slack", trustClass: "unknown" },
157
+ });
158
+
159
+ expect(result).toContain(GUARDRAIL);
160
+ expect(result).toContain(STRANGER_GREETING);
161
+ expect(result).not.toContain(TRUSTED_GREETING);
162
+ });
163
+
164
+ test("trusted contact sees the guardrail and the trusted greeting", () => {
165
+ const result = buildSystemPrompt({
166
+ trustContext: { sourceChannel: "slack", trustClass: "trusted_contact" },
167
+ });
168
+
169
+ expect(result).toContain(GUARDRAIL);
170
+ expect(result).toContain(TRUSTED_GREETING);
171
+ expect(result).not.toContain(STRANGER_GREETING);
172
+ });
173
+
174
+ test("unverified contact is framed like a trusted contact", () => {
175
+ const result = buildSystemPrompt({
176
+ trustContext: {
177
+ sourceChannel: "slack",
178
+ trustClass: "unverified_contact",
179
+ },
180
+ });
181
+
182
+ expect(result).toContain(GUARDRAIL);
183
+ expect(result).toContain(TRUSTED_GREETING);
184
+ expect(result).not.toContain(STRANGER_GREETING);
185
+ });
186
+
187
+ test("guardian trust class gates the whole default persona off", () => {
188
+ // A guardian normally renders their own users/<slug>.md; if they ever fall
189
+ // back to default.md, every section is gated off and nothing leaks.
190
+ const result = buildSystemPrompt({
191
+ trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
192
+ });
193
+
194
+ expect(result).not.toContain(GUARDRAIL);
195
+ expect(result).not.toContain(TRUSTED_GREETING);
196
+ expect(result).not.toContain(STRANGER_GREETING);
197
+ });
198
+
199
+ test("renders for a non-guardian even when HTTP auth is disabled", () => {
200
+ // Platform-managed deployments run with DISABLE_HTTP_AUTH=true. A *present*
201
+ // trustContext must keep the actor's real class under that posture
202
+ // (resolveTrustClass only fail-safes *unresolved* actors), or the guardrail
203
+ // would silently switch off for the non-guardian channel actors it exists
204
+ // to protect.
205
+ process.env.DISABLE_HTTP_AUTH = "true";
206
+ const result = buildSystemPrompt({
207
+ trustContext: { sourceChannel: "slack", trustClass: "unknown" },
208
+ });
209
+
210
+ expect(result).toContain(GUARDRAIL);
211
+ expect(result).toContain(STRANGER_GREETING);
212
+ });
213
+
214
+ test("gates off for an unresolved local build when HTTP auth is disabled", () => {
215
+ // Initial-prompt warming, home generation, and btw sidechains build
216
+ // prompts with NO trustContext on behalf of the owner. In an auth-disabled
217
+ // (local / platform-managed) deployment that unresolved actor is the
218
+ // guardian, so the guardrail must not render into those guardian-facing
219
+ // prompts (fail-stranger would stonewall the owner about their own data).
220
+ process.env.DISABLE_HTTP_AUTH = "true";
221
+ const result = buildSystemPrompt({});
222
+
223
+ expect(result).not.toContain(GUARDRAIL);
224
+ expect(result).not.toContain(TRUSTED_GREETING);
225
+ expect(result).not.toContain(STRANGER_GREETING);
226
+ });
227
+
228
+ test("fails closed to the guardrail for an unresolved build when auth is enabled", () => {
229
+ // With auth enabled there is no basis to assume the unresolved actor is
230
+ // the guardian, so an unclassifiable build keeps the boundary.
231
+ delete process.env.DISABLE_HTTP_AUTH;
232
+ const result = buildSystemPrompt({});
233
+
234
+ expect(result).toContain(GUARDRAIL);
235
+ expect(result).toContain(STRANGER_GREETING);
236
+ });
237
+
238
+ test("boundary survives a per-contact persona file replacing default.md", () => {
239
+ // Every contact already has a `users/<slug>.md` filename reserved on
240
+ // their contact record; the moment that file exists with content it
241
+ // replaces `default.md` in the `10-user-persona` section. The privacy
242
+ // boundary must render regardless — it lives in the always-on
243
+ // `10a-non-guardian-boundary` section, not in the fallback file.
244
+ writeFileSync(
245
+ join(TEST_DIR, "users", "jane.md"),
246
+ "# Jane\n\nJane likes concise answers.\n",
247
+ "utf-8",
140
248
  );
141
- expect(buildSystemPrompt({ hasNoClient: true })).not.toContain(
142
- WITH_CLIENT_MARKER,
249
+ const result = buildSystemPrompt({
250
+ trustContext: { sourceChannel: "slack", trustClass: "trusted_contact" },
251
+ personaOverride: { userSlug: "jane" },
252
+ });
253
+
254
+ // The contact's own persona replaced the default greetings...
255
+ expect(result).toContain("Jane likes concise answers.");
256
+ expect(result).not.toContain(TRUSTED_GREETING);
257
+ // ...but the boundary still renders.
258
+ expect(result).toContain(GUARDRAIL);
259
+ });
260
+
261
+ test("boundary is omitted for a guardian rendering their own persona file", () => {
262
+ writeFileSync(
263
+ join(TEST_DIR, "users", "owner.md"),
264
+ "# Owner\n\nThe guardian's own profile.\n",
265
+ "utf-8",
143
266
  );
267
+ const result = buildSystemPrompt({
268
+ trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
269
+ personaOverride: { userSlug: "owner" },
270
+ });
271
+
272
+ expect(result).toContain("The guardian's own profile.");
273
+ expect(result).not.toContain(GUARDRAIL);
274
+ });
275
+
276
+ test("never leaks literal mustache tags or comment lines", () => {
277
+ for (const trustClass of [
278
+ "unknown",
279
+ "trusted_contact",
280
+ "unverified_contact",
281
+ "guardian",
282
+ ] as const) {
283
+ const result = buildSystemPrompt({
284
+ trustContext: { sourceChannel: "slack", trustClass },
285
+ });
286
+ expect(result).not.toContain("{{");
287
+ expect(result).not.toContain("}}");
288
+ expect(result).not.toContain("Lines starting with");
289
+ }
290
+ });
291
+ });
292
+
293
+ describe("buildSystemPrompt — hasNoClient no longer affects the prompt", () => {
294
+ beforeEach(() => {
295
+ mkdirSync(TEST_DIR, { recursive: true });
144
296
  });
145
297
 
146
- test("personaOverride.hasNoClient pins the flag over the conversation-derived option", () => {
147
- // Fork-retrospective case: the fork is hydrated clientless
148
- // (hasNoClient: true) but pins the source's live-turn value (false) so
149
- // the prompt byte-matches the source's cached prefix.
298
+ // No system-prompt section branches on hasNoClient, so neither the flag nor
299
+ // the SystemPromptPersonaOverride.hasNoClient pin changes prompt output.
300
+ // Guards against a future section re-coupling to the flag.
301
+ test("output is identical regardless of the flag or its pin", () => {
302
+ const base = buildSystemPrompt({ hasNoClient: false });
303
+ expect(buildSystemPrompt({ hasNoClient: true })).toBe(base);
150
304
  expect(
151
305
  buildSystemPrompt({
152
306
  hasNoClient: true,
153
307
  personaOverride: { hasNoClient: false },
154
308
  }),
155
- ).toContain(WITH_CLIENT_MARKER);
156
- // And the pin wins in the other direction too.
157
- expect(
158
- buildSystemPrompt({
159
- hasNoClient: false,
160
- personaOverride: { hasNoClient: true },
161
- }),
162
- ).not.toContain(WITH_CLIENT_MARKER);
163
- });
164
-
165
- test("a personaOverride without the pin leaves the conversation-derived flag untouched", () => {
166
- expect(
167
- buildSystemPrompt({ hasNoClient: true, personaOverride: {} }),
168
- ).not.toContain(WITH_CLIENT_MARKER);
169
- expect(
170
- buildSystemPrompt({ hasNoClient: false, personaOverride: {} }),
171
- ).toContain(WITH_CLIENT_MARKER);
309
+ ).toBe(base);
172
310
  });
173
311
  });
174
312
 
@@ -91,7 +91,9 @@ function resolveGuardianUserFile(trustContext: TrustContext): string | null {
91
91
  }
92
92
  }
93
93
  const guardian = peekGuardianForChannel(trustContext.sourceChannel);
94
- return guardian ? (guardianDeliveryUserFile(guardian) ?? "guardian.md") : null;
94
+ return guardian
95
+ ? (guardianDeliveryUserFile(guardian) ?? "guardian.md")
96
+ : null;
95
97
  }
96
98
 
97
99
  /**
@@ -103,10 +105,7 @@ function resolveGuardianUserFile(trustContext: TrustContext): string | null {
103
105
  function guardianDeliveryUserFile(
104
106
  guardian: GuardianDelivery,
105
107
  ): string | undefined {
106
- const contact = findContactByAddress(
107
- guardian.channelType,
108
- guardian.address,
109
- );
108
+ const contact = findContactByAddress(guardian.channelType, guardian.address);
110
109
  return contact?.userFile ?? undefined;
111
110
  }
112
111
 
@@ -147,13 +146,18 @@ function resolveUserFilename(
147
146
  trustContext.sourceChannel,
148
147
  trustContext.requesterExternalUserId,
149
148
  );
150
- if (contactWithChannels) {
151
- filename = contactWithChannels.userFile ?? null;
149
+ if (contactWithChannels?.userFile) {
150
+ filename = contactWithChannels.userFile;
152
151
  } else if (trustContext.trustClass === "guardian") {
153
152
  // Managed desktop: the JWT principal ID used as requesterExternalUserId
154
153
  // may differ from the contact channel's address (they are separate
155
- // identity concepts). Read the guardian's user file keyed by the
156
- // verdict-bound guardian identity.
154
+ // identity concepts) OR the guardian's contact row exists but carries
155
+ // no explicit userFile yet (the normal post-hatch state, since the
156
+ // guardian contact is created with a null userFile and onboarding
157
+ // writes the file on disk, not the column). Either way, read the
158
+ // guardian's user file keyed by the verdict-bound guardian identity so
159
+ // the onboarding profile (written to guardian.md) loads instead of
160
+ // falling through to users/default.md.
157
161
  filename = resolveGuardianUserFile(trustContext);
158
162
  }
159
163
  } else if (trustContext.trustClass === "guardian") {
@@ -10,8 +10,12 @@ import { join } from "node:path";
10
10
 
11
11
  import { getIsContainerized } from "../config/env-registry.js";
12
12
  import type { ChannelCapabilities } from "../daemon/conversation-runtime-assembly.js";
13
- import type { TrustContext } from "../daemon/trust-context.js";
13
+ import {
14
+ resolveTrustClass,
15
+ type TrustContext,
16
+ } from "../daemon/trust-context.js";
14
17
  import { markActivationSession } from "../plugins/defaults/memory/activation-session-store.js";
18
+ import { derivePersonaTrustFlags } from "../runtime/trust-class.js";
15
19
  import { ACTIVATION_RAIL_BOOTSTRAP_TEMPLATE } from "../telemetry/activation-funnel.js";
16
20
  import type { OnboardingContext } from "../types/onboarding-context.js";
17
21
  import { resolveBundledDir } from "../util/bundled-asset.js";
@@ -319,14 +323,12 @@ export interface SystemPromptPersonaOverride {
319
323
  /**
320
324
  * Pins the `hasNoClient` flag for the prompt build, taking precedence over
321
325
  * the top-level `BuildSystemPromptOptions.hasNoClient` (which mirrors the
322
- * conversation's live client state). The `05-access-preference` section
323
- * renders different text under the flag early in the prompt, so a
324
- * mismatch breaks byte-parity with a cached prefix even when persona and
325
- * profile match. Used by fork-based memory retrospectives: the fork is
326
- * hydrated clientless (`hasNoClient = true`) while the source's live turns
327
- * ran under the source's own client state (`false` for interactive
328
- * interfaces, `true` for channel-routed sources) — the pin carries that
329
- * live-turn value.
326
+ * conversation's live client state). No system-prompt section branches on
327
+ * `hasNoClient`, so this pin does not affect prompt output; it is retained
328
+ * so fork-based memory retrospectives can thread the source conversation's
329
+ * live-turn value (`false` for interactive interfaces, `true` for
330
+ * channel-routed sources) through the build without depending on the fork's
331
+ * clientless hydration default.
330
332
  */
331
333
  hasNoClient?: boolean;
332
334
  }
@@ -395,6 +397,21 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
395
397
  const hasNoClient =
396
398
  options?.personaOverride?.hasNoClient ?? options?.hasNoClient;
397
399
 
400
+ // Trust flags for the current actor, lifted onto the render context so
401
+ // persona sections — notably `users/default.md`, the persona rendered for
402
+ // non-guardian actors — can gate privacy guardrails on who is being spoken
403
+ // to. The class is resolved through `resolveTrustClass` first: a *present*
404
+ // trustContext always keeps the actor's real class (a resolved non-guardian
405
+ // channel actor is never elevated, even under DISABLE_HTTP_AUTH), while an
406
+ // *absent* one follows the actor-resolution contract — guardian for
407
+ // local/native builds in an auth-disabled deployment (initial-prompt
408
+ // warming, home generation, and btw sidechains build prompts with no
409
+ // trustContext for the owner), unknown otherwise so an unclassifiable turn
410
+ // still fails closed to the guardrail. The flag grouping itself lives on
411
+ // {@link derivePersonaTrustFlags}.
412
+ const { trustClass, isGuardian, isTrustedContact, isStranger } =
413
+ derivePersonaTrustFlags(resolveTrustClass(options?.trustContext));
414
+
398
415
  // Section render context. Workspace section frontmatter `enabled:`
399
416
  // predicates, `{{key}}` / `{{#flag}}...{{/flag}}` body interpolation,
400
417
  // and `{{key}}` paths inside `workspacePath` all resolve against this
@@ -411,6 +428,10 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
411
428
  workspaceDir: getWorkspaceDir(),
412
429
  userSlug,
413
430
  channelSlug,
431
+ trustClass,
432
+ isGuardian,
433
+ isTrustedContact,
434
+ isStranger,
414
435
  };
415
436
 
416
437
  // Every system-prompt block flows through the bundled section