@vellumai/assistant 0.11.2 → 0.11.3-staging.2

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 (720) hide show
  1. package/ARCHITECTURE.md +58 -3
  2. package/docs/trusted-contact-access.md +9 -5
  3. package/docs/vellum-doctor.md +195 -0
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  7. package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
  8. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
  9. package/node_modules/@vellumai/environments/package.json +2 -1
  10. package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
  11. package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
  12. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
  13. package/node_modules/@vellumai/environments/src/index.ts +17 -6
  14. package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
  15. package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
  16. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  19. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
  20. package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
  21. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
  22. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
  23. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
  24. package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
  25. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
  26. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
  27. package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  28. package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  29. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  30. package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
  31. package/openapi.yaml +589 -30
  32. package/package.json +1 -1
  33. package/src/__tests__/agent-image-optimize.test.ts +4 -4
  34. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
  35. package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
  36. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
  37. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  38. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  39. package/src/__tests__/answered-question-persistence.test.ts +240 -0
  40. package/src/__tests__/anthropic-provider.test.ts +165 -30
  41. package/src/__tests__/app-control-flow.test.ts +9 -8
  42. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  43. package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
  44. package/src/__tests__/attachments-store.test.ts +130 -68
  45. package/src/__tests__/attachments.test.ts +36 -36
  46. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  47. package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
  48. package/src/__tests__/canned-reply-release.test.ts +86 -0
  49. package/src/__tests__/channel-guardian.test.ts +59 -29
  50. package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
  51. package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
  52. package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
  53. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  54. package/src/__tests__/consult-deadline.test.ts +65 -0
  55. package/src/__tests__/conversation-agent-loop.test.ts +438 -2
  56. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
  57. package/src/__tests__/conversation-disk-view.test.ts +4 -4
  58. package/src/__tests__/conversation-error.test.ts +22 -3
  59. package/src/__tests__/conversation-fork-crud.test.ts +5 -1
  60. package/src/__tests__/conversation-fork-referential.test.ts +352 -0
  61. package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
  62. package/src/__tests__/conversation-group-tools.test.ts +32 -2
  63. package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
  64. package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
  65. package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
  66. package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
  67. package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
  68. package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
  69. package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
  70. package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
  71. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
  72. package/src/__tests__/conversation-queue.test.ts +433 -1
  73. package/src/__tests__/conversation-retry-route.test.ts +3 -1
  74. package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
  75. package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
  76. package/src/__tests__/conversation-store.test.ts +26 -10
  77. package/src/__tests__/conversation-summarize-route.test.ts +1 -1
  78. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
  79. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
  81. package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
  82. package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
  83. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
  84. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  85. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
  90. package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
  91. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
  92. package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
  93. package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
  94. package/src/__tests__/credential-prompt-route.test.ts +57 -7
  95. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  96. package/src/__tests__/cu-unified-flow.test.ts +89 -28
  97. package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
  98. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
  99. package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
  100. package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
  101. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  102. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  103. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  104. package/src/__tests__/disk-usage.test.ts +35 -20
  105. package/src/__tests__/document-sync-tags.test.ts +379 -0
  106. package/src/__tests__/document-update-default-surface.test.ts +28 -0
  107. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  108. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
  109. package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
  110. package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
  111. package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
  112. package/src/__tests__/file-list-tool.test.ts +12 -10
  113. package/src/__tests__/file-ops-service.test.ts +151 -44
  114. package/src/__tests__/file-read-container-boundary.test.ts +137 -0
  115. package/src/__tests__/file-read-tool.test.ts +21 -9
  116. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  117. package/src/__tests__/filesystem-tools.test.ts +82 -66
  118. package/src/__tests__/guardian-outbound-http.test.ts +8 -8
  119. package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
  120. package/src/__tests__/helpers/hub-clients.ts +42 -0
  121. package/src/__tests__/helpers/mock-conversation.ts +46 -0
  122. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
  123. package/src/__tests__/history-repair.test.ts +112 -12
  124. package/src/__tests__/host-bash-proxy.test.ts +10 -5
  125. package/src/__tests__/host-bash-routes.test.ts +67 -0
  126. package/src/__tests__/host-browser-proxy.test.ts +2 -2
  127. package/src/__tests__/host-cu-proxy.test.ts +3 -7
  128. package/src/__tests__/host-file-proxy.test.ts +3 -7
  129. package/src/__tests__/host-file-read-tool.test.ts +5 -1
  130. package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
  131. package/src/__tests__/http-conversation-lineage.test.ts +2 -5
  132. package/src/__tests__/http-user-message-parity.test.ts +44 -0
  133. package/src/__tests__/identity-routes.test.ts +13 -13
  134. package/src/__tests__/image-conversion.test.ts +29 -26
  135. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  136. package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
  137. package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
  138. package/src/__tests__/introduction-card-resolver.test.ts +6 -1
  139. package/src/__tests__/list-messages-attachments.test.ts +56 -32
  140. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  141. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  142. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  143. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  144. package/src/__tests__/list-messages-provider-error.test.ts +6 -6
  145. package/src/__tests__/list-messages-queued.test.ts +49 -6
  146. package/src/__tests__/list-messages-system-card.test.ts +4 -4
  147. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  148. package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
  149. package/src/__tests__/llm-usage-store.test.ts +55 -0
  150. package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
  151. package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
  152. package/src/__tests__/media-stream-server-integration.test.ts +36 -0
  153. package/src/__tests__/migration-export-http.test.ts +1 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  155. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  156. package/src/__tests__/migration-validate-http.test.ts +1 -1
  157. package/src/__tests__/mtime-cache.test.ts +65 -3
  158. package/src/__tests__/notification-platform-adapter.test.ts +104 -0
  159. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  160. package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
  161. package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
  162. package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
  163. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  164. package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
  165. package/src/__tests__/path-policy.test.ts +164 -1
  166. package/src/__tests__/persist-media-references.test.ts +2 -2
  167. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  168. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  169. package/src/__tests__/persona-resolver.test.ts +154 -0
  170. package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
  171. package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
  172. package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
  173. package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
  174. package/src/__tests__/profiler-routes.test.ts +13 -13
  175. package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
  176. package/src/__tests__/proxy-approval-callback.test.ts +3 -3
  177. package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
  178. package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
  179. package/src/__tests__/resolve-trust-class.test.ts +20 -0
  180. package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
  181. package/src/__tests__/run-due-schedules.test.ts +174 -0
  182. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  183. package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
  184. package/src/__tests__/schedule-routes.test.ts +730 -8
  185. package/src/__tests__/schedule-store.test.ts +540 -0
  186. package/src/__tests__/schedule-tools.test.ts +103 -0
  187. package/src/__tests__/scheduler-wake.test.ts +5 -0
  188. package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
  189. package/src/__tests__/secure-keys.test.ts +91 -0
  190. package/src/__tests__/server-history-render.test.ts +97 -7
  191. package/src/__tests__/size-guard.test.ts +8 -8
  192. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  193. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  194. package/src/__tests__/skills-install-staging.test.ts +15 -6
  195. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  196. package/src/__tests__/slack-inbound-verification.test.ts +4 -1
  197. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  198. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  199. package/src/__tests__/starter-task-flow.test.ts +5 -4
  200. package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
  201. package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
  202. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  203. package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
  204. package/src/__tests__/subagent-disposal.test.ts +10 -0
  205. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  206. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  207. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  208. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  209. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  210. package/src/__tests__/subagent-persistence.test.ts +141 -0
  211. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  212. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  213. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  214. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  215. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  216. package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
  217. package/src/__tests__/subagent-tools.test.ts +1901 -108
  218. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  219. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  220. package/src/__tests__/system-prompt.test.ts +82 -7
  221. package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
  222. package/src/__tests__/tool-result-spool.test.ts +74 -18
  223. package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
  224. package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
  225. package/src/__tests__/tools-audio-read.test.ts +10 -10
  226. package/src/__tests__/tools-get-route.test.ts +85 -12
  227. package/src/__tests__/tools-list-cli.test.ts +171 -0
  228. package/src/__tests__/top-level-renderer.test.ts +54 -1
  229. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
  230. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
  231. package/src/__tests__/turn-tail-chain.test.ts +135 -0
  232. package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
  233. package/src/__tests__/ui-visual-surface.test.ts +5 -4
  234. package/src/__tests__/ui-work-result-surface.test.ts +5 -4
  235. package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
  236. package/src/__tests__/usage-routes.test.ts +62 -0
  237. package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
  238. package/src/__tests__/visible-app-context.test.ts +20 -4
  239. package/src/__tests__/web-search-history.test.ts +96 -0
  240. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
  241. package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
  242. package/src/acp/failure-error.ts +3 -5
  243. package/src/agent/attachments.ts +26 -24
  244. package/src/agent/history-repair/history-repair.ts +27 -26
  245. package/src/agent/image-optimize.ts +6 -6
  246. package/src/agent/loop.ts +40 -22
  247. package/src/agent/message-types.ts +3 -3
  248. package/src/api/constants/document-tools.ts +55 -0
  249. package/src/api/events/question-answered.ts +53 -0
  250. package/src/api/events/tool-result.ts +7 -0
  251. package/src/api/index.ts +13 -0
  252. package/src/api/responses/conversation-message.ts +11 -0
  253. package/src/api/surfaces-oauth-connect.test.ts +96 -0
  254. package/src/api/surfaces.ts +36 -8
  255. package/src/approvals/guardian-channel-delivery.ts +83 -0
  256. package/src/approvals/guardian-expiry-notifier.ts +13 -11
  257. package/src/approvals/guardian-request-resolvers.ts +222 -135
  258. package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
  259. package/src/calls/media-stream-server.ts +9 -1
  260. package/src/calls/voice-session-bridge.ts +38 -0
  261. package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
  262. package/src/channels/config.ts +7 -2
  263. package/src/channels/gateway-verification-sessions.ts +7 -2
  264. package/src/channels/types.ts +7 -1
  265. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  266. package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
  267. package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
  268. package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
  269. package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
  270. package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
  271. package/src/cli/commands/__tests__/plugins.test.ts +692 -0
  272. package/src/cli/commands/__tests__/schedules.test.ts +136 -37
  273. package/src/cli/commands/conversations.ts +7 -3
  274. package/src/cli/commands/credentials.help.ts +7 -0
  275. package/src/cli/commands/inference-profiles.ts +9 -3
  276. package/src/cli/commands/inference.help.ts +16 -2
  277. package/src/cli/commands/mcp.help.ts +4 -2
  278. package/src/cli/commands/memory/memory-retrospective.ts +18 -0
  279. package/src/cli/commands/notifications.ts +3 -6
  280. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
  281. package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
  282. package/src/cli/commands/oauth/connect.test.ts +26 -1
  283. package/src/cli/commands/oauth/connect.ts +4 -1
  284. package/src/cli/commands/oauth/index.help.ts +3 -1
  285. package/src/cli/commands/oauth/providers.ts +3 -0
  286. package/src/cli/commands/plugins.help.ts +25 -2
  287. package/src/cli/commands/plugins.ts +289 -10
  288. package/src/cli/commands/schedules.help.ts +14 -12
  289. package/src/cli/commands/schedules.ts +19 -5
  290. package/src/cli/commands/tools.help.ts +4 -2
  291. package/src/cli/commands/tools.ts +38 -0
  292. package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
  293. package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
  294. package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
  295. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
  296. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
  297. package/src/cli/lib/install-from-github.ts +61 -0
  298. package/src/cli/lib/install-from-platform.ts +13 -2
  299. package/src/cli/lib/plugin-surfaces.ts +124 -4
  300. package/src/cli/lib/upgrade-plugin.ts +18 -0
  301. package/src/cli.ts +1 -1
  302. package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
  303. package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
  304. package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
  305. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  306. package/src/config/bundled-skills/AGENTS.md +1 -1
  307. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  308. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
  309. package/src/config/bundled-skills/schedule/SKILL.md +5 -1
  310. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  311. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  312. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
  313. package/src/config/bundled-skills/subagent/SKILL.md +53 -22
  314. package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
  315. package/src/config/bundled-skills/visualize/SKILL.md +1 -1
  316. package/src/config/default-profile-catalog.ts +6 -2
  317. package/src/config/feature-flag-registry.json +25 -17
  318. package/src/config/llm-resolver.ts +45 -15
  319. package/src/config/loader.ts +70 -1
  320. package/src/config/profile-tool-support.ts +110 -0
  321. package/src/config/sanitize-for-transfer.ts +11 -0
  322. package/src/config/schema.ts +4 -0
  323. package/src/config/schemas/__tests__/stt.test.ts +20 -5
  324. package/src/config/schemas/channels.ts +13 -0
  325. package/src/config/schemas/memory-retrospective.ts +25 -0
  326. package/src/config/schemas/plugin-updates.ts +55 -0
  327. package/src/config/schemas/services.ts +8 -4
  328. package/src/config/schemas/stt.ts +17 -5
  329. package/src/config/schemas/timeouts.ts +1 -1
  330. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
  331. package/src/contacts/guardian-delivery-reader.ts +29 -2
  332. package/src/context/compactor.ts +4 -4
  333. package/src/context/post-turn-tool-result-truncation.ts +32 -16
  334. package/src/context/strip-injections.ts +42 -0
  335. package/src/context/tool-result-spool.ts +32 -18
  336. package/src/credential-execution/ces-runtime.ts +3 -0
  337. package/src/credential-execution/client.ts +22 -1
  338. package/src/credential-execution/process-manager.test.ts +99 -0
  339. package/src/credential-execution/process-manager.ts +62 -16
  340. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  341. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
  342. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  343. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
  344. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
  345. package/src/daemon/channel-ui-capability.ts +4 -4
  346. package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
  347. package/src/daemon/conversation-agent-loop.ts +318 -148
  348. package/src/daemon/conversation-attachments.ts +1 -1
  349. package/src/daemon/conversation-error.ts +8 -1
  350. package/src/daemon/conversation-initial-prompt.ts +16 -38
  351. package/src/daemon/conversation-lifecycle.ts +154 -32
  352. package/src/daemon/conversation-messaging.ts +106 -43
  353. package/src/daemon/conversation-process.ts +131 -33
  354. package/src/daemon/conversation-queue-manager.ts +10 -0
  355. package/src/daemon/conversation-runtime-assembly.ts +9 -4
  356. package/src/daemon/conversation-store.ts +52 -3
  357. package/src/daemon/conversation-surface-state.ts +9 -0
  358. package/src/daemon/conversation-surfaces.ts +403 -210
  359. package/src/daemon/conversation-tool-setup.ts +56 -7
  360. package/src/daemon/conversation-turn-finalize.ts +134 -89
  361. package/src/daemon/conversation.ts +111 -27
  362. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  363. package/src/daemon/disk-pressure-guard.ts +3 -3
  364. package/src/daemon/doordash-steps.ts +5 -5
  365. package/src/daemon/external-plugins-bootstrap.ts +7 -1
  366. package/src/daemon/handlers/config-channels.ts +48 -5
  367. package/src/daemon/handlers/conversation-history.ts +1 -1
  368. package/src/daemon/handlers/conversations.ts +62 -17
  369. package/src/daemon/handlers/shared.ts +12 -0
  370. package/src/daemon/handlers/skills.ts +11 -1
  371. package/src/daemon/identity-helpers.ts +38 -10
  372. package/src/daemon/install-assistant-command.ts +322 -0
  373. package/src/daemon/lifecycle.ts +14 -3
  374. package/src/daemon/message-types/conversations.ts +6 -7
  375. package/src/daemon/message-types/sync.ts +1 -0
  376. package/src/daemon/persist-media-references.ts +23 -14
  377. package/src/daemon/process-message.ts +6 -6
  378. package/src/daemon/tool-setup-types.ts +19 -122
  379. package/src/daemon/tool-side-effects.ts +17 -94
  380. package/src/daemon/trust-context-types.ts +39 -0
  381. package/src/daemon/trust-context.ts +14 -6
  382. package/src/daemon/turn-tail-chain.ts +73 -0
  383. package/src/daemon/web-search-history.ts +47 -33
  384. package/src/heartbeat/heartbeat-service.ts +6 -6
  385. package/src/ipc/__tests__/socket-path.test.ts +21 -0
  386. package/src/ipc/assistant-server.ts +17 -10
  387. package/src/ipc/cli-client.ts +10 -1
  388. package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
  389. package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
  390. package/src/ipc/socket-cleanup.ts +9 -7
  391. package/src/ipc/socket-path.ts +4 -96
  392. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  393. package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
  394. package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
  395. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  396. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
  397. package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
  398. package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
  399. package/src/live-voice/__tests__/protocol.test.ts +52 -0
  400. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
  401. package/src/live-voice/live-voice-archive.ts +13 -13
  402. package/src/live-voice/live-voice-connection.ts +7 -1
  403. package/src/live-voice/live-voice-photo.ts +169 -0
  404. package/src/live-voice/live-voice-session.ts +108 -4
  405. package/src/live-voice/protocol.ts +89 -1
  406. package/src/mcp/client.ts +10 -0
  407. package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
  408. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
  409. package/src/messaging/providers/callback-routing.ts +1 -0
  410. package/src/messaging/providers/discord/api.ts +312 -0
  411. package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
  412. package/src/messaging/providers/discord/render.test.ts +204 -0
  413. package/src/messaging/providers/discord/render.ts +195 -0
  414. package/src/messaging/providers/discord/send.test.ts +179 -0
  415. package/src/messaging/providers/discord/send.ts +212 -0
  416. package/src/messaging/providers/discord/transport.ts +81 -0
  417. package/src/messaging/providers/index.ts +3 -1
  418. package/src/messaging/providers/retry-policy.test.ts +247 -0
  419. package/src/messaging/providers/retry-policy.ts +206 -0
  420. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  421. package/src/messaging/providers/slack/mention-source.ts +287 -0
  422. package/src/messaging/providers/telegram-bot/api.ts +47 -130
  423. package/src/messaging/providers/whatsapp/api.ts +47 -136
  424. package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
  425. package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
  426. package/src/monitoring/db-integrity-sample.ts +6 -1
  427. package/src/monitoring/plugin-auto-update.ts +359 -0
  428. package/src/monitoring/resource-sampler.ts +21 -5
  429. package/src/monitoring/worker.ts +13 -0
  430. package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
  431. package/src/notifications/__tests__/broadcaster.test.ts +37 -1
  432. package/src/notifications/__tests__/copy-composer.test.ts +165 -0
  433. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
  434. package/src/notifications/__tests__/notification-utils.test.ts +249 -0
  435. package/src/notifications/adapters/platform.ts +31 -2
  436. package/src/notifications/assistant-reply-producer.ts +79 -32
  437. package/src/notifications/broadcaster.ts +30 -10
  438. package/src/notifications/copy-composer.ts +69 -0
  439. package/src/notifications/emit-signal.ts +82 -15
  440. package/src/notifications/events-store.ts +10 -2
  441. package/src/notifications/home-feed-side-effect.ts +6 -3
  442. package/src/notifications/notification-utils.ts +173 -5
  443. package/src/notifications/signal.ts +12 -0
  444. package/src/oauth/AGENTS.md +4 -2
  445. package/src/oauth/byo-connection.ts +6 -1
  446. package/src/oauth/credential-token-resolver.ts +3 -10
  447. package/src/oauth/manual-token-connection.ts +29 -64
  448. package/src/oauth/manual-token-providers.ts +62 -0
  449. package/src/oauth/provider-serializer.ts +13 -0
  450. package/src/oauth/seed-providers.ts +62 -11
  451. package/src/onboarding/onboarding-events-store.ts +91 -1
  452. package/src/permissions/question-prompter.test.ts +4 -0
  453. package/src/permissions/question-prompter.ts +21 -4
  454. package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
  455. package/src/persistence/attachments-store.ts +15 -15
  456. package/src/persistence/conversation-attention-store.ts +30 -10
  457. package/src/persistence/conversation-bootstrap.ts +17 -0
  458. package/src/persistence/conversation-crud.ts +363 -97
  459. package/src/persistence/conversation-group-migration.ts +1 -1
  460. package/src/persistence/conversation-key-store.ts +38 -10
  461. package/src/persistence/conversation-lineage.ts +226 -0
  462. package/src/persistence/conversation-plugin-facade.ts +28 -3
  463. package/src/persistence/conversation-queries.ts +207 -33
  464. package/src/persistence/conversation-types.ts +107 -1
  465. package/src/persistence/jobs-store.ts +32 -8
  466. package/src/persistence/llm-usage-store.ts +22 -0
  467. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  468. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  469. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  470. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  471. package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
  472. package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
  473. package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
  474. package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
  475. package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
  476. package/src/persistence/schema/conversations.ts +32 -0
  477. package/src/persistence/schema/infrastructure.ts +3 -0
  478. package/src/persistence/steps.ts +30 -0
  479. package/src/persistence/subagent-store.ts +148 -6
  480. package/src/platform/managed-speech.test.ts +20 -0
  481. package/src/platform/managed-speech.ts +9 -0
  482. package/src/plugin-api/index.ts +8 -0
  483. package/src/plugin-api/webhook-url.ts +151 -0
  484. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
  485. package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
  486. package/src/plugins/collect-source-versions.ts +4 -27
  487. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  488. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  489. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  490. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  491. package/src/plugins/defaults/index.ts +1 -1
  492. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
  493. package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
  494. package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
  495. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
  496. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
  497. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
  498. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
  499. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
  500. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
  501. package/src/plugins/defaults/memory/job-handlers.ts +87 -5
  502. package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
  503. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  504. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
  505. package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
  506. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
  507. package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
  508. package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
  509. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  510. package/src/plugins/defaults/memory/v2/router.ts +8 -0
  511. package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
  512. package/src/plugins/external-plugin-loader.ts +17 -8
  513. package/src/plugins/installed-plugin-dirs.ts +101 -0
  514. package/src/plugins/mtime-cache.ts +34 -22
  515. package/src/plugins/types.ts +69 -8
  516. package/src/prompts/persona-resolver.ts +6 -2
  517. package/src/prompts/system-prompt.ts +72 -17
  518. package/src/providers/__tests__/inference.test.ts +40 -0
  519. package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
  520. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  521. package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
  522. package/src/providers/anthropic/client.ts +112 -95
  523. package/src/providers/connection-resolution.ts +35 -1
  524. package/src/providers/gemini/client.ts +5 -5
  525. package/src/providers/inference/adapter-factory.ts +16 -10
  526. package/src/providers/inference/auth.ts +16 -0
  527. package/src/providers/inference/connection-availability.ts +164 -12
  528. package/src/providers/inference/connections.ts +25 -1
  529. package/src/providers/media-resolve.ts +21 -11
  530. package/src/providers/model-catalog.ts +15 -0
  531. package/src/providers/openai/chat-completions-provider.ts +4 -4
  532. package/src/providers/openai/responses-provider.ts +12 -25
  533. package/src/providers/registry.ts +9 -4
  534. package/src/providers/retry.ts +25 -0
  535. package/src/providers/server-tool-pairing.ts +134 -0
  536. package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
  537. package/src/providers/speech-to-text/deepgram.ts +1 -0
  538. package/src/providers/speech-to-text/resolve.ts +80 -10
  539. package/src/providers/speech-to-text/vellum-managed.ts +7 -1
  540. package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
  541. package/src/providers/types.ts +26 -6
  542. package/src/providers/vellum-model-routing.ts +6 -7
  543. package/src/runtime/AGENTS.md +2 -0
  544. package/src/runtime/__tests__/agent-wake.test.ts +16 -16
  545. package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
  546. package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
  547. package/src/runtime/agent-wake.ts +63 -24
  548. package/src/runtime/assistant-event-hub.ts +87 -12
  549. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
  550. package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
  551. package/src/runtime/auth/same-actor.ts +56 -8
  552. package/src/runtime/auth/scopes.ts +12 -0
  553. package/src/runtime/auth/types.ts +2 -0
  554. package/src/runtime/background-job-runner.ts +5 -27
  555. package/src/runtime/channel-readiness-service.ts +59 -3
  556. package/src/runtime/channel-readiness-types.ts +18 -0
  557. package/src/runtime/desktop-presence.ts +69 -0
  558. package/src/runtime/http-server.ts +12 -0
  559. package/src/runtime/local-actor-identity.ts +11 -9
  560. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  561. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  562. package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
  563. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
  564. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
  565. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
  566. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
  567. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  568. package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
  569. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  570. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
  571. package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
  572. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
  573. package/src/runtime/routes/archive-utils.ts +16 -12
  574. package/src/runtime/routes/attachment-routes.ts +13 -6
  575. package/src/runtime/routes/canned-reply-release.ts +54 -0
  576. package/src/runtime/routes/channel-verification-routes.ts +2 -27
  577. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
  578. package/src/runtime/routes/client-routes.ts +114 -2
  579. package/src/runtime/routes/conversation-cli-routes.ts +10 -12
  580. package/src/runtime/routes/conversation-list-routes.ts +59 -10
  581. package/src/runtime/routes/conversation-management-routes.ts +47 -18
  582. package/src/runtime/routes/conversation-query-routes.ts +32 -53
  583. package/src/runtime/routes/conversation-routes.ts +360 -293
  584. package/src/runtime/routes/credential-prompt-routes.ts +23 -2
  585. package/src/runtime/routes/debug-routes.ts +4 -1
  586. package/src/runtime/routes/default-provider-routes.ts +7 -11
  587. package/src/runtime/routes/documents-routes.ts +44 -1
  588. package/src/runtime/routes/events-routes.ts +28 -1
  589. package/src/runtime/routes/host-app-control-routes.ts +2 -0
  590. package/src/runtime/routes/host-bash-routes.ts +2 -0
  591. package/src/runtime/routes/host-browser-routes.ts +2 -0
  592. package/src/runtime/routes/host-cu-routes.ts +2 -0
  593. package/src/runtime/routes/host-file-routes.ts +2 -0
  594. package/src/runtime/routes/host-transfer-routes.ts +4 -0
  595. package/src/runtime/routes/identity-routes.ts +6 -6
  596. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  597. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
  598. package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
  599. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
  600. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
  601. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
  602. package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
  603. package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
  604. package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
  605. package/src/runtime/routes/inference-profiles-routes.ts +152 -73
  606. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
  607. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  608. package/src/runtime/routes/log-export-routes.ts +1 -1
  609. package/src/runtime/routes/notification-routes.ts +0 -14
  610. package/src/runtime/routes/oauth-providers.ts +1 -0
  611. package/src/runtime/routes/plugins-routes.ts +106 -1
  612. package/src/runtime/routes/profiler-routes.ts +4 -2
  613. package/src/runtime/routes/question-routes.ts +28 -10
  614. package/src/runtime/routes/retrospective-routes.ts +9 -3
  615. package/src/runtime/routes/schedule-routes.ts +210 -12
  616. package/src/runtime/routes/secret-routes.ts +40 -23
  617. package/src/runtime/routes/settings-routes.ts +41 -13
  618. package/src/runtime/routes/skills-routes.ts +79 -0
  619. package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
  620. package/src/runtime/routes/wake-conversation-routes.ts +23 -0
  621. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  622. package/src/runtime/services/conversation-serializer.ts +24 -9
  623. package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
  624. package/src/runtime/sync/resource-sync-events.ts +79 -1
  625. package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
  626. package/src/runtime/sync/worker-daemon-notify.ts +44 -6
  627. package/src/runtime/verification-outbound-actions.ts +250 -222
  628. package/src/runtime/verification-templates.ts +41 -30
  629. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
  630. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
  631. package/src/schedule/inference-profile.ts +64 -3
  632. package/src/schedule/plugin-schedule-declarations.ts +518 -0
  633. package/src/schedule/plugin-schedule-reconciler.ts +605 -0
  634. package/src/schedule/plugin-schedules-gate.ts +23 -0
  635. package/src/schedule/schedule-store.ts +520 -26
  636. package/src/schedule/scheduler.ts +38 -0
  637. package/src/security/credential-backend.ts +51 -4
  638. package/src/security/encrypted-store.ts +64 -42
  639. package/src/security/secure-keys.ts +55 -7
  640. package/src/skills/catalog-install.ts +20 -7
  641. package/src/skills/inline-command-runner.ts +2 -7
  642. package/src/skills/skill-history.test.ts +269 -0
  643. package/src/skills/skill-history.ts +250 -0
  644. package/src/skills/skillssh-registry.ts +1 -1
  645. package/src/stt/daemon-batch-transcriber.ts +8 -6
  646. package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
  647. package/src/subagent/consult-prompt.ts +3 -1
  648. package/src/subagent/consult-transcript.ts +1 -1
  649. package/src/subagent/manager.ts +304 -44
  650. package/src/subagent/progress-events.ts +35 -0
  651. package/src/subagent/role-resolution.ts +88 -0
  652. package/src/subagent/types.ts +302 -67
  653. package/src/subagent/validate-allowlists.ts +3 -4
  654. package/src/telegram/__tests__/webhook-health.test.ts +73 -1
  655. package/src/telegram/webhook-health.ts +101 -3
  656. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  657. package/src/telemetry/activation-funnel.ts +6 -1
  658. package/src/telemetry/live-voice-funnel.ts +75 -0
  659. package/src/telemetry/telemetry-event-sources.ts +6 -0
  660. package/src/telemetry/telemetry-wire-source.json +1 -1
  661. package/src/telemetry/telemetry-wire.generated.ts +2 -0
  662. package/src/telemetry/types.ts +23 -4
  663. package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
  664. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  665. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  666. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  667. package/src/tools/browser/browser-execution.ts +1 -1
  668. package/src/tools/calls/call-start.ts +8 -5
  669. package/src/tools/conversation-groups/move_to_group.ts +10 -12
  670. package/src/tools/document/document-tool.ts +11 -4
  671. package/src/tools/execution-timeout.ts +9 -2
  672. package/src/tools/executor.ts +7 -6
  673. package/src/tools/filesystem/edit.ts +1 -1
  674. package/src/tools/filesystem/list.ts +1 -1
  675. package/src/tools/filesystem/read.ts +7 -13
  676. package/src/tools/filesystem/search.ts +23 -21
  677. package/src/tools/filesystem/write.ts +4 -1
  678. package/src/tools/host-filesystem/edit.ts +7 -2
  679. package/src/tools/host-filesystem/read.ts +21 -8
  680. package/src/tools/host-filesystem/write.ts +10 -2
  681. package/src/tools/host-terminal/host-shell.ts +2 -2
  682. package/src/tools/mcp/mcp-tool-factory.ts +25 -1
  683. package/src/tools/permission-checker.ts +8 -3
  684. package/src/tools/schedule/delete.ts +13 -1
  685. package/src/tools/schedule/list.ts +14 -3
  686. package/src/tools/schedule/update.ts +56 -33
  687. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  688. package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
  689. package/src/tools/shared/filesystem/image-read.ts +12 -12
  690. package/src/tools/shared/filesystem/path-policy.ts +70 -5
  691. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  692. package/src/tools/shared/input-misuse.ts +72 -0
  693. package/src/tools/skills/scaffold-managed.ts +82 -0
  694. package/src/tools/skills/skill-tool-factory.ts +14 -1
  695. package/src/tools/subagent/consult-deadline.ts +12 -7
  696. package/src/tools/subagent/message.ts +3 -1
  697. package/src/tools/subagent/read.ts +66 -4
  698. package/src/tools/subagent/spawn.ts +500 -78
  699. package/src/tools/tool-approval-handler.ts +45 -4
  700. package/src/tools/types.ts +22 -3
  701. package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
  702. package/src/tools/ui-surface/visual-validation.ts +2 -0
  703. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  704. package/src/usage/subagent-attribution.ts +108 -0
  705. package/src/util/__tests__/sqlite-retry.test.ts +112 -0
  706. package/src/util/abort-reasons.ts +16 -0
  707. package/src/util/ansi.ts +44 -0
  708. package/src/util/disk-usage.ts +17 -13
  709. package/src/util/image-conversion.ts +20 -13
  710. package/src/util/schedule-source-key.ts +23 -0
  711. package/src/util/worker-process.ts +7 -1
  712. package/src/workspace/git-service.ts +33 -9
  713. package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
  714. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
  715. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
  716. package/src/workspace/migrations/registry.ts +4 -0
  717. package/src/workspace/top-level-renderer.ts +15 -2
  718. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
  719. package/src/daemon/install-symlink.ts +0 -207
  720. package/src/notifications/deferred-emit.ts +0 -147
package/ARCHITECTURE.md CHANGED
@@ -67,8 +67,10 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
67
67
  | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
68
68
  | `actor_client_v1` | `chat.{read,write}`, `approval.{read,write}`, `settings.{read,write}`, `attachments.{read,write}`, `calls.{read,write}`, `feature_flags.{read,write}` | Desktop, CLI clients |
69
69
  | `gateway_ingress_v1` | `ingress.write`, `internal.write` | Gateway channel inbound + webhook forwarding |
70
- | `gateway_service_v1` | `settings.read`, `settings.write`, `internal.write` | Gateway service-to-daemon calls |
71
- | `internal_v1` | `internal.all` | Internal service connections |
70
+ | `gateway_service_v1` | `chat.{read,write}`, `settings.{read,write}`, `attachments.{read,write}`, `internal.write` | Gateway service-to-daemon calls |
71
+ | `local_v1` | `local.all` | Local (loopback) conversation sessions |
72
+ | `speech_relay_v1` | `speech.relay` | Daemon dial of the gateway speech relay only |
73
+ | `ui_page_v1` | `settings.read` | Served UI pages |
72
74
 
73
75
  **Identity lifecycle:**
74
76
 
@@ -836,7 +838,7 @@ graph LR
836
838
  JOBS["memory_jobs<br/>───────────────<br/>Async task queue<br/>Types: embed, extract,<br/>summarize, backfill, cleanup<br/>Status: pending → running →<br/>completed | failed"]
837
839
  ATT["attachments<br/>───────────────<br/>base64-encoded file data<br/>mime_type, size_bytes<br/>Linked to messages via<br/>message_attachments join"]
838
840
  REM["reminders<br/>───────────────<br/>One-time scheduled reminders<br/>label, message, fireAt<br/>mode: notify | execute<br/>status: pending → fired | cancelled<br/>routing_intent: single_channel |<br/>multi_channel | all_channels<br/>routing_hints_json (free-form)"]
839
- SCHED_JOBS["cron_jobs (recurrence schedules)<br/>───────────────<br/>Recurring schedule definitions<br/>cron_expression: cron or RRULE string<br/>schedule_syntax: 'cron' | 'rrule'<br/>timezone, message, next_run_at<br/>enabled, retry_count<br/>Legacy alias: scheduleJobs"]
841
+ SCHED_JOBS["cron_jobs (recurrence schedules)<br/>───────────────<br/>Recurring schedule definitions<br/>cron_expression: cron or RRULE string<br/>schedule_syntax: 'cron' | 'rrule'<br/>timezone, message, next_run_at<br/>enabled, retry_count<br/>source_key: plugin-declared provenance<br/>definition_hash, user_enabled<br/>Legacy alias: scheduleJobs"]
840
842
  SCHED_RUNS["cron_runs (schedule runs)<br/>───────────────<br/>Execution history per schedule<br/>job_id (FK → cron_jobs)<br/>status: ok | error<br/>duration_ms, output, error<br/>Legacy alias: scheduleRuns"]
841
843
  TASKS["tasks<br/>───────────────<br/>Reusable prompt templates<br/>title, Handlebars template<br/>inputSchema, contextFlags<br/>requiredTools, status"]
842
844
  TASK_RUNS["task_runs<br/>───────────────<br/>Execution history per task<br/>taskId (FK → tasks)<br/>conversationId, status<br/>startedAt, finishedAt, error"]
@@ -861,6 +863,59 @@ graph LR
861
863
 
862
864
  ---
863
865
 
866
+ ## Plugin-Declared Schedules: Declaration → Reconciler → cron_jobs
867
+
868
+ Plugins contribute recurring schedules as a surface: directories under
869
+ `<pluginDir>/schedules/`, each a `<name>/` holding `config.json` plus
870
+ exactly one `index.md` (runs as `execute`) or `index.sh` (runs as `script`)
871
+ entrypoint. Ambiguity fails closed: a file sitting directly under
872
+ `schedules/`, zero/multiple/unsupported entrypoints, and malformed config
873
+ produce per-schedule `DeclarationError`s without affecting siblings
874
+ (`src/schedule/plugin-schedule-declarations.ts`).
875
+
876
+ A level-based reconciler (`src/schedule/plugin-schedule-reconciler.ts`)
877
+ converges declarations into ordinary `cron_jobs` rows keyed by the nullable
878
+ `source_key` column (`plugin:<plugin>/<name>`). Rows with `source_key IS
879
+ NULL` are imperative schedules the reconciler never touches. Triggers: a
880
+ startup pass in `daemon/lifecycle.ts` (after plugin init, before the
881
+ scheduler starts), the end of `reconcilePluginSourcesNow()` in
882
+ `plugins/mtime-cache.ts` (install/uninstall/upgrade and sentinel-driven
883
+ changes), the plugin enable/disable routes, and a 60s backstop sweep
884
+ registered with the HTTP server's background sweeps.
885
+
886
+ Reconcile lag never lets a disabled plugin run. The disable path writes a
887
+ `.disabled` sentinel that only a reconcile pass turns into disarmed rows, so
888
+ the scheduler re-reads the sentinel at fire time and records a skipped run
889
+ instead of executing a claimed row whose plugin is off. Run-now applies the
890
+ same boundary through `declarationExistsOnDisk`, which also covers a plugin
891
+ whose manifest no longer parses, a declaration directory that is gone, and a
892
+ plugin root or declaration directory resolving outside the tree it belongs to
893
+ (the same `isInsidePluginRoot` containment the loader applies before importing
894
+ a plugin).
895
+
896
+ A declaration that stops parsing keeps its execute row armed on the message
897
+ already stored in the row, but disarms its script rows: a script row fires its
898
+ entrypoint by absolute path, so leaving it armed would run the very `index.sh`
899
+ the parser rejected. Those rows re-arm on the pass after the declaration parses
900
+ again.
901
+
902
+ Ownership boundaries: the reconciler owns definition columns (expression,
903
+ timezone, message/script, retry policy, `definition_hash`); the execution
904
+ engine owns runtime columns (`next_run_at`, `status`, `last_*`,
905
+ `retry_count`) and its latches are never overridden; the user owns
906
+ `user_enabled`, a sticky override consulted when computing effective
907
+ `enabled`. Nothing ever writes to plugin files. Execution itself is
908
+ unchanged: declared rows fire through the same `claimDueSchedules` path as
909
+ imperative ones.
910
+
911
+ Consent and surfacing: CLI install/upgrade list declared schedules and
912
+ prompt before finalizing; unattended daemon-route installs are covered by
913
+ `schedule.declared` arrival notifications, with `schedule.definition_changed`
914
+ and `schedule.definition_error` covering upgrades and broken declarations
915
+ (events registered in `notifications/signal.ts`, deterministic templates in
916
+ `notifications/copy-composer.ts`). Settings routes, CLI, and web render
917
+ plugin-sourced rows read-only except the enabled toggle.
918
+
864
919
  ---
865
920
 
866
921
  ## Web Server — Connection Modes
@@ -43,6 +43,9 @@ Design doc defining how unknown users gain access to a Vellum assistant via chan
43
43
  5. **On approval the gateway mints a verification session.** The decide op carries a `mint_outbound_session` outcome; inside the decide transaction the gateway (`gateway/src/verification/session-service.ts`) generates a 6-digit code, persists only its SHA-256 hash in `channel_verification_sessions` (identity-bound to the requester, `verificationPurpose: 'trusted_contact'`), and returns the raw secret to the daemon in the decide response for delivery.
44
44
  6. **The code is delivered.** The daemon delivers the code to the guardian's verified channel (ephemeral + DM on Slack shared channels so other members never see it). On Slack the code is also DM'd straight to the requester; on other channels the guardian relays it out-of-band (in person, text message, phone call). That out-of-band transfer is the trust anchor: it proves the requester has a real-world relationship with the guardian.
45
45
  7. **Requester enters the code** back to the assistant on the same channel. The **gateway** intercepts bare verification codes at ingress (`gateway/src/verification/text-verification.ts`) whenever an interceptable session exists for that channel — the daemon never sees verification code messages.
46
+
47
+ On Discord the code is delivered to, and answered in, a DM (`gateway/src/discord/admit.ts` admits DMs on their own lane). A bare code typed into a guild channel is dropped by the mention gate before it reaches the intercept, so it is never consumed and never reaches the agent.
48
+
46
49
  8. **Gateway verifies the code and activates the user.** `validateAndConsumeSession()` checks the rate limit, hashes the code, matches it against a live session, verifies identity binding, atomically consumes the session, then applies the trusted-contact side effects: `applyTrustedContactSideEffects()` upserts the verified channel into the gateway ACL with `status: 'active'`, `policy: 'allow'` and mirrors the contact identity to the assistant DB. A blocked/revoked authoritative gateway row rejects the verification even when the code matched. The gateway delivers the deterministic success reply.
47
50
  9. **All subsequent messages are accepted normally.** The gateway stamps an allow verdict and the daemon processes the message.
48
51
 
@@ -65,11 +68,12 @@ requested -> pending_guardian -> verification_pending -> active | denied | expir
65
68
 
66
69
  Identity binding ensures the verification code can only be consumed by the intended recipient on the intended channel. The binding fields are set on the gateway `channel_verification_sessions` record when the session is created; the check itself is `checkIdentityMatch` (`gateway/src/verification/identity-match.ts`).
67
70
 
68
- | Channel | Identity fields | Binding behavior |
69
- | --------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
70
- | Telegram | `expectedExternalUserId` = Telegram user ID, `expectedChatId` = Telegram chat ID | Both are taken from the original denied message's metadata. The `identityBindingStatus` is `'bound'`. Verification requires the actor's user ID or chat ID to match (user ID required when both are set on a shared chat). |
71
- | Voice | `expectedPhoneE164` = phone number in E.164 format | Phone-based identity binding. Verification requires the caller's number to match the expected phone. |
72
- | Bootstrap | none yet (`identityBindingStatus: 'pending_bootstrap'`) | Unbound deep-link sessions use a 32-byte hex token instead of a numeric code; the identity is bound when the token is redeemed (`verification_sessions_bind_identity`). |
71
+ | Channel | Identity fields | Binding behavior |
72
+ | --------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
73
+ | Telegram | `expectedExternalUserId` = Telegram user ID, `expectedChatId` = Telegram chat ID | Both are taken from the original denied message's metadata. The `identityBindingStatus` is `'bound'`. Verification requires the actor's user ID or chat ID to match (user ID required when both are set on a shared chat). |
74
+ | Voice | `expectedPhoneE164` = phone number in E.164 format | Phone-based identity binding. Verification requires the caller's number to match the expected phone. |
75
+ | Discord | `expectedExternalUserId` = Discord user snowflake. `expectedChatId` is unset on the guardian-initiated and trusted-contact paths, and is the originating guild channel on the access-request approval path (`mint_outbound_session`), which sets it for every channel alike. | The code is delivered to a DM and answered there, but the DM channel does not exist until it is opened, so those two paths have no chat id to record at mint time. Where the approval path does set one, it is a room rather than an identity and never becomes a sufficient credential on its own: `checkIdentityMatch` requires the `expectedExternalUserId` match whenever both fields are set. That path also writes the room into `destinationAddress`, where it describes nothing the code is ever sent to (see LUM-3110). |
76
+ | Bootstrap | none yet (`identityBindingStatus: 'pending_bootstrap'`) | Unbound deep-link sessions use a 32-byte hex token instead of a numeric code; the identity is bound when the token is redeemed (`verification_sessions_bind_identity`). |
73
77
 
74
78
  **Anti-oracle invariant:** When identity verification fails, the error message is identical to the "invalid or expired code" message. This prevents attackers from distinguishing between a wrong code and a wrong identity, which would leak information about which identities have pending sessions.
75
79
 
@@ -0,0 +1,195 @@
1
+ # Vellum Doctor
2
+
3
+ Vellum Doctor is a platform-hosted diagnostic tool for investigating problems with a Vellum assistant.
4
+
5
+ > **Status:** Beta. Vellum Doctor is available in the web client for platform-hosted assistants; it is not available for self-hosted assistants.
6
+
7
+ ## What it does
8
+
9
+ Doctor provides a separate diagnostic session where a guardian can describe an issue and receive an investigation that may include:
10
+
11
+ - Plain-language explanations of what the Doctor found.
12
+ - Tool calls with expandable technical details and outputs.
13
+ - Requests for approval before an operation runs.
14
+ - A backup prompt before an operation that may modify the assistant.
15
+ - Feedback prompts when an issue may need attention from the Vellum team.
16
+ - A session transcript that can be copied for follow-up or support.
17
+
18
+ Doctor is separate from the assistant's normal conversation. It is a support and diagnosis surface, not another assistant that builds a long-term relationship with the guardian.
19
+
20
+ ## When to use it
21
+
22
+ Open Doctor when an assistant is not behaving as expected, especially when the cause could be a runtime problem, an integration or credential problem, a missing capability, a failed scheduled action, or a permission boundary.
23
+
24
+ The web client may show a **Go to Doctor** action in an operational error notice. Doctor can also be opened from the **Doctor** tab under the assistant's debug settings.
25
+
26
+ ### Open Doctor from chat
27
+
28
+ The web client supports a slash command that opens the Doctor panel:
29
+
30
+ ```text
31
+ /doctor
32
+ ```
33
+
34
+ You can include the first message after the command:
35
+
36
+ ```text
37
+ /doctor My assistant stopped responding after I connected Slack
38
+ ```
39
+
40
+ The command navigates to Doctor instead of sending the text as a normal assistant turn. On a self-hosted assistant, Doctor is unavailable and the command does not start a Doctor session.
41
+
42
+ ## Session lifecycle
43
+
44
+ A Doctor session follows this flow:
45
+
46
+ 1. The web client creates a diagnostic session for the active assistant.
47
+ 2. Doctor sends a greeting and opens a live event stream.
48
+ 3. The guardian describes the issue and can send follow-up messages while the session is active.
49
+ 4. Doctor streams assistant messages, tool activity, approval requests, backup prompts, and errors into the panel.
50
+ 5. The session ends with either `completed` or `error` status.
51
+ 6. The guardian can start a new session after a terminal state.
52
+
53
+ The web client can load the most recent persisted session when the Doctor panel opens. An active session can be resumed, including pending approval or backup prompts, and completed sessions remain available as history.
54
+
55
+ ## Approval and backup prompts
56
+
57
+ Doctor can ask for confirmation before running an operation.
58
+
59
+ - **Allow once** approves the requested operation for the current prompt.
60
+ - **Always Allow** is available for `exec_command` requests and approves future execution requests in that session.
61
+ - **Deny** rejects the requested operation.
62
+ - **Show details** reveals the tool name, description, and input that Doctor received.
63
+
64
+ Before an operation that may modify the assistant, Doctor can ask whether to create a backup first:
65
+
66
+ - **Back up** creates the backup before continuing.
67
+ - **Skip** continues without that backup.
68
+
69
+ Approval and backup prompts are part of the session transcript, so the guardian can see which operations were proposed and how they were handled.
70
+
71
+ ## Session history and transcripts
72
+
73
+ Doctor sessions are persisted against the assistant that they diagnose. The web client can retrieve the newest sessions and the ordered message ledger for a selected session.
74
+
75
+ A persisted session includes:
76
+
77
+ - Lifecycle status: `active`, `completed`, or `error`.
78
+ - Ordered user and Doctor messages.
79
+ - Tool calls and tool results.
80
+ - Approval, backup, feedback, status, and error entries.
81
+ - Message timestamps and counts.
82
+ - Token and estimated-cost totals returned by the platform API.
83
+
84
+ The **Copy Session** action serializes the visible session into text. Doctor's idle panel also warns that Doctor logs may be temporarily stored, so guardians should avoid entering secrets that are not necessary for diagnosis.
85
+
86
+ ## Feedback and support handoff
87
+
88
+ Doctor can show a feedback prompt when the investigation identifies an issue that may be useful to the Vellum team. The feedback flow can include the Doctor session ID and a transcript file, subject to the diagnostics choice in the feedback form.
89
+
90
+ Sharing feedback is separate from approving a Doctor operation. A guardian can continue describing the issue while the feedback prompt is present.
91
+
92
+ ## API reference
93
+
94
+ The platform API exposes Doctor under the assistant-scoped routes below. Requests use the same authentication options as the surrounding platform API.
95
+
96
+ | Operation | Route | Purpose |
97
+ | ---------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------- |
98
+ | List history | `GET /v1/assistants/{assistant_id}/doctor/history/` | List persisted sessions, newest first. |
99
+ | Retrieve history | `GET /v1/assistants/{assistant_id}/doctor/history/{doctor_session_id}/` | Retrieve one session and its ordered message ledger. |
100
+ | Create session | `POST /v1/assistants/{assistant_id}/doctor/sessions/` | Create a new diagnostic session and return its session ID. |
101
+ | Stream events | `GET /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/events/` | Receive Doctor events over Server-Sent Events. |
102
+ | Send message | `POST /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/messages/` | Send a message to an active session. |
103
+ | Record outcome | `POST /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/user-outcome/` | Record whether Doctor solved the problem. |
104
+ | Delete session | `DELETE /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/` | End and clean up a session. |
105
+
106
+ ### Create a session
107
+
108
+ A successful create request returns:
109
+
110
+ ```json
111
+ {
112
+ "session_id": "doctor-session-id"
113
+ }
114
+ ```
115
+
116
+ ### Send a message
117
+
118
+ The message body requires non-empty `content` and can include an optional `source_event_id` for replay-safe delivery:
119
+
120
+ ```json
121
+ {
122
+ "content": "My assistant cannot send messages to Slack"
123
+ }
124
+ ```
125
+
126
+ A successful request is accepted with HTTP `202` while the response arrives on the event stream.
127
+
128
+ ### Record the user outcome
129
+
130
+ When Doctor asks whether it solved the problem, submit the answer to the session's outcome route:
131
+
132
+ ```json
133
+ {
134
+ "resolved": true
135
+ }
136
+ ```
137
+
138
+ Use `false` when the problem was not resolved. The endpoint returns `200`, records the latest answer for the session, and works for both active and completed sessions.
139
+
140
+ ### Event types
141
+
142
+ The event stream validates and handles these event types:
143
+
144
+ | Event | Meaning |
145
+ | --------------------- | --------------------------------------------------------------- |
146
+ | `message` | A complete Doctor message. |
147
+ | `message_delta` | A streamed part of a Doctor message. |
148
+ | `tool_call` | Doctor started a tool operation. |
149
+ | `tool_result` | A tool operation returned output, including whether it failed. |
150
+ | `approval_required` | Doctor is waiting for an approval response. |
151
+ | `backup_prompt` | Doctor is asking whether to create a backup before continuing. |
152
+ | `feedback_prompt` | Doctor is offering a feedback handoff. |
153
+ | `user_outcome_prompt` | Doctor is asking whether it solved the guardian's problem. |
154
+ | `status` | The session is active, completed, or in an error state. |
155
+ | `error` | The session encountered an error with a human-readable message. |
156
+
157
+ Malformed events and unknown event types are ignored by the web client rather than being treated as trusted Doctor output.
158
+
159
+ ## Failure states and recovery
160
+
161
+ ### No assistant is selected
162
+
163
+ Doctor cannot start without an active assistant. Hatch or select an assistant, then reopen the Doctor panel.
164
+
165
+ ### Doctor is unavailable
166
+
167
+ Doctor is platform-hosted. Self-hosted assistants do not expose the Doctor tab or the `/doctor` command.
168
+
169
+ ### Monthly session limit
170
+
171
+ The platform can reject session creation when the available Doctor sessions for the month have been used. The web client tells the guardian to try again next month.
172
+
173
+ ### Service or connection failure
174
+
175
+ Session creation, message delivery, and event streaming can fail when the Doctor service or platform proxy is unavailable. The panel surfaces the returned error and ends the session when it cannot recover.
176
+
177
+ The event stream retries recoverable interruptions with a bounded reconnect policy. If the session has expired, its event history cannot be replayed, or the stream remains idle, the panel asks the guardian to start a new session.
178
+
179
+ ### A tool operation fails
180
+
181
+ A failed tool result is shown in the transcript with its technical output. Doctor can continue investigating, ask for another action, or end the session with an error. A failed operation does not become a successful diagnosis merely because the session is still open.
182
+
183
+ ## Source map
184
+
185
+ The implementation currently lives in the web client and platform API contract:
186
+
187
+ - `clients/web/src/domains/settings/pages/debug-page.tsx` exposes the Doctor tab.
188
+ - `clients/web/src/domains/settings/components/panels/doctor-panel.tsx` owns session creation, messaging, history, cleanup, and the panel UI.
189
+ - `clients/web/src/domains/settings/components/panels/use-doctor-sse.ts` owns the event stream, validation boundary, reconnect behavior, and replay handling.
190
+ - `clients/web/src/domains/settings/components/panels/doctor-event-schema.ts` defines the validated event contract.
191
+ - `clients/web/src/domains/settings/components/panels/doctor-event-handlers.ts` maps events into visible session entries.
192
+ - `clients/web/src/domains/settings/components/panels/doctor-history.ts` maps persisted messages and serializes copied transcripts.
193
+ - `clients/web/openapi-schemas/platform.yaml` defines the assistant-scoped Doctor routes and persisted session schemas.
194
+
195
+ The Vellum Assistant runtime does not provide a local Doctor CLI command. Doctor is a web and platform capability, not a command run inside a self-hosted assistant.
@@ -40,3 +40,42 @@ export function isChannelId(value: unknown): value is ChannelId {
40
40
  (CHANNEL_IDS as readonly string[]).includes(value)
41
41
  );
42
42
  }
43
+
44
+ /**
45
+ * The provider key holding each channel's bot credential.
46
+ *
47
+ * Two senses of "connected" share the provider registry: a provider the user
48
+ * authorized so the assistant can act **as them** (`slack`, `discord`,
49
+ * `google`), and a bot credential letting people reach the assistant **as
50
+ * itself**. Nothing in a provider key says which, and the naming actively
51
+ * misleads: `slack` and `discord` name the user integration while their bots
52
+ * take a `_channel` suffix, yet `telegram` *is* the bot, because Telegram has
53
+ * no user-identity integration.
54
+ *
55
+ * That irregularity is why this is stated rather than derived from the key,
56
+ * and it is stated here because this file already owns what a channel is.
57
+ *
58
+ * Deliberately only the key. What fields each credential requires is declared
59
+ * once already, per service, in the gateway's credential specs; restating it
60
+ * here would be a second copy of a different fact.
61
+ *
62
+ * Channels absent from this map reach the assistant without a bot credential
63
+ * of their own: `phone` through the voice provider, `vellum` and `platform`
64
+ * internally.
65
+ */
66
+ export const CHANNEL_BOT_PROVIDER = {
67
+ slack: "slack_channel",
68
+ discord: "discord_channel",
69
+ telegram: "telegram",
70
+ } as const satisfies Partial<Record<ChannelId, string>>;
71
+
72
+ /**
73
+ * Whether a provider key names a bot the assistant is reached through, rather
74
+ * than a grant letting it act as the user. This is the "which sense of
75
+ * connected" question, for any provider key.
76
+ */
77
+ export function isChannelBotProvider(providerKey: string): boolean {
78
+ return (Object.values(CHANNEL_BOT_PROVIDER) as readonly string[]).includes(
79
+ providerKey,
80
+ );
81
+ }
@@ -20,6 +20,16 @@ export function normalizePublicBaseUrl(value: unknown): string | undefined {
20
20
  return normalized.length > 0 ? normalized : undefined;
21
21
  }
22
22
 
23
+ /**
24
+ * Application close code the gateway's velay bridge sends to proxied
25
+ * WebSockets when the tunnel itself is lost (velay disconnect, gateway
26
+ * shutdown). A dedicated code because the natural 1001 (going away) cannot
27
+ * be sent through the JS `close()` API (the bridge would remap it to a
28
+ * misleading 4001), and Bun's WebSocket client drops close reasons, so the
29
+ * code is the only signal that survives the relay to the daemon.
30
+ */
31
+ export const GATEWAY_TUNNEL_LOST_WS_CLOSE_CODE = 4801;
32
+
23
33
  export function normalizeHttpPublicBaseUrl(value: unknown): string | undefined {
24
34
  if (typeof value !== "string") return undefined;
25
35
  const trimmed = value.trim();
@@ -21,6 +21,12 @@
21
21
  * `Date#toISOString()`.
22
22
  */
23
23
 
24
+ /**
25
+ * Pairing-challenge TTL in milliseconds (10 minutes): the gateway's challenge
26
+ * store enforces it and the `vellum pair` CLI renders it in user-facing copy.
27
+ */
28
+ export const REMOTE_WEB_PAIRING_CODE_TTL_MS = 10 * 60 * 1000;
29
+
24
30
  /** `POST /v1/remote-web/pairing-challenge` request body. */
25
31
  export interface RemoteWebPairingChallengeRequest {
26
32
  /** Public https base URL the scanning device can reach the assistant at. */
@@ -40,4 +40,5 @@ export {
40
40
  type CesRpcClient,
41
41
  type CesRpcClientConfig,
42
42
  type CesRpcHandshakeOptions,
43
+ type CesRpcLogger,
43
44
  } from "./rpc-client.js";
@@ -69,11 +69,23 @@ interface PendingRequest {
69
69
  // Client configuration
70
70
  // ---------------------------------------------------------------------------
71
71
 
72
+ /** Minimal logger interface. Callers can supply pino, console, etc. */
73
+ export interface CesRpcLogger {
74
+ info(obj: Record<string, unknown>, msg: string): void;
75
+ info(msg: string): void;
76
+ }
77
+
72
78
  export interface CesRpcClientConfig {
73
79
  /** Timeout for individual RPC requests (ms). Default: 30 000 */
74
80
  requestTimeoutMs?: number;
75
81
  /** Timeout for the initial handshake (ms). Default: 10 000 */
76
82
  handshakeTimeoutMs?: number;
83
+ /**
84
+ * Optional logger for lifecycle transitions (handshake accepted, close).
85
+ * These transitions are otherwise invisible, which made a stuck credential
86
+ * backend hard to diagnose.
87
+ */
88
+ logger?: CesRpcLogger;
77
89
  }
78
90
 
79
91
  const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
@@ -154,12 +166,15 @@ export function createCesRpcClient(
154
166
  config?.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
155
167
  const handshakeTimeoutMs =
156
168
  config?.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS;
169
+ const logger = config?.logger;
157
170
 
158
171
  const sessionId = randomUUID();
159
172
  let requestCounter = 0;
160
173
  let ready = false;
161
- let inflightHandshake: Promise<{ accepted: boolean; reason?: string }> | null =
162
- null;
174
+ let inflightHandshake: Promise<{
175
+ accepted: boolean;
176
+ reason?: string;
177
+ }> | null = null;
163
178
 
164
179
  const pending = new Map<string, PendingRequest>();
165
180
 
@@ -380,6 +395,7 @@ export function createCesRpcClient(
380
395
 
381
396
  if (ack.accepted) {
382
397
  ready = true;
398
+ logger?.info("CES RPC client handshake accepted; ready for calls");
383
399
  }
384
400
 
385
401
  return { accepted: ack.accepted, reason: ack.reason };
@@ -413,6 +429,7 @@ export function createCesRpcClient(
413
429
  close(): void {
414
430
  rejectAllPending(new CesTransportError("CES client closed"));
415
431
  ready = false;
432
+ logger?.info("CES RPC client closed");
416
433
  transport.close();
417
434
  },
418
435
  };
@@ -5,7 +5,8 @@
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "exports": {
8
- ".": "./src/index.ts"
8
+ ".": "./src/index.ts",
9
+ "./seeds": "./src/seeds.ts"
9
10
  },
10
11
  "scripts": {
11
12
  "typecheck": "bunx tsc --noEmit",
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Pins the environment-to-cloud-hub mapping in one place. Both consumers
3
+ * (the Capacitor shell's `server.url` and the CLI remote-web edge's
4
+ * `hubUrl`) read this helper, so this matrix is the single behavioral pin
5
+ * for the served URLs.
6
+ */
7
+
8
+ import { describe, expect, test } from "bun:test";
9
+
10
+ import { cloudAssistantHubUrl, SEEDS } from "../index.js";
11
+
12
+ describe("cloudAssistantHubUrl", () => {
13
+ test("cloud environments resolve to their own web origin", () => {
14
+ expect(cloudAssistantHubUrl("production")).toBe(
15
+ "https://www.vellum.ai/assistant",
16
+ );
17
+ expect(cloudAssistantHubUrl("staging")).toBe(
18
+ "https://staging-assistant.vellum.ai/assistant",
19
+ );
20
+ });
21
+
22
+ test("every other environment falls back to the dev SPA", () => {
23
+ for (const name of ["dev", "test", "local", "unknown-env", undefined]) {
24
+ expect(cloudAssistantHubUrl(name)).toBe(
25
+ "https://dev-assistant.vellum.ai/assistant",
26
+ );
27
+ }
28
+ });
29
+
30
+ test("cloud hub URLs derive from the seed web URLs", () => {
31
+ for (const name of ["production", "staging"]) {
32
+ expect(cloudAssistantHubUrl(name)).toBe(
33
+ `${SEEDS[name].webUrl}/assistant`,
34
+ );
35
+ }
36
+ expect(cloudAssistantHubUrl("local")).toBe(`${SEEDS.dev.webUrl}/assistant`);
37
+ });
38
+ });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Tests for reading an install layout: telling a repo checkout from an
3
+ * installed package, and locating the `assistant` command that ships with an
4
+ * install.
5
+ */
6
+
7
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
+
12
+ import { findAssistantCommand, isRepoCheckoutPath } from "../index.js";
13
+
14
+ let root: string;
15
+
16
+ beforeEach(() => {
17
+ root = mkdtempSync(join(tmpdir(), "install-layout-"));
18
+ });
19
+
20
+ afterEach(() => {
21
+ rmSync(root, { recursive: true, force: true });
22
+ });
23
+
24
+ /** Create `<nodeModulesDir>/.bin/assistant` and return its path. */
25
+ function seedCommand(nodeModulesDir: string): string {
26
+ const binDir = join(nodeModulesDir, ".bin");
27
+ mkdirSync(binDir, { recursive: true });
28
+ const command = join(binDir, "assistant");
29
+ writeFileSync(command, "#!/usr/bin/env bun\n");
30
+ return command;
31
+ }
32
+
33
+ describe("isRepoCheckoutPath", () => {
34
+ test("an installed package is not a checkout", () => {
35
+ expect(
36
+ isRepoCheckoutPath(
37
+ "/Users/x/Library/Application Support/@vellumai/macos/cli/latest/node_modules/@vellumai/assistant/src/index.ts",
38
+ ),
39
+ ).toBe(false);
40
+ });
41
+
42
+ test("a repo checkout is", () => {
43
+ expect(
44
+ isRepoCheckoutPath("/Users/x/dev/vellum/assistant/src/index.ts"),
45
+ ).toBe(true);
46
+ });
47
+
48
+ test("a directory merely named node_modules-ish is not enough", () => {
49
+ expect(
50
+ isRepoCheckoutPath("/Users/x/node_modules_backup/a/src/index.ts"),
51
+ ).toBe(true);
52
+ });
53
+ });
54
+
55
+ describe("findAssistantCommand", () => {
56
+ test("finds the command shipped beside an installed package", () => {
57
+ const nodeModules = join(root, "cli", "latest", "node_modules");
58
+ const command = seedCommand(nodeModules);
59
+ const path = join(nodeModules, "@vellumai", "assistant", "src", "index.ts");
60
+
61
+ expect(findAssistantCommand(path)).toBe(command);
62
+ });
63
+
64
+ test("prefers a nested install over a hoisted one", () => {
65
+ const outer = join(root, "node_modules");
66
+ const outerCommand = seedCommand(outer);
67
+ const inner = join(outer, "vellum", "node_modules");
68
+ const innerCommand = seedCommand(inner);
69
+ const path = join(inner, "@vellumai", "assistant", "src", "index.ts");
70
+
71
+ expect(findAssistantCommand(path)).toBe(innerCommand);
72
+ expect(innerCommand).not.toBe(outerCommand);
73
+ });
74
+
75
+ test("falls back to a hoisted install when the nested one has no command", () => {
76
+ const outer = join(root, "node_modules");
77
+ const outerCommand = seedCommand(outer);
78
+ const inner = join(outer, "vellum", "node_modules");
79
+ mkdirSync(inner, { recursive: true });
80
+ const path = join(inner, "@vellumai", "assistant", "src", "index.ts");
81
+
82
+ expect(findAssistantCommand(path)).toBe(outerCommand);
83
+ });
84
+
85
+ test("returns null for a repo checkout", () => {
86
+ expect(
87
+ findAssistantCommand(join(root, "assistant", "src", "index.ts")),
88
+ ).toBeNull();
89
+ });
90
+
91
+ test("returns null when the install ships no assistant command", () => {
92
+ const nodeModules = join(root, "node_modules");
93
+ mkdirSync(join(nodeModules, ".bin"), { recursive: true });
94
+ const path = join(nodeModules, "@vellumai", "assistant", "src", "index.ts");
95
+
96
+ expect(findAssistantCommand(path)).toBeNull();
97
+ });
98
+ });
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Package boundary tests for @vellumai/environments.
3
3
  *
4
- * This package is the lowest layer of the shared-packages hierarchy: pure
5
- * environment types and constants with no runtime dependencies. It must
6
- * stay a leaf so any consumer (CLI, assistant, local-mode host) can depend
7
- * on it without dragging in a dependency tree.
4
+ * This package is the lowest layer of the shared-packages hierarchy:
5
+ * environment types, constants, and small helpers over node builtins, with no
6
+ * runtime dependencies. It must stay a leaf so any consumer (CLI, assistant,
7
+ * local-mode host) can depend on it without dragging in a dependency tree.
8
8
  *
9
9
  * Enforces that the package:
10
10
  * 1. Imports only node builtins and its own relative modules — no `@vellumai/*`
@@ -79,7 +79,7 @@ describe("package boundary", () => {
79
79
  throw new Error(
80
80
  `Found ${violations.length} forbidden import(s) in @vellumai/environments:\n` +
81
81
  violations.map((v) => ` - ${v}`).join("\n") +
82
- "\n\n@vellumai/environments is a pure types/constants leaf and must\n" +
82
+ "\n\n@vellumai/environments is a dependency-free leaf and must\n" +
83
83
  "import only node builtins and its own relative modules.",
84
84
  );
85
85
  }