@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
@@ -0,0 +1,437 @@
1
+ /**
2
+ * Per-statement duration logging for every `bun:sqlite` query — Drizzle and raw.
3
+ *
4
+ * `bun:sqlite` executes synchronously on the daemon's single event-loop thread,
5
+ * so any statement that runs long — a large history scan, a memory query, or a
6
+ * write that blocks on the WAL write-lock (`busy_timeout` makes a contended
7
+ * writer *wait*, spinning the loop for up to {@link SQLITE_BUSY_TIMEOUT_MS}) —
8
+ * freezes every other handler (SSE, HTTP, health) for its full duration. The
9
+ * event-loop watchdog can see *that* a freeze happened but not *what* ran, and
10
+ * the section-level {@link ./slow-sync-log timeSyncSection} only covers the few
11
+ * call sites that opt in — notably not the Drizzle ORM hot writers.
12
+ *
13
+ * {@link wrapSqliteForSlowQueryLogging} closes that gap by wrapping the three
14
+ * statement-execution entry points on a `Database` — `.query()`, `.prepare()`,
15
+ * and the `.run()` shortcut — so that every execution (`.run()/.get()/.all()/
16
+ * .values()`) is timed with `performance.now()`. Executions slower than
17
+ * {@link SLOW_QUERY_THRESHOLD_MS} are logged at WARN with the offending SQL,
18
+ * naming the specific query behind a freeze regardless of whether it came from
19
+ * Drizzle or {@link ./raw-query}.
20
+ *
21
+ * Attribution: raw-query callers attach a curated `.label()` (e.g.
22
+ * `"schedule:claimDue"`). Drizzle's fluent API has no chokepoint to label, so
23
+ * for any query without an explicit label the reporter derives a `caller` from
24
+ * the stack — `path:function:line` of the application frame that issued it —
25
+ * captured only on the slow path. Between the two, every slow query is
26
+ * attributable to its call site with no per-query annotation of Drizzle code.
27
+ *
28
+ * The same per-statement chokepoint also surfaces *failed* executions: when a
29
+ * statement throws, the error is handed to {@link observeSqliteStatementError}
30
+ * before it propagates unchanged. This is how the SQLite corruption watchdog
31
+ * notices `SQLITE_CORRUPT` / `SQLITE_NOTADB` on any query or write — read or
32
+ * write, Drizzle or raw — the moment the workload hits the damaged page.
33
+ *
34
+ * This is pure instrumentation: return values, parameter binding, transactions,
35
+ * savepoints, and error propagation are all preserved exactly. The fast path
36
+ * adds only a `performance.now()` pair and a numeric compare — no allocation,
37
+ * SQL slicing, or observer call happens unless the statement is slow or throws.
38
+ */
39
+
40
+ import { basename } from "node:path";
41
+ import type { Database, Statement } from "bun:sqlite";
42
+
43
+ import { observeSqliteStatementError } from "../daemon/sqlite-corruption-watchdog.js";
44
+ import { getLogger } from "../util/logger.js";
45
+
46
+ const log = getLogger("slow-query");
47
+
48
+ // Parsed once at module load; falls back below for any non-positive or
49
+ // unparseable value.
50
+ const configuredThresholdMs = Number(
51
+ process.env.VELLUM_SLOW_QUERY_THRESHOLD_MS,
52
+ );
53
+
54
+ /**
55
+ * Statement executions that block the event loop at least this long are logged.
56
+ * Deliberately conservative (300ms) so it names sub-watchdog contributors
57
+ * without logging every fast query. Env-overridable for tuning on a busy host
58
+ * without a rebuild.
59
+ */
60
+ export const SLOW_QUERY_THRESHOLD_MS =
61
+ Number.isFinite(configuredThresholdMs) && configuredThresholdMs > 0
62
+ ? configuredThresholdMs
63
+ : 300;
64
+
65
+ /** Max SQL characters retained in the log preview. */
66
+ const SQL_PREVIEW_MAX = 120;
67
+
68
+ /** The statement methods that actually execute SQL and can block. */
69
+ const TIMED_METHODS = new Set(["run", "get", "all", "values"]);
70
+
71
+ /** A slow statement execution, as handed to {@link reportSlowQuery}. */
72
+ export interface SlowQueryEvent {
73
+ durationMs: number;
74
+ /** SQL preview (first {@link SQL_PREVIEW_MAX} chars). */
75
+ sql: string;
76
+ /** Number of rows returned, when the execution produced an array result. */
77
+ rowCount?: number;
78
+ /** Caller-supplied attribution tag, when the query was issued via `.label()`. */
79
+ label?: string;
80
+ /**
81
+ * Auto-derived call site (`path:function:line`) for queries with no explicit
82
+ * `.label()` — notably every Drizzle query, which has no chokepoint to attach
83
+ * a label to. Captured from the stack only on the slow path.
84
+ */
85
+ caller?: string;
86
+ }
87
+
88
+ /** This instrumentation module — never the query's call site. */
89
+ const SELF_MODULE = "slow-query-log.ts";
90
+
91
+ /**
92
+ * Marks the assistant package's own source. In local-runtime installs the CLI
93
+ * runs the daemon from `<installDir>/node_modules/@vellumai/assistant/src/…`, so
94
+ * the assistant's own frames also contain `node_modules` — they must NOT be
95
+ * treated as third-party dependency frames when deriving the caller.
96
+ */
97
+ const ASSISTANT_SRC_MARKER = "@vellumai/assistant/src/";
98
+
99
+ /**
100
+ * True for stack frames that are runtime/ORM/instrumentation plumbing rather
101
+ * than the application code that issued the query. Third-party dependency frames
102
+ * (Drizzle et al.) live under `node_modules/` or Bun's global install cache
103
+ * (`.bun/install/cache/drizzle-orm@x.y.z/…`) and are skipped — but the
104
+ * assistant's own packaged `src/` frames, which also live under `node_modules`,
105
+ * are preserved.
106
+ */
107
+ function isPlumbingFrame(line: string): boolean {
108
+ // Runtime internals: `node:*` / `bun:*` modules and Bun's `native:` frames
109
+ // (moduleEvaluation, processTicksAndRejections, …).
110
+ if (
111
+ line.includes("node:") ||
112
+ line.includes("bun:") ||
113
+ line.includes("native:")
114
+ ) {
115
+ return true;
116
+ }
117
+ if (line.includes(SELF_MODULE)) return true;
118
+ const isDependency =
119
+ line.includes("node_modules/") || line.includes(".bun/install/cache/");
120
+ return isDependency && !line.includes(ASSISTANT_SRC_MARKER);
121
+ }
122
+
123
+ /** `src/`-relative path, or bare basename when the frame is outside `src/`. */
124
+ function shortenStackFile(file: string): string {
125
+ const idx = file.lastIndexOf("/src/");
126
+ if (idx >= 0) return file.slice(idx + "/src/".length);
127
+ return file.split("/").pop() ?? file;
128
+ }
129
+
130
+ /**
131
+ * Best-effort attribution for a query with no explicit label: the first stack
132
+ * frame outside this module, dependencies, and the runtime — i.e. the
133
+ * application code that issued the query. Returns e.g.
134
+ * `persistence/conversation-crud.ts:insertMessageCore:474`. Only called on the
135
+ * slow path (a query already past the threshold), so the `Error().stack` cost is
136
+ * incurred rarely. Accepts an explicit `stack` for testing.
137
+ *
138
+ * @internal exported only for unit tests.
139
+ */
140
+ export function callerFromStack(
141
+ stack: string | undefined = new Error().stack,
142
+ ): string | undefined {
143
+ if (!stack) return undefined;
144
+ const lines = stack.split("\n");
145
+ for (let i = 1; i < lines.length; i++) {
146
+ const line = lines[i];
147
+ if (!line.includes("at ")) continue;
148
+ if (isPlumbingFrame(line)) continue;
149
+ // Bun renders frames as `at fn (file:line:col)`, `at file:line:col`, or
150
+ // (for some optimized frames) `at file:line` with no function or column.
151
+ const withFn = line.match(
152
+ /at (?:async )?([^\s(]+) \((.+?):(\d+)(?::\d+)?\)/,
153
+ );
154
+ if (withFn) {
155
+ return `${shortenStackFile(withFn[2])}:${withFn[1]}:${withFn[3]}`;
156
+ }
157
+ const noFn = line.match(/at (?:async )?(.+?):(\d+)(?::\d+)?$/);
158
+ if (noFn) {
159
+ return `${shortenStackFile(noFn[1])}:${noFn[2]}`;
160
+ }
161
+ }
162
+ return undefined;
163
+ }
164
+
165
+ /** Log a slow statement execution at WARN with its SQL and duration. */
166
+ export function reportSlowQuery(event: SlowQueryEvent): void {
167
+ log.warn(event, "Slow SQLite query blocked the event loop");
168
+ }
169
+
170
+ /** Context handed to {@link observeSqliteStatementError} for a failed execution. */
171
+ export interface StatementErrorContext {
172
+ /** SQL preview (first {@link SQL_PREVIEW_MAX} chars) of the failing statement. */
173
+ sql: string;
174
+ /**
175
+ * The database file's basename (e.g. `"assistant.db"` / `"assistant-logs.db"`),
176
+ * derived from the `Database`'s own `filename`. Always set by the wrapper;
177
+ * optional only for direct callers (tests) that construct a context by hand.
178
+ */
179
+ database?: string;
180
+ /** Caller-supplied `.label()` attribution tag, when present. */
181
+ label?: string;
182
+ }
183
+
184
+ /** Injectable seams so the wrapper is unit-testable with a fake clock/sink. */
185
+ export interface SlowQueryWatcherOptions {
186
+ thresholdMs?: number;
187
+ now?: () => number;
188
+ onSlowQuery?: (event: SlowQueryEvent) => void;
189
+ }
190
+
191
+ /** Fluent handle returned by {@link Database.label}; tags any slow-query log. */
192
+ export interface LabeledQueries {
193
+ query(sql: string, ...rest: unknown[]): Statement;
194
+ prepare(sql: string, ...rest: unknown[]): Statement;
195
+ run(sql: string, ...params: unknown[]): ReturnType<Database["run"]>;
196
+ }
197
+
198
+ declare module "bun:sqlite" {
199
+ interface Database {
200
+ /**
201
+ * Return `query`/`prepare`/`run` bound to `label`, so any slow-query log
202
+ * emitted for statements created through the returned handle carries it —
203
+ * e.g. `getSqlite().label("schedule::claimDue").query(sql).run(...)`.
204
+ * Only present on connections wrapped by
205
+ * {@link wrapSqliteForSlowQueryLogging} (all accessor connections).
206
+ */
207
+ label(label: string): LabeledQueries;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Wrap a `bun:sqlite` {@link Database} in place so every statement execution is
213
+ * timed and the slow ones are logged. The Drizzle path (`.prepare(sql)` then
214
+ * `.run()/.all()/.values()`), {@link ./raw-query} (`.query(sql).get()/.all()/
215
+ * .run()`), and the `Database.run(sql, params)` shortcut (used by migration
216
+ * code via `getSqliteFrom(db).run(...)`) all route through the entry points
217
+ * wrapped here, so a single call covers every path.
218
+ *
219
+ * Returns the same instance (mutated), so callers can wrap inline at
220
+ * construction. `.exec()` — batch DDL, PRAGMAs, and transaction `BEGIN`/`COMMIT`
221
+ * — is intentionally left unwrapped: it takes no bindings and isn't a
222
+ * statement-execution path. `options` exists only for tests.
223
+ */
224
+ export function wrapSqliteForSlowQueryLogging(
225
+ sqlite: Database,
226
+ options: SlowQueryWatcherOptions = {},
227
+ ): Database {
228
+ const thresholdMs = options.thresholdMs ?? SLOW_QUERY_THRESHOLD_MS;
229
+ const now = options.now ?? (() => performance.now());
230
+ const onSlowQuery = options.onSlowQuery ?? reportSlowQuery;
231
+ // Reuse the path this connection was opened with (`new Database(path)`) rather
232
+ // than a hand-passed key — its basename names the damaged file.
233
+ const database = basename(sqlite.filename);
234
+
235
+ // Slow path only (a statement threw). Surface it to the corruption watchdog;
236
+ // its failure must never escape into the query path.
237
+ const notifyError = (
238
+ err: unknown,
239
+ sql: string,
240
+ label: string | undefined,
241
+ ): void => {
242
+ try {
243
+ observeSqliteStatementError(err, {
244
+ sql: sql.slice(0, SQL_PREVIEW_MAX),
245
+ database,
246
+ ...(label === undefined ? {} : { label }),
247
+ });
248
+ } catch {
249
+ // The observer must never break the query path.
250
+ }
251
+ };
252
+
253
+ // Re-entrancy guard. `bun:sqlite` implements `db.query(sql).run()` by
254
+ // delegating through the (also-wrapped) `db.prepare(sql)`, so the outer
255
+ // `.run()` would time the inner `.run()` a second time. Because `bun:sqlite`
256
+ // is fully synchronous, a per-connection flag safely collapses that nesting:
257
+ // only the outermost execution is timed (its duration already includes any
258
+ // inner re-prepare), inner ones pass straight through. Not shared across
259
+ // connections so tests stay isolated.
260
+ let timing = false;
261
+
262
+ const emit = (
263
+ sql: string,
264
+ label: string | undefined,
265
+ durationMs: number,
266
+ result: unknown,
267
+ ): void => {
268
+ // Only ever called on the slow path, so building the payload — including the
269
+ // stack walk for unlabeled (Drizzle) queries — is fine.
270
+ const caller = label === undefined ? callerFromStack() : undefined;
271
+ onSlowQuery({
272
+ durationMs,
273
+ sql: sql.slice(0, SQL_PREVIEW_MAX),
274
+ ...(Array.isArray(result) ? { rowCount: result.length } : {}),
275
+ ...(label === undefined ? {} : { label }),
276
+ ...(caller === undefined ? {} : { caller }),
277
+ });
278
+ };
279
+
280
+ // Statement proxies are cached against their native statement so repeated
281
+ // executions of a `.query()`-cached prepared statement reuse one proxy and its
282
+ // timed closures — nothing allocates on the hot path. The cache is keyed by
283
+ // label as well as statement so a native statement reused under different
284
+ // labels gets one proxy per label (no label leaks across callers), and the
285
+ // labeled hot path (e.g. the raw-query helpers) stays allocation-free too.
286
+ const UNLABELED = "";
287
+ const proxiesByStmt = new WeakMap<Statement, Map<string, Statement>>();
288
+
289
+ const wrapStatement = (
290
+ stmt: Statement,
291
+ sql: string,
292
+ label: string | undefined,
293
+ ): Statement => {
294
+ const cacheKey = label ?? UNLABELED;
295
+ let byLabel = proxiesByStmt.get(stmt);
296
+ if (byLabel) {
297
+ const cached = byLabel.get(cacheKey);
298
+ if (cached) return cached;
299
+ } else {
300
+ byLabel = new Map();
301
+ proxiesByStmt.set(stmt, byLabel);
302
+ }
303
+
304
+ const timed = new Map<string, (...args: unknown[]) => unknown>();
305
+ const proxy = new Proxy(stmt, {
306
+ get(target, prop) {
307
+ if (typeof prop === "string" && TIMED_METHODS.has(prop)) {
308
+ let fn = timed.get(prop);
309
+ if (!fn) {
310
+ const call = (
311
+ target as unknown as Record<string, (...a: unknown[]) => unknown>
312
+ )[prop].bind(target);
313
+ fn = (...args: unknown[]): unknown => {
314
+ if (timing) return call(...args); // inner re-entry: no timing
315
+ timing = true;
316
+ const start = now();
317
+ let result: unknown;
318
+ try {
319
+ result = call(...args);
320
+ return result;
321
+ } catch (err) {
322
+ // The failed op still blocked and still needs timing (below);
323
+ // surface it to the error observer before it propagates
324
+ // unchanged. Re-entrant inner calls short-circuit above
325
+ // (`if (timing)`), so a nested throw is observed once, here.
326
+ notifyError(err, sql, label);
327
+ throw err;
328
+ } finally {
329
+ timing = false;
330
+ // Fast path: one subtraction + one compare. Nothing is
331
+ // allocated or sliced unless we cross the threshold.
332
+ const durationMs = now() - start;
333
+ if (durationMs >= thresholdMs) {
334
+ emit(sql, label, durationMs, result);
335
+ }
336
+ }
337
+ };
338
+ timed.set(prop, fn);
339
+ }
340
+ return fn;
341
+ }
342
+ // Everything else (columnNames, paramsCount, finalize, toString, …)
343
+ // passes straight through, bound to the real statement so native
344
+ // methods keep their `this`.
345
+ const value = Reflect.get(target, prop, target);
346
+ return typeof value === "function"
347
+ ? (value as (...a: unknown[]) => unknown).bind(target)
348
+ : value;
349
+ },
350
+ });
351
+
352
+ byLabel.set(cacheKey, proxy);
353
+ return proxy;
354
+ };
355
+
356
+ const originalQuery = sqlite.query.bind(sqlite);
357
+ const originalPrepare = sqlite.prepare.bind(sqlite);
358
+ const originalRun = sqlite.run.bind(sqlite);
359
+
360
+ // `.query()` / `.prepare()` compile the SQL, which reads the schema — on a
361
+ // file with a corrupt header ("file is not a database") that read throws
362
+ // *here*, before any execution method runs, so the error is surfaced to the
363
+ // observer at creation time too. (Malformed-*page* corruption instead
364
+ // surfaces at step time and is caught in the execution closures above.) A
365
+ // `query()` that delegates through the wrapped `prepare()` may notify twice;
366
+ // the observer's per-database debounce collapses that to one report.
367
+ const createStatement = (
368
+ create: (...a: unknown[]) => Statement,
369
+ sql: string,
370
+ label: string | undefined,
371
+ rest: unknown[],
372
+ ): Statement => {
373
+ let stmt: Statement;
374
+ try {
375
+ stmt = create(sql, ...rest);
376
+ } catch (err) {
377
+ notifyError(err, sql, label);
378
+ throw err;
379
+ }
380
+ return wrapStatement(stmt, sql, label);
381
+ };
382
+
383
+ const makeQuery =
384
+ (label: string | undefined) =>
385
+ (sql: string, ...rest: unknown[]): Statement =>
386
+ createStatement(
387
+ originalQuery as (...a: unknown[]) => Statement,
388
+ sql,
389
+ label,
390
+ rest,
391
+ );
392
+
393
+ const makePrepare =
394
+ (label: string | undefined) =>
395
+ (sql: string, ...rest: unknown[]): Statement =>
396
+ createStatement(
397
+ originalPrepare as (...a: unknown[]) => Statement,
398
+ sql,
399
+ label,
400
+ rest,
401
+ );
402
+
403
+ // `Database.run(sql, ...params)` is a native shortcut that does not route
404
+ // through `.prepare()`, so it is timed directly here. `sql` is an argument
405
+ // (not fixed per closure), so one closure per label reads it from the call.
406
+ const makeRun =
407
+ (label: string | undefined) =>
408
+ (sql: string, ...params: unknown[]): unknown => {
409
+ const call = originalRun as (...a: unknown[]) => unknown;
410
+ if (timing) return call(sql, ...params);
411
+ timing = true;
412
+ const start = now();
413
+ let result: unknown;
414
+ try {
415
+ result = call(sql, ...params);
416
+ return result;
417
+ } catch (err) {
418
+ notifyError(err, sql, label);
419
+ throw err;
420
+ } finally {
421
+ timing = false;
422
+ const durationMs = now() - start;
423
+ if (durationMs >= thresholdMs) emit(sql, label, durationMs, result);
424
+ }
425
+ };
426
+
427
+ sqlite.query = makeQuery(undefined) as typeof sqlite.query;
428
+ sqlite.prepare = makePrepare(undefined) as typeof sqlite.prepare;
429
+ sqlite.run = makeRun(undefined) as typeof sqlite.run;
430
+ sqlite.label = (label: string): LabeledQueries => ({
431
+ query: makeQuery(label),
432
+ prepare: makePrepare(label),
433
+ run: makeRun(label) as LabeledQueries["run"],
434
+ });
435
+
436
+ return sqlite;
437
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Attribution for event-loop stalls caused by synchronous SQLite work.
3
+ *
4
+ * `bun:sqlite` runs on the daemon's single event-loop thread, so any slow
5
+ * statement — a large conversation-history load, a memory scan, a WAL
6
+ * checkpoint folding a multi-GB WAL — freezes every other handler (SSE,
7
+ * HTTP, health) for its full duration. The event-loop watchdog
8
+ * (`daemon/event-loop-watchdog.ts`) detects *that* a freeze happened but,
9
+ * being single-threaded itself, cannot capture *what* was running: by the
10
+ * time its tick fires the blocking call has returned and its stack is gone.
11
+ *
12
+ * This module fills that gap two ways:
13
+ *
14
+ * 1. **Threshold reports** — wrap a known-heavy synchronous section with
15
+ * {@link timeSyncSection} (or call {@link reportSlowSync} with a measured
16
+ * duration); when it blocks past {@link SLOW_SYNC_THRESHOLD_MS} it logs a
17
+ * structured warning naming the call site and records a `watchdog`
18
+ * telemetry event. The threshold is deliberately below the watchdog's own
19
+ * 5s floor so sub-watchdog contributors are still named. Override with
20
+ * `VELLUM_SLOW_SYNC_THRESHOLD_MS`.
21
+ *
22
+ * 2. **Section trail** — a small in-memory ring of the most recently entered
23
+ * instrumented sections ({@link markSection} / {@link traceAsyncSection};
24
+ * {@link timeSyncSection} marks automatically). The event-loop watchdog
25
+ * attaches {@link getSectionTrail} to every freeze report: because the
26
+ * loop is single-threaded, the newest mark still un-ended at block start
27
+ * (entries older than `blockedMs`) names — or tightly brackets — the code
28
+ * that froze, even when the block sits in a section nobody thought to
29
+ * time. Marks record only static labels, never content.
30
+ */
31
+
32
+ import { getLogger } from "../util/logger.js";
33
+
34
+ const log = getLogger("slow-sync");
35
+
36
+ /**
37
+ * Synchronous sections that block the event loop at least this long are
38
+ * reported. Env-overridable for tuning attribution verbosity on a busy
39
+ * host without a rebuild; falls back to 1000ms for any non-positive or
40
+ * unparseable value.
41
+ */
42
+ export const SLOW_SYNC_THRESHOLD_MS = ((): number => {
43
+ const raw = Number(process.env.VELLUM_SLOW_SYNC_THRESHOLD_MS);
44
+ return Number.isFinite(raw) && raw > 0 ? raw : 1000;
45
+ })();
46
+
47
+ /**
48
+ * `check_name` for slow-sync telemetry events. Stable so downstream
49
+ * grouping stays consistent; keep it in sync with any admin query.
50
+ */
51
+ export const SLOW_SYNC_CHECK_NAME = "slow_sync_operation";
52
+
53
+ /** One recorded section entry: a static label plus monotonic start/end stamps. */
54
+ export interface SectionMark {
55
+ label: string;
56
+ startedAt: number;
57
+ endedAt?: number;
58
+ }
59
+
60
+ /**
61
+ * How many section marks the trail retains. Sized so the sections between a
62
+ * container mark (e.g. an agent-event dispatch) and a freeze — typically a
63
+ * handful of nested query marks — don't evict the container before the
64
+ * watchdog reads the trail.
65
+ */
66
+ const SECTION_TRAIL_CAPACITY = 16;
67
+
68
+ const sectionTrail: SectionMark[] = [];
69
+
70
+ /**
71
+ * Record that an instrumented section is starting. Returns the mark so the
72
+ * caller can stamp its completion with {@link endSection}. Cheap enough for
73
+ * hot paths: one small allocation and a bounded-array push.
74
+ */
75
+ export function markSection(label: string): SectionMark {
76
+ const mark: SectionMark = { label, startedAt: performance.now() };
77
+ sectionTrail.push(mark);
78
+ if (sectionTrail.length > SECTION_TRAIL_CAPACITY) {
79
+ sectionTrail.shift();
80
+ }
81
+ return mark;
82
+ }
83
+
84
+ /** Stamp a mark's completion; returns the section's elapsed milliseconds. */
85
+ export function endSection(mark: SectionMark): number {
86
+ mark.endedAt = performance.now();
87
+ return mark.endedAt - mark.startedAt;
88
+ }
89
+
90
+ /**
91
+ * Trail a section that spans an `await` (a hook chain, a provider call). The
92
+ * mark stays open for the span's full wall time — sections entered by work
93
+ * interleaving on the loop during the await appear as newer trail entries, so
94
+ * a freeze inside the span is still bracketed correctly. Wall time is NOT
95
+ * reported as a slow sync: an awaited span legitimately spends most of it
96
+ * off-loop.
97
+ */
98
+ export async function traceAsyncSection<T>(
99
+ label: string,
100
+ fn: () => Promise<T>,
101
+ ): Promise<T> {
102
+ const mark = markSection(label);
103
+ try {
104
+ return await fn();
105
+ } finally {
106
+ endSection(mark);
107
+ }
108
+ }
109
+
110
+ /** A trail entry made relative to "now" for freeze reports. */
111
+ export interface SectionTrailEntry {
112
+ label: string;
113
+ startedAgoMs: number;
114
+ /** Absent while the section is still running (or never ended). */
115
+ endedAgoMs?: number;
116
+ }
117
+
118
+ /**
119
+ * Newest-first snapshot of recent section marks, ages relative to `now`.
120
+ * Reading it against a freeze report: the block began ~`blockedMs` ago, so
121
+ * the newest entry with `startedAgoMs >= blockedMs` that has no `endedAgoMs`
122
+ * (or ended after the block began) is the section that was running when the
123
+ * loop froze.
124
+ */
125
+ export function getSectionTrail(
126
+ now: number = performance.now(),
127
+ ): SectionTrailEntry[] {
128
+ return [...sectionTrail].reverse().map((mark) => ({
129
+ label: mark.label,
130
+ startedAgoMs: Math.round(now - mark.startedAt),
131
+ ...(mark.endedAt !== undefined
132
+ ? { endedAgoMs: Math.round(now - mark.endedAt) }
133
+ : {}),
134
+ }));
135
+ }
136
+
137
+ /** Test isolation only — the trail is process-global module state. */
138
+ export function resetSectionTrailForTests(): void {
139
+ sectionTrail.length = 0;
140
+ }
141
+
142
+ /**
143
+ * Report a synchronous section that blocked the event loop for `elapsedMs`.
144
+ * No-op below {@link SLOW_SYNC_THRESHOLD_MS}. `label` names the call site
145
+ * (e.g. `conversation:load-from-db`); `detail` carries attribution context
146
+ * (conversation id, row count, SQL preview) — never conversation content.
147
+ */
148
+ export function reportSlowSync(
149
+ label: string,
150
+ elapsedMs: number,
151
+ detail?: Record<string, unknown>,
152
+ ): void {
153
+ if (elapsedMs < SLOW_SYNC_THRESHOLD_MS) return;
154
+ log.warn(
155
+ { label, elapsedMs, ...detail },
156
+ "Slow synchronous DB operation blocked the event loop",
157
+ );
158
+ // Record telemetry via a lazy dynamic import. A static import would pull the
159
+ // telemetry → consent-cache → config/loader chain into the module graph of
160
+ // every raw-query / conversation-load caller, where a test's `mock.module`
161
+ // of the loader leaks across the shared test process and breaks unrelated
162
+ // files at eval time. Loading it only on the rare slow path keeps that chain
163
+ // off the hot path's static graph; best-effort, so a failure is swallowed.
164
+ void import("../telemetry/watchdog-events-store.js")
165
+ .then(({ recordWatchdogEvent }) => {
166
+ recordWatchdogEvent({
167
+ checkName: SLOW_SYNC_CHECK_NAME,
168
+ value: elapsedMs,
169
+ detail: { label, ...detail },
170
+ });
171
+ })
172
+ .catch(() => {
173
+ // Telemetry is best-effort — never let it escape the timed section.
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Time a synchronous section, returning its value, and {@link reportSlowSync}
179
+ * it when it blocks past the threshold. Every section also lands in the
180
+ * section trail, so watchdog freeze reports can place it on the timeline.
181
+ * `detail` is evaluated only on success, from the section's result, so it can
182
+ * report a computed count. A thrown error is still reported (the failed op
183
+ * still blocked) and then rethrown unchanged.
184
+ */
185
+ export function timeSyncSection<T>(
186
+ label: string,
187
+ fn: () => T,
188
+ detail?: (result: T) => Record<string, unknown>,
189
+ ): T {
190
+ const mark = markSection(label);
191
+ try {
192
+ const result = fn();
193
+ const elapsedMs = endSection(mark);
194
+ // Build `detail` only when actually reporting — the section runs on hot
195
+ // query paths, so the thunk must not allocate on the sub-threshold path.
196
+ if (elapsedMs >= SLOW_SYNC_THRESHOLD_MS) {
197
+ reportSlowSync(label, elapsedMs, detail?.(result));
198
+ }
199
+ return result;
200
+ } catch (err) {
201
+ reportSlowSync(label, endSection(mark));
202
+ throw err;
203
+ }
204
+ }
@@ -418,6 +418,14 @@ import { migrateAcpSessionHistoryUsageColumns } from "./migrations/307-acp-sessi
418
418
  import { migrateAcpSessionHistoryTokenColumns } from "./migrations/308-acp-session-history-token-columns.js";
419
419
  import { migrateDropRedundantIndexes } from "./migrations/309-drop-redundant-indexes.js";
420
420
  import { migrateLlmRequestLogLatencyBreakdown } from "./migrations/310-llm-request-log-latency-breakdown.js";
421
+ import { migrateCreateSubagentsTable } from "./migrations/311-create-subagents-table.js";
422
+ import { migrateDropInboxConversationStateTable } from "./migrations/312-drop-inbox-conversation-state-table.js";
423
+ import { migrateDropMessagesFts } from "./migrations/313-drop-messages-fts.js";
424
+ import { migrateAddConversationEnabledPlugins } from "./migrations/314-add-conversation-enabled-plugins.js";
425
+ import { migrateCreateA2aInvitesTable } from "./migrations/315-create-a2a-invites.js";
426
+ import { migrateDropContactChannelInviteId } from "./migrations/316-drop-contact-channels-invite-id.js";
427
+ import { migrateCanonicalGuardianRequesterSignals } from "./migrations/317-canonical-guardian-requester-signals.js";
428
+ import { migrateDropContactChannelTelemetry } from "./migrations/318-drop-contact-channel-telemetry.js";
421
429
  import type { MigrationStep } from "./migrations/run-migrations.js";
422
430
 
423
431
  export const migrationSteps: MigrationStep[] = [
@@ -1307,4 +1315,12 @@ export const migrationSteps: MigrationStep[] = [
1307
1315
  migrateAcpSessionHistoryTokenColumns,
1308
1316
  migrateDropRedundantIndexes,
1309
1317
  migrateLlmRequestLogLatencyBreakdown,
1318
+ migrateCreateSubagentsTable,
1319
+ migrateDropInboxConversationStateTable,
1320
+ migrateDropMessagesFts,
1321
+ migrateAddConversationEnabledPlugins,
1322
+ migrateCreateA2aInvitesTable,
1323
+ migrateDropContactChannelInviteId,
1324
+ migrateCanonicalGuardianRequesterSignals,
1325
+ migrateDropContactChannelTelemetry,
1310
1326
  ];