@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
@@ -132,7 +132,7 @@ describe("persistUnsendableImageDowngrades", () => {
132
132
  );
133
133
 
134
134
  // WHEN the downgrade is persisted
135
- const rewritten = persistUnsendableImageDowngrades(conv.id);
135
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
136
136
 
137
137
  // THEN one message is rewritten with no image block left
138
138
  expect(rewritten).toBe(1);
@@ -162,7 +162,7 @@ describe("persistUnsendableImageDowngrades", () => {
162
162
  );
163
163
 
164
164
  // WHEN the downgrade is persisted
165
- const rewritten = persistUnsendableImageDowngrades(conv.id);
165
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
166
166
 
167
167
  // THEN only the rejected original is removed
168
168
  expect(rewritten).toBe(1);
@@ -184,7 +184,7 @@ describe("persistUnsendableImageDowngrades", () => {
184
184
  );
185
185
 
186
186
  // WHEN the downgrade is persisted
187
- const rewritten = persistUnsendableImageDowngrades(conv.id);
187
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
188
188
 
189
189
  // THEN nothing is rewritten and the image remains
190
190
  expect(rewritten).toBe(0);
@@ -202,7 +202,7 @@ describe("persistUnsendableImageDowngrades", () => {
202
202
  });
203
203
 
204
204
  // WHEN the downgrade is persisted
205
- const rewritten = persistUnsendableImageDowngrades(conv.id);
205
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
206
206
 
207
207
  // THEN the oversized-payload image is removed
208
208
  expect(rewritten).toBe(1);
@@ -224,7 +224,7 @@ describe("persistUnsendableImageDowngrades", () => {
224
224
  );
225
225
 
226
226
  // WHEN the downgrade is persisted
227
- const rewritten = persistUnsendableImageDowngrades(conv.id);
227
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
228
228
 
229
229
  // THEN the undersized image is removed (upscale is a no-op on this host)
230
230
  expect(rewritten).toBe(1);
@@ -248,7 +248,7 @@ describe("persistUnsendableImageDowngrades", () => {
248
248
  );
249
249
 
250
250
  // WHEN the downgrade is persisted
251
- const rewritten = persistUnsendableImageDowngrades(conv.id);
251
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
252
252
 
253
253
  // THEN the message is rewritten with the nested image swapped for a note
254
254
  expect(rewritten).toBe(1);
@@ -274,7 +274,7 @@ describe("persistUnsendableImageDowngrades", () => {
274
274
  );
275
275
 
276
276
  // WHEN the downgrade is persisted
277
- const rewritten = persistUnsendableImageDowngrades(conv.id);
277
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
278
278
 
279
279
  // THEN nothing is rewritten and the nested image remains
280
280
  expect(rewritten).toBe(0);
@@ -302,7 +302,7 @@ describe("persistUnsendableImageDowngrades", () => {
302
302
  );
303
303
 
304
304
  // WHEN the downgrade is persisted
305
- const rewritten = persistUnsendableImageDowngrades(conv.id);
305
+ const rewritten = await persistUnsendableImageDowngrades(conv.id);
306
306
 
307
307
  // THEN the image survives with its media type corrected to the sniffed one
308
308
  expect(rewritten).toBe(1);
@@ -319,7 +319,7 @@ describe("persistUnsendableImageDowngrades", () => {
319
319
  });
320
320
 
321
321
  // AND a second run is a no-op (the corrected block no longer mismatches)
322
- expect(persistUnsendableImageDowngrades(conv.id)).toBe(0);
322
+ expect(await persistUnsendableImageDowngrades(conv.id)).toBe(0);
323
323
  });
324
324
 
325
325
  /** Re-running after a rewrite is a safe no-op (no image blocks remain). */
@@ -332,10 +332,10 @@ describe("persistUnsendableImageDowngrades", () => {
332
332
  JSON.stringify([imageBlock(makePngBase64(10000, 10000))]),
333
333
  { skipIndexing: true },
334
334
  );
335
- expect(persistUnsendableImageDowngrades(conv.id)).toBe(1);
335
+ expect(await persistUnsendableImageDowngrades(conv.id)).toBe(1);
336
336
 
337
337
  // WHEN the downgrade runs a second time
338
- const secondRun = persistUnsendableImageDowngrades(conv.id);
338
+ const secondRun = await persistUnsendableImageDowngrades(conv.id);
339
339
 
340
340
  // THEN nothing further is rewritten
341
341
  expect(secondRun).toBe(0);
@@ -346,46 +346,46 @@ describe("unsendableImageReplacement", () => {
346
346
  /** A still-sendable image must be left alone — never replaced with a note.
347
347
  * This is the gate that keeps the in-memory recovery from discarding valid
348
348
  * screenshots when only one image in the turn was actually oversized. */
349
- test("returns null for an image within the provider caps", () => {
349
+ test("returns null for an image within the provider caps", async () => {
350
350
  const sendable = imageBlock(makePngBase64(1024, 768)) as Extract<
351
351
  ContentBlock,
352
352
  { type: "image" }
353
353
  >;
354
- expect(unsendableImageReplacement(sendable)).toBeNull();
354
+ expect(await unsendableImageReplacement(sendable)).toBeNull();
355
355
  });
356
356
 
357
357
  /** An image past the provider caps that cannot be shrunk on this host (fake
358
358
  * PNG that sips cannot decode) collapses to the unsendable note. */
359
- test("returns the unsendable note when an oversized image cannot be shrunk", () => {
359
+ test("returns the unsendable note when an oversized image cannot be shrunk", async () => {
360
360
  const oversized = imageBlock(makePngBase64(12000, 9000)) as Extract<
361
361
  ContentBlock,
362
362
  { type: "image" }
363
363
  >;
364
- const replacement = unsendableImageReplacement(oversized);
364
+ const replacement = await unsendableImageReplacement(oversized);
365
365
  expect(replacement?.type).toBe("text");
366
366
  });
367
367
 
368
368
  /** An image below the provider's minimum-size floor (rejected with "Could
369
369
  * not process image") that cannot be upscaled on this host collapses to
370
370
  * the unsendable note, same as the oversized direction. */
371
- test("returns the unsendable note when an undersized image cannot be upscaled", () => {
371
+ test("returns the unsendable note when an undersized image cannot be upscaled", async () => {
372
372
  const undersized = imageBlock(makePngBase64(16, 14)) as Extract<
373
373
  ContentBlock,
374
374
  { type: "image" }
375
375
  >;
376
- const replacement = unsendableImageReplacement(undersized);
376
+ const replacement = await unsendableImageReplacement(undersized);
377
377
  expect(replacement?.type).toBe("text");
378
378
  });
379
379
 
380
380
  /** A within-limits image whose declared media type disagrees with its bytes
381
381
  * is relabeled with the sniffed type instead of being noted out. */
382
- test("relabels a mislabeled image with its sniffed media type", () => {
382
+ test("relabels a mislabeled image with its sniffed media type", async () => {
383
383
  const pngData = makePngBase64(1024, 768);
384
384
  const mislabeled = imageBlock(pngData, "image/jpeg") as Extract<
385
385
  ContentBlock,
386
386
  { type: "image" }
387
387
  >;
388
- const replacement = unsendableImageReplacement(mislabeled);
388
+ const replacement = await unsendableImageReplacement(mislabeled);
389
389
  expect(replacement).toMatchObject({
390
390
  type: "image",
391
391
  source: { type: "base64", media_type: "image/png", data: pngData },
@@ -394,9 +394,9 @@ describe("unsendableImageReplacement", () => {
394
394
 
395
395
  /** Relabeling a persisted (workspace_ref) image keeps the reference shape —
396
396
  * inlining it would bake the full payload into the stored message row. */
397
- test("relabels a mislabeled workspace_ref without inlining the payload", () => {
397
+ test("relabels a mislabeled workspace_ref without inlining the payload", async () => {
398
398
  const pngData = makePngBase64(1024, 768);
399
- const stored = uploadAttachment("photo.png", "image/png", pngData);
399
+ const stored = await uploadAttachment("photo.png", "image/png", pngData);
400
400
  const mislabeledRef = {
401
401
  type: "image",
402
402
  source: {
@@ -407,7 +407,7 @@ describe("unsendableImageReplacement", () => {
407
407
  },
408
408
  } as Extract<ContentBlock, { type: "image" }>;
409
409
 
410
- const replacement = unsendableImageReplacement(mislabeledRef);
410
+ const replacement = await unsendableImageReplacement(mislabeledRef);
411
411
 
412
412
  expect(replacement).toMatchObject({
413
413
  type: "image",
@@ -419,7 +419,7 @@ describe("unsendableImageReplacement", () => {
419
419
  });
420
420
  // AND the corrected reference no longer matches on a second pass
421
421
  expect(
422
- unsendableImageReplacement(
422
+ await unsendableImageReplacement(
423
423
  replacement as Extract<ContentBlock, { type: "image" }>,
424
424
  ),
425
425
  ).toBeNull();
@@ -63,6 +63,8 @@ function seedVellumGuardian(userFile: string | null): void {
63
63
 
64
64
  mock.module("../util/platform.js", () => ({
65
65
  getWorkspaceDir: () => mockWorkspaceDir,
66
+ getWorkspacePromptPath: (filename: string) =>
67
+ join(mockWorkspaceDir, "prompts", filename),
66
68
  }));
67
69
 
68
70
  mock.module("../contacts/contact-store.js", () => ({
@@ -96,6 +98,7 @@ mock.module("../contacts/guardian-delivery-reader.js", () => ({
96
98
  // Import AFTER mocks so the module under test binds to the stubbed
97
99
  // implementations.
98
100
  import { getGuardianDelivery } from "../contacts/guardian-delivery-reader.js";
101
+ import { resolveUserName } from "../daemon/identity-helpers.js";
99
102
  import type { TrustContext } from "../daemon/trust-context-types.js";
100
103
  import {
101
104
  ensureGuardianPersonaFile,
@@ -408,3 +411,154 @@ describe("resolveUserSlug (guardian trust WITH requester identity)", () => {
408
411
  expect(resolveUserSlug(trustContext)).toBeNull();
409
412
  });
410
413
  });
414
+
415
+ // ── resolveUserSlug — guardian bound on a non-vellum channel ───────
416
+ //
417
+ // warmGuardianBindings warms both the channel-filtered and unfiltered cache
418
+ // keys, but a guardian may be bound only on a non-vellum channel (phone,
419
+ // Telegram). A guardian-class turn sourced elsewhere must still resolve that
420
+ // guardian instead of silently landing on users/default.md.
421
+
422
+ describe("resolveUserSlug (guardian bound on a non-vellum channel)", () => {
423
+ test("falls back to the any-channel guardian when the source channel has none", () => {
424
+ mockGuardianDeliveries = [
425
+ { channelType: "telegram", address: "guardian-tg", status: "active" },
426
+ ];
427
+ mockContactsByAddress["telegram:guardian-tg"] = { userFile: "alice.md" };
428
+
429
+ const trustContext = {
430
+ sourceChannel: "vellum",
431
+ trustClass: "guardian",
432
+ } as TrustContext;
433
+
434
+ expect(resolveUserSlug(trustContext)).toBe("alice");
435
+ });
436
+
437
+ test("any-channel guardian with no userFile resolves the guardian.md fallback", () => {
438
+ mockGuardianDeliveries = [
439
+ { channelType: "telegram", address: "guardian-tg", status: "active" },
440
+ ];
441
+ mockContactsByAddress["telegram:guardian-tg"] = { userFile: null };
442
+
443
+ const trustContext = {
444
+ sourceChannel: "vellum",
445
+ trustClass: "guardian",
446
+ } as TrustContext;
447
+
448
+ expect(resolveUserSlug(trustContext)).toBe("guardian");
449
+ });
450
+ });
451
+
452
+ // ── resolveUserSlug — cold cache then construction-time warm ───────
453
+ //
454
+ // The exact shape scheduled tasks and memory consolidation pass through
455
+ // resolveInitialSystemPrompt: guardian class, no requester identity, built in
456
+ // a worker process whose guardian-delivery cache starts cold.
457
+
458
+ describe("resolveUserSlug (cold cache, background shape)", () => {
459
+ test("misses on a cold cache, resolves the guardian after the construction-time warm", async () => {
460
+ pendingWarmDeliveries = [
461
+ { channelType: "vellum", address: "vellum:self", status: "active" },
462
+ ];
463
+ mockContactsByAddress["vellum:vellum:self"] = { userFile: "alice.md" };
464
+
465
+ const trustContext = {
466
+ sourceChannel: "vellum",
467
+ trustClass: "guardian",
468
+ } as TrustContext;
469
+
470
+ // Cold: the sync peek finds nothing and the slug falls back to default.
471
+ expect(resolveUserSlug(trustContext)).toBeNull();
472
+
473
+ // resolveInitialSystemPrompt warms guardian bindings for guardian-class
474
+ // contexts before building; afterwards the same resolution succeeds.
475
+ await getGuardianDelivery({ channelTypes: ["vellum"] });
476
+
477
+ expect(resolveUserSlug(trustContext)).toBe("alice");
478
+ });
479
+ });
480
+
481
+ // ── resolveUserName — guardian-preferred display name ──────────────
482
+ //
483
+ // The sweep job and v2 router address the user by name in their prompts. The
484
+ // name must come from the guardian's own persona file when one is resolvable,
485
+ // falling back to users/default.md.
486
+
487
+ describe("resolveUserName", () => {
488
+ test("prefers the Name label from the guardian's own persona file over default.md", () => {
489
+ seedVellumGuardian("alice.md");
490
+ const usersDir = join(mockWorkspaceDir, "users");
491
+ mkdirSync(usersDir, { recursive: true });
492
+ writeFileSync(join(usersDir, "alice.md"), "**Name:** Alice\n", "utf-8");
493
+ writeFileSync(
494
+ join(usersDir, "default.md"),
495
+ "**Name:** Default User\n",
496
+ "utf-8",
497
+ );
498
+
499
+ expect(resolveUserName(mockWorkspaceDir)).toBe("Alice");
500
+ });
501
+
502
+ test("reads the onboarding-written Preferred name bullet", () => {
503
+ seedVellumGuardian("alice.md");
504
+ const usersDir = join(mockWorkspaceDir, "users");
505
+ mkdirSync(usersDir, { recursive: true });
506
+ writeFileSync(
507
+ join(usersDir, "alice.md"),
508
+ "# User Profile\n\n## Onboarding Context\n\n- **Preferred name:** Ali\n",
509
+ "utf-8",
510
+ );
511
+
512
+ expect(resolveUserName(mockWorkspaceDir)).toBe("Ali");
513
+ });
514
+
515
+ test("reads the scaffold's filled Preferred name/reference line", () => {
516
+ seedVellumGuardian("alice.md");
517
+ const usersDir = join(mockWorkspaceDir, "users");
518
+ mkdirSync(usersDir, { recursive: true });
519
+ writeFileSync(
520
+ join(usersDir, "alice.md"),
521
+ "- Preferred name/reference: Alice\n- Pronouns: she/her\n",
522
+ "utf-8",
523
+ );
524
+
525
+ expect(resolveUserName(mockWorkspaceDir)).toBe("Alice");
526
+ });
527
+
528
+ test("an unfilled scaffold does not swallow the next line and falls back to default.md", () => {
529
+ seedVellumGuardian("alice.md");
530
+ const usersDir = join(mockWorkspaceDir, "users");
531
+ mkdirSync(usersDir, { recursive: true });
532
+ // The bare scaffold: every label present, every value unfilled.
533
+ ensureGuardianPersonaFile("alice.md");
534
+ writeFileSync(join(usersDir, "default.md"), "**Name:** Bob\n", "utf-8");
535
+
536
+ expect(resolveUserName(mockWorkspaceDir)).toBe("Bob");
537
+ });
538
+
539
+ test("a declined_by_user sentinel is not used as a name", () => {
540
+ seedVellumGuardian("alice.md");
541
+ const usersDir = join(mockWorkspaceDir, "users");
542
+ mkdirSync(usersDir, { recursive: true });
543
+ writeFileSync(
544
+ join(usersDir, "alice.md"),
545
+ "- Preferred name/reference: declined_by_user\n",
546
+ "utf-8",
547
+ );
548
+ writeFileSync(join(usersDir, "default.md"), "**Name:** Bob\n", "utf-8");
549
+
550
+ expect(resolveUserName(mockWorkspaceDir)).toBe("Bob");
551
+ });
552
+
553
+ test("falls back to default.md when no guardian resolves", () => {
554
+ const usersDir = join(mockWorkspaceDir, "users");
555
+ mkdirSync(usersDir, { recursive: true });
556
+ writeFileSync(join(usersDir, "default.md"), "**Name:** Bob\n", "utf-8");
557
+
558
+ expect(resolveUserName(mockWorkspaceDir)).toBe("Bob");
559
+ });
560
+
561
+ test("returns null when neither file yields a name", () => {
562
+ expect(resolveUserName(mockWorkspaceDir)).toBeNull();
563
+ });
564
+ });
@@ -0,0 +1,170 @@
1
+ /**
2
+ * `resolveWebhookUrl`: the URL a plugin hands a vendor.
3
+ *
4
+ * The resolution order itself belongs to `resolveCallbackUrl`, which is spied
5
+ * on here rather than reimplemented. Restating it would recreate the
6
+ * duplication this module exists to remove. What is covered is what this
7
+ * module adds: which plugin the route belongs to, the path it composes, the
8
+ * registration type it derives, and what it refuses.
9
+ */
10
+
11
+ import { describe, expect, spyOn, test } from "bun:test";
12
+
13
+ import * as registration from "../inbound/platform-callback-registration.js";
14
+ import { resolveWebhookUrl } from "../plugin-api/webhook-url.js";
15
+ import { runInPluginContext } from "../plugins/plugin-execution-context.js";
16
+
17
+ describe("resolveWebhookUrl", () => {
18
+ test("composes the plugin's namespaced path and delegates the tier choice", async () => {
19
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
20
+ "https://callbacks.vellum.ai/abc/webhooks/plugins/imessage/events-photon",
21
+ );
22
+
23
+ const url = await resolveWebhookUrl({
24
+ plugin: "imessage",
25
+ path: "events-photon",
26
+ });
27
+
28
+ expect(url).toBe(
29
+ "https://callbacks.vellum.ai/abc/webhooks/plugins/imessage/events-photon",
30
+ );
31
+ expect(spy.mock.calls[0]![1]).toBe(
32
+ "webhooks/plugins/imessage/events-photon",
33
+ );
34
+ spy.mockRestore();
35
+ });
36
+
37
+ test("defaults to the plugin in context", async () => {
38
+ // Hooks and tools run in plugin context, so the common caller passes no
39
+ // plugin at all.
40
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
41
+ "https://example.test/x",
42
+ );
43
+
44
+ await runInPluginContext("imessage", () =>
45
+ resolveWebhookUrl({ path: "events-comms" }),
46
+ );
47
+
48
+ expect(spy.mock.calls[0]![1]).toBe(
49
+ "webhooks/plugins/imessage/events-comms",
50
+ );
51
+ spy.mockRestore();
52
+ });
53
+
54
+ test("an explicit plugin wins over the one in context", async () => {
55
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
56
+ "https://example.test/x",
57
+ );
58
+
59
+ await runInPluginContext("other", () =>
60
+ resolveWebhookUrl({ plugin: "imessage", path: "events-comms" }),
61
+ );
62
+
63
+ expect(spy.mock.calls[0]![1]).toBe(
64
+ "webhooks/plugins/imessage/events-comms",
65
+ );
66
+ spy.mockRestore();
67
+ });
68
+
69
+ test("says so when there is no plugin to attribute the route to", async () => {
70
+ await expect(resolveWebhookUrl({ path: "events" })).rejects.toThrow(
71
+ /No plugin is in context/,
72
+ );
73
+ });
74
+
75
+ test("gives routes that share a slug distinct registration types", async () => {
76
+ // The platform keys a callback route by type, so a collision has the
77
+ // second registration replace the first. `events-v1` and `events_v1`
78
+ // slugify identically.
79
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
80
+ "https://example.test/x",
81
+ );
82
+
83
+ await resolveWebhookUrl({ plugin: "imessage", path: "events-v1" });
84
+ await resolveWebhookUrl({ plugin: "imessage", path: "events_v1" });
85
+
86
+ const types = spy.mock.calls.map((call) => call[2]);
87
+ expect(new Set(types).size).toBe(2);
88
+ spy.mockRestore();
89
+ });
90
+
91
+ test("accepts the paths the gateway's route schema accepts", async () => {
92
+ // A path this rejects but the gateway serves is a route a plugin can
93
+ // install and then never resolve a URL for.
94
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
95
+ "https://example.test/x",
96
+ );
97
+
98
+ for (const path of [
99
+ "events-photon",
100
+ "events:v1",
101
+ "hooks/@vendor",
102
+ "a/b/c",
103
+ ]) {
104
+ await expect(
105
+ resolveWebhookUrl({ plugin: "imessage", path }),
106
+ ).resolves.toBeDefined();
107
+ }
108
+ spy.mockRestore();
109
+ });
110
+
111
+ test("refuses a plugin name or path that escapes the namespace", async () => {
112
+ // The prefix is fixed so a plugin cannot claim another's routes. That only
113
+ // holds if the segments cannot escape it either.
114
+ for (const options of [
115
+ { plugin: "../vellum", path: "events" },
116
+ { plugin: "imessage", path: "../../admin" },
117
+ { plugin: "imessage", path: "/events" },
118
+ { plugin: "imessage", path: "events/" },
119
+ { plugin: "imessage", path: "events?x=1" },
120
+ { plugin: "imessage", path: "%2e%2e/admin" },
121
+ { plugin: "imessage", path: "" },
122
+ ]) {
123
+ await expect(resolveWebhookUrl(options)).rejects.toThrow(/Invalid/);
124
+ }
125
+ });
126
+
127
+ test("hands the vendor a URL with no trailing slash", async () => {
128
+ // The platform appends one, and a provider delivers to the URL it was
129
+ // given verbatim. The gateway matches the declared path, which never ends
130
+ // in a slash, so a registration carrying one 404s every delivery.
131
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
132
+ "https://callbacks.vellum.ai/abc/webhooks/plugins/imessage/events-comms/",
133
+ );
134
+
135
+ await expect(
136
+ resolveWebhookUrl({ plugin: "imessage", path: "events-comms" }),
137
+ ).resolves.toBe(
138
+ "https://callbacks.vellum.ai/abc/webhooks/plugins/imessage/events-comms",
139
+ );
140
+ spy.mockRestore();
141
+ });
142
+
143
+ test("leaves a URL carrying a query string alone", async () => {
144
+ // Trimming there would cut into the query rather than the path.
145
+ const spy = spyOn(registration, "resolveCallbackUrl").mockResolvedValue(
146
+ "https://example.test/webhooks/plugins/imessage/events-comms?token=abc/",
147
+ );
148
+
149
+ await expect(
150
+ resolveWebhookUrl({ plugin: "imessage", path: "events-comms" }),
151
+ ).resolves.toBe(
152
+ "https://example.test/webhooks/plugins/imessage/events-comms?token=abc/",
153
+ );
154
+ spy.mockRestore();
155
+ });
156
+
157
+ test("propagates the failure when nothing can answer", async () => {
158
+ // No ingress and no platform connection means there is no URL that works.
159
+ // Returning a plausible one would produce a vendor registration that
160
+ // silently receives nothing.
161
+ const spy = spyOn(registration, "resolveCallbackUrl").mockRejectedValue(
162
+ new Error("Public ingress URL is not configured"),
163
+ );
164
+
165
+ await expect(
166
+ resolveWebhookUrl({ plugin: "imessage", path: "events-photon" }),
167
+ ).rejects.toThrow("Public ingress URL is not configured");
168
+ spy.mockRestore();
169
+ });
170
+ });
@@ -115,6 +115,12 @@ const BASELINE: Record<string, readonly string[]> = {
115
115
  "../../../../config/skill-state.js",
116
116
  "../../../../config/skills.js",
117
117
  "../../../../config/types.js",
118
+ // Same host module the retrospective job couples to (the `../../../`
119
+ // entry below): the sweep job and v2 router warm the guardian-delivery
120
+ // cache before their sync `resolveUserName` reads so worker-process
121
+ // prompts address the guardian instead of the default profile. No
122
+ // plugin-api equivalent.
123
+ "../../../../contacts/guardian-delivery-reader.js",
118
124
  "../../../../context/token-estimator.js",
119
125
  "../../../../daemon/conversation-error.js",
120
126
  "../../../../daemon/conversation-notices.js",
@@ -1,9 +1,15 @@
1
1
  /**
2
2
  * Regression: `Conversation.setProcessing(value)` flips the in-memory flag and
3
- * then persists it to the `processing_started_at` column. If that DB write
4
- * throws (e.g. SQLITE_BUSY under contention), the in-memory flag must not be
5
- * left stranded out of sync with the column — it reverts to its prior value
6
- * and the error re-throws so callers' existing failure handling still runs.
3
+ * then persists it to the `processing_started_at` column. The two directions
4
+ * treat a failed write differently, and both are covered here.
5
+ *
6
+ * Acquiring is strict: the in-memory flag reverts to its prior value and the
7
+ * error re-throws so callers' existing failure handling still runs.
8
+ *
9
+ * Clearing is not: the in-memory flag is this process's queue gate while the
10
+ * column is advisory state the boot-time stale-processing sweep recovers, so a
11
+ * failed mirror write must still leave the conversation released rather than
12
+ * latching it "busy" for the rest of the daemon's life.
7
13
  */
8
14
  import { beforeEach, describe, expect, mock, test } from "bun:test";
9
15
 
@@ -209,17 +215,16 @@ describe("Conversation.setProcessing persistence failure", () => {
209
215
  expect(conversation.isProcessing()).toBe(false);
210
216
  });
211
217
 
212
- test("restores the prior value when clearing fails mid-turn", () => {
218
+ test("releases in memory when the clear's mirror write fails", () => {
213
219
  conversation.setProcessing(true);
214
220
  expect(conversation.isProcessing()).toBe(true);
215
221
 
216
222
  persistShouldThrow = true;
217
- expect(() => conversation.setProcessing(false)).toThrow(
218
- "database is locked",
219
- );
223
+ expect(() => conversation.setProcessing(false)).not.toThrow();
220
224
 
221
- // Clear didn't persist, so the flag stays consistent with the column.
222
- expect(conversation.isProcessing()).toBe(true);
225
+ // The queue gate is the in-memory flag, so a failed advisory write must
226
+ // not leave the conversation rejecting every later send as "busy".
227
+ expect(conversation.isProcessing()).toBe(false);
223
228
  });
224
229
 
225
230
  test("commits the flag when the DB write succeeds", () => {