@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
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Queue-cancellation and steer-recovery contracts on the shared handlers.
3
+ *
4
+ * `deleteQueuedMessage` closes out the queued row on the sender's event sink,
5
+ * pairing that terminal event with the same visibility predicate the enqueue
6
+ * ack used.
7
+ *
8
+ * `steerToMessage` promotes a queued message and then aborts the in-flight
9
+ * turn. When the flag is latched with no live controller there is nothing to
10
+ * abort and no agent-loop release coming, so the handler force-clears and
11
+ * drains itself instead of leaving the promoted message at the head of a queue
12
+ * that never runs.
13
+ */
14
+ import { afterEach, describe, expect, mock, test } from "bun:test";
15
+
16
+ import type { AssistantEvent } from "../api/index.js";
17
+
18
+ const broadcasts: AssistantEvent[] = [];
19
+ mock.module("../runtime/assistant-event-hub.js", () => ({
20
+ broadcastMessage: (msg: AssistantEvent) => {
21
+ broadcasts.push(msg);
22
+ },
23
+ }));
24
+
25
+ import type { Conversation } from "../daemon/conversation.js";
26
+ import type { QueuedMessage } from "../daemon/conversation-queue-manager.js";
27
+ import {
28
+ deleteConversation,
29
+ setConversation,
30
+ } from "../daemon/conversation-registry.js";
31
+ import {
32
+ deleteQueuedMessage,
33
+ steerToMessage,
34
+ } from "../daemon/handlers/conversations.js";
35
+
36
+ const CONV = "queued-cancel-conv";
37
+
38
+ /**
39
+ * Register a conversation holding one queued message, and hand back the events
40
+ * the handler delivered to that message's sender sink.
41
+ */
42
+ function registerWithQueuedMessage(
43
+ queued: Partial<QueuedMessage> | undefined,
44
+ ): AssistantEvent[] {
45
+ const sent: AssistantEvent[] = [];
46
+ const item = queued
47
+ ? { ...queued, onEvent: (msg: AssistantEvent) => sent.push(msg) }
48
+ : undefined;
49
+ const fake = {
50
+ conversationId: CONV,
51
+ isProcessing: () => false,
52
+ queue: {
53
+ findByRequestId: (requestId: string) =>
54
+ item?.requestId === requestId ? item : undefined,
55
+ },
56
+ removeQueuedMessage: () => item,
57
+ };
58
+ setConversation(CONV, fake as unknown as Conversation);
59
+ return sent;
60
+ }
61
+
62
+ interface LatchedTurn {
63
+ cleared: () => boolean;
64
+ drainReasons: string[];
65
+ pendingSteerRepair: () => boolean;
66
+ }
67
+
68
+ /**
69
+ * Register a conversation whose processing flag is latched with no live
70
+ * controller: the shape a turn leaves behind when it tore its controller down
71
+ * (or died) without any release running.
72
+ */
73
+ function registerLatchedTurn(): LatchedTurn {
74
+ let processing = true;
75
+ const drainReasons: string[] = [];
76
+ const fake = {
77
+ conversationId: CONV,
78
+ isProcessing: () => processing,
79
+ setProcessing: (value: boolean) => {
80
+ processing = value;
81
+ },
82
+ abortController: null,
83
+ queue: {
84
+ findByRequestId: (requestId: string) => ({ requestId }),
85
+ promoteToHead: (requestId: string) => ({ requestId }),
86
+ },
87
+ pendingSteerRepair: false,
88
+ kickDrainQueue: (reason: string) => {
89
+ drainReasons.push(reason);
90
+ return Promise.resolve();
91
+ },
92
+ denyAllPendingConfirmations: () => {},
93
+ };
94
+ setConversation(CONV, fake as unknown as Conversation);
95
+ return {
96
+ cleared: () => !processing,
97
+ drainReasons,
98
+ pendingSteerRepair: () => fake.pendingSteerRepair,
99
+ };
100
+ }
101
+
102
+ describe("deleteQueuedMessage", () => {
103
+ afterEach(() => {
104
+ broadcasts.length = 0;
105
+ deleteConversation(CONV);
106
+ });
107
+
108
+ test("closes out the queued row so clients retire the pending indicator", () => {
109
+ const sent = registerWithQueuedMessage({
110
+ requestId: "req-1",
111
+ clientMessageId: "client-1",
112
+ metadata: {},
113
+ });
114
+
115
+ expect(deleteQueuedMessage(CONV, "req-1")).toEqual({ removed: true });
116
+ expect(sent).toEqual([
117
+ {
118
+ type: "message_queued_deleted",
119
+ conversationId: CONV,
120
+ requestId: "req-1",
121
+ clientMessageId: "client-1",
122
+ },
123
+ ]);
124
+ });
125
+
126
+ test("omits clientMessageId when the sender minted none", () => {
127
+ const sent = registerWithQueuedMessage({
128
+ requestId: "req-2",
129
+ metadata: {},
130
+ });
131
+
132
+ expect(deleteQueuedMessage(CONV, "req-2")).toEqual({ removed: true });
133
+ expect(sent).toEqual([
134
+ {
135
+ type: "message_queued_deleted",
136
+ conversationId: CONV,
137
+ requestId: "req-2",
138
+ },
139
+ ]);
140
+ });
141
+
142
+ test("stays silent for an echo-suppressed entry", () => {
143
+ // A daemon-injected notification never produced a `message_queued` ack, so
144
+ // a delete event would be an unpaired retire for a row no client renders.
145
+ const sent = registerWithQueuedMessage({
146
+ requestId: "req-3",
147
+ metadata: {
148
+ subagentNotification: { subagentId: "child-1", label: "research" },
149
+ },
150
+ });
151
+
152
+ expect(deleteQueuedMessage(CONV, "req-3")).toEqual({ removed: true });
153
+ expect(sent).toEqual([]);
154
+ });
155
+
156
+ test("stays silent when nothing matched the request id", () => {
157
+ const sent = registerWithQueuedMessage(undefined);
158
+
159
+ expect(deleteQueuedMessage(CONV, "req-missing")).toEqual({
160
+ removed: false,
161
+ reason: "message_not_found",
162
+ });
163
+ expect(sent).toEqual([]);
164
+ expect(broadcasts).toEqual([]);
165
+ });
166
+ });
167
+
168
+ describe("steerToMessage with a latched processing flag", () => {
169
+ afterEach(() => {
170
+ broadcasts.length = 0;
171
+ deleteConversation(CONV);
172
+ });
173
+
174
+ test("force-clears and drains when no live controller can be aborted", () => {
175
+ const turn = registerLatchedTurn();
176
+
177
+ expect(steerToMessage(CONV, "req-steer")).toEqual({ steered: true });
178
+
179
+ // Without the force-clear the promoted message would sit behind a flag
180
+ // nothing is going to release.
181
+ expect(turn.cleared()).toBe(true);
182
+ expect(turn.drainReasons).toEqual(["loop_complete"]);
183
+ // The drain consumes the repair flag, so it must survive the force-clear.
184
+ expect(turn.pendingSteerRepair()).toBe(true);
185
+ expect(broadcasts).toEqual([
186
+ { type: "message_steered", conversationId: CONV, requestId: "req-steer" },
187
+ ]);
188
+ });
189
+ });
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Authorization for steering to a queued message.
3
+ *
4
+ * Steering aborts the in-flight generation and promotes the named queued
5
+ * message to the head of the queue, so it is scoped to the actor principal
6
+ * that enqueued the message the same way deletion is: every subscriber sees
7
+ * every `message_queued` ack, so requestIds are not secrets and cannot stand
8
+ * in for authorization. The caller identity is normalized exactly as the send
9
+ * path normalizes it before recording `sourceActorPrincipalId`.
10
+ */
11
+ import { afterEach, describe, expect, test } from "bun:test";
12
+
13
+ import {
14
+ MessageQueue,
15
+ type QueuedMessage,
16
+ } from "../daemon/conversation-queue-manager.js";
17
+ import {
18
+ deleteConversation,
19
+ setConversation,
20
+ } from "../daemon/conversation-registry.js";
21
+ import { ROUTES } from "../runtime/routes/conversation-query-routes.js";
22
+
23
+ const steerRoute = ROUTES.find(
24
+ (route) => route.operationId === "messages_queued_steer",
25
+ )!;
26
+
27
+ const registered: string[] = [];
28
+
29
+ interface QueuedFixture {
30
+ requestId: string;
31
+ sourceActorPrincipalId?: string;
32
+ }
33
+
34
+ /**
35
+ * Register a live, mid-turn conversation holding `items`. The steer path
36
+ * reads the in-memory registry and touches no persistence, so a queue-only
37
+ * stand-in exercises the real code.
38
+ */
39
+ function seedProcessingConversation(
40
+ conversationId: string,
41
+ items: QueuedFixture[],
42
+ ): { queue: MessageQueue; aborted: () => boolean } {
43
+ const queue = new MessageQueue();
44
+ for (const item of items) {
45
+ queue.push({
46
+ content: `content for ${item.requestId}`,
47
+ attachments: [],
48
+ requestId: item.requestId,
49
+ onEvent: () => {},
50
+ sentAt: Date.now(),
51
+ sourceActorPrincipalId: item.sourceActorPrincipalId,
52
+ } as QueuedMessage);
53
+ }
54
+ const abortController = new AbortController();
55
+ const conversation = {
56
+ conversationId,
57
+ queue,
58
+ isProcessing: () => true,
59
+ pendingSteerRepair: false,
60
+ abortController,
61
+ denyAllPendingConfirmations: () => {},
62
+ };
63
+ setConversation(conversationId, conversation as never);
64
+ registered.push(conversationId);
65
+ return { queue, aborted: () => abortController.signal.aborted };
66
+ }
67
+
68
+ function dispatchSteer(args: {
69
+ conversationId: string;
70
+ requestId: string;
71
+ actorPrincipalId?: string;
72
+ }) {
73
+ return Promise.resolve(
74
+ steerRoute.handler({
75
+ pathParams: { id: args.requestId },
76
+ queryParams: { conversationId: args.conversationId },
77
+ headers:
78
+ args.actorPrincipalId !== undefined
79
+ ? { "x-vellum-actor-principal-id": args.actorPrincipalId }
80
+ : {},
81
+ }),
82
+ );
83
+ }
84
+
85
+ afterEach(() => {
86
+ for (const conversationId of registered.splice(0)) {
87
+ deleteConversation(conversationId);
88
+ }
89
+ delete process.env.DISABLE_HTTP_AUTH;
90
+ });
91
+
92
+ describe("queued message steer: actor scoping", () => {
93
+ test("a different actor principal cannot steer to someone else's queued message", async () => {
94
+ const { queue, aborted } = seedProcessingConversation("conv-steer-1", [
95
+ { requestId: "r-head", sourceActorPrincipalId: "actor-owner" },
96
+ { requestId: "r-target", sourceActorPrincipalId: "actor-owner" },
97
+ ]);
98
+
99
+ await expect(
100
+ dispatchSteer({
101
+ conversationId: "conv-steer-1",
102
+ requestId: "r-target",
103
+ actorPrincipalId: "actor-bystander",
104
+ }),
105
+ ).rejects.toThrow("sent by a different user");
106
+
107
+ // The queue order is untouched and the live generation kept running.
108
+ expect(queue.peek(0)?.requestId).toBe("r-head");
109
+ expect(aborted()).toBe(false);
110
+ });
111
+
112
+ test("the enqueuing actor principal can steer to its own queued message", async () => {
113
+ const { queue, aborted } = seedProcessingConversation("conv-steer-2", [
114
+ { requestId: "r-head", sourceActorPrincipalId: "actor-owner" },
115
+ { requestId: "r-target", sourceActorPrincipalId: "actor-owner" },
116
+ ]);
117
+
118
+ expect(
119
+ await dispatchSteer({
120
+ conversationId: "conv-steer-2",
121
+ requestId: "r-target",
122
+ actorPrincipalId: "actor-owner",
123
+ }),
124
+ ).toEqual({
125
+ ok: true,
126
+ conversationId: "conv-steer-2",
127
+ requestId: "r-target",
128
+ });
129
+
130
+ expect(queue.peek(0)?.requestId).toBe("r-target");
131
+ expect(aborted()).toBe(true);
132
+ });
133
+
134
+ test("a caller with no actor principal is the guardian by construction", async () => {
135
+ const { queue } = seedProcessingConversation("conv-steer-3", [
136
+ { requestId: "r-head", sourceActorPrincipalId: "actor-owner" },
137
+ { requestId: "r-target", sourceActorPrincipalId: "actor-owner" },
138
+ ]);
139
+
140
+ // Local/IPC and service principals carry no actorPrincipalId; the CLI
141
+ // must keep being able to steer.
142
+ await dispatchSteer({
143
+ conversationId: "conv-steer-3",
144
+ requestId: "r-target",
145
+ });
146
+
147
+ expect(queue.peek(0)?.requestId).toBe("r-target");
148
+ });
149
+
150
+ test("a daemon-internal enqueue with no recorded requester stays steerable", async () => {
151
+ const { queue } = seedProcessingConversation("conv-steer-4", [
152
+ { requestId: "r-head" },
153
+ { requestId: "r-target" },
154
+ ]);
155
+
156
+ await dispatchSteer({
157
+ conversationId: "conv-steer-4",
158
+ requestId: "r-target",
159
+ actorPrincipalId: "actor-anyone",
160
+ });
161
+
162
+ expect(queue.peek(0)?.requestId).toBe("r-target");
163
+ });
164
+ });
@@ -78,6 +78,26 @@ describe("mapChatTypeToConversationType", () => {
78
78
  test("maps DM-shaped chat types to dm", () => {
79
79
  expect(mapChatTypeToConversationType("im")).toBe("dm"); // Slack DM
80
80
  expect(mapChatTypeToConversationType("private")).toBe("dm"); // Telegram DM
81
+ expect(mapChatTypeToConversationType("dm")).toBe("dm"); // Discord DM
82
+ });
83
+
84
+ test("every DM-capable channel's own word for a DM lands on the axis", () => {
85
+ // A missing arm is silent rather than loud: the permission cell stays
86
+ // settable, because the adapter validates against the channel registry,
87
+ // and simply never matches. The guardian sets a rule for DMs on that
88
+ // channel and it does nothing. Stated as a sweep so adding a DM-capable
89
+ // channel without its arm fails here.
90
+ const dmChatTypeByChannel = {
91
+ slack: "im",
92
+ telegram: "private",
93
+ whatsapp: "private",
94
+ discord: "dm",
95
+ };
96
+ for (const [channel, chatType] of Object.entries(dmChatTypeByChannel)) {
97
+ expect(`${channel}:${mapChatTypeToConversationType(chatType)}`).toBe(
98
+ `${channel}:dm`,
99
+ );
100
+ }
81
101
  });
82
102
 
83
103
  test("maps closed-group chat types to private", () => {
@@ -52,7 +52,7 @@ mock.module("../daemon/conversation-store.js", () => ({
52
52
  | "background",
53
53
  });
54
54
  } else {
55
- ensureConversationExists(conversationId);
55
+ ensureConversationExists(conversationId, "vellum");
56
56
  }
57
57
  }
58
58
  return {
@@ -5,6 +5,8 @@
5
5
  * sequences.
6
6
  */
7
7
 
8
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
9
+ import { join } from "node:path";
8
10
  import { beforeEach, describe, expect, mock, test } from "bun:test";
9
11
 
10
12
  mock.module("../background-wake/publisher.js", () => ({
@@ -58,8 +60,11 @@ import { initializeDb } from "../persistence/db-init.js";
58
60
  import {
59
61
  createSchedule,
60
62
  deferClaimedSchedule,
63
+ upsertDeclaredSchedule,
61
64
  } from "../schedule/schedule-store.js";
62
65
  import { runDueSchedulesOnce } from "../schedule/scheduler.js";
66
+ import { getWorkspacePluginsDir } from "../util/platform.js";
67
+ import { setOverridesForTesting } from "./feature-flag-test-helpers.js";
63
68
 
64
69
  await initializeDb();
65
70
 
@@ -217,3 +222,172 @@ describe("runDueSchedulesOnce (the schedule worker's tick)", () => {
217
222
  expect(row.next_run_at).toBeGreaterThan(Date.now());
218
223
  });
219
224
  });
225
+
226
+ describe("fire-time source-availability gate", () => {
227
+ const PLUGIN_NAME = "example-plugin";
228
+ const SCHEDULE_NAME = "daily-digest";
229
+ const SOURCE_KEY = `plugin:${PLUGIN_NAME}/${SCHEDULE_NAME}`;
230
+ const pluginDir = join(getWorkspacePluginsDir(), PLUGIN_NAME);
231
+ const declarationDir = join(pluginDir, "schedules", SCHEDULE_NAME);
232
+ const manifest = join(pluginDir, "package.json");
233
+ // The marker lives outside the plugin directory so the uninstall case still
234
+ // proves the script never ran: a `touch` into a deleted tree would fail on
235
+ // its own and hide a guard that let the row through.
236
+ const marker = join(getWorkspacePluginsDir(), "ran.txt");
237
+
238
+ // The gate probes the declaration's on-disk presence and its plugin's
239
+ // manifest, so the healthy fixture is a full plugin: a valid package.json
240
+ // and a schedules/<name>/ declaration directory.
241
+ beforeEach(() => {
242
+ rmSync(pluginDir, { recursive: true, force: true });
243
+ rmSync(marker, { force: true });
244
+ mkdirSync(declarationDir, { recursive: true });
245
+ writeFileSync(
246
+ join(declarationDir, "config.json"),
247
+ JSON.stringify({ expression: "* * * * *" }),
248
+ );
249
+ writeFileSync(join(declarationDir, "index.sh"), "#!/bin/sh\ntrue\n");
250
+ writeFileSync(
251
+ manifest,
252
+ JSON.stringify({ name: PLUGIN_NAME, version: "1.0.0" }),
253
+ );
254
+ // The feature ships off, so the healthy-plugin cases below need it on.
255
+ setOverridesForTesting({ "plugin-schedules": true });
256
+ });
257
+
258
+ function skipRunsFor(jobId: string): Array<{
259
+ status: string;
260
+ error: string | null;
261
+ }> {
262
+ return rawDb()
263
+ .query("SELECT status, error FROM cron_runs WHERE job_id = ?")
264
+ .all(jobId) as Array<{ status: string; error: string | null }>;
265
+ }
266
+
267
+ /** A due plugin-sourced script row whose script leaves a marker when it runs. */
268
+ async function seedDueSourcedScript() {
269
+ const job = await upsertDeclaredSchedule(SOURCE_KEY, {
270
+ name: "Daily digest",
271
+ syntax: "cron",
272
+ expression: "* * * * *",
273
+ timezone: null,
274
+ message: "",
275
+ script: `touch ${marker}`,
276
+ mode: "script",
277
+ inferenceProfile: null,
278
+ timeoutMs: null,
279
+ enabled: true,
280
+ definitionHash: "hash-1",
281
+ });
282
+ rawDb().run("UPDATE cron_jobs SET next_run_at = ? WHERE id = ?", [
283
+ Date.now() - 1000,
284
+ job.id,
285
+ ]);
286
+ return job;
287
+ }
288
+
289
+ test("does not execute a due sourced row whose plugin is disabled", async () => {
290
+ const job = await seedDueSourcedScript();
291
+ writeFileSync(join(pluginDir, ".disabled"), "");
292
+
293
+ const result = await runDueSchedulesOnce();
294
+
295
+ expect(result.claimed).toBe(1);
296
+ expect(result.skipped).toBe(1);
297
+ expect(result.completed).toBe(0);
298
+ expect(existsSync(marker)).toBe(false);
299
+ // The skip is recorded so it stays visible in the schedule's run history.
300
+ const runs = skipRunsFor(job.id);
301
+ expect(runs).toHaveLength(1);
302
+ expect(runs[0].status).toBe("error");
303
+ expect(runs[0].error).toContain("no longer declares this schedule");
304
+ });
305
+
306
+ test("does not execute a due sourced row whose plugin directory is gone", async () => {
307
+ const job = await seedDueSourcedScript();
308
+ // A local CLI uninstall removes the directory outright, with no daemon
309
+ // call to disarm the row first.
310
+ rmSync(pluginDir, { recursive: true, force: true });
311
+
312
+ const result = await runDueSchedulesOnce();
313
+
314
+ expect(result.claimed).toBe(1);
315
+ expect(result.skipped).toBe(1);
316
+ expect(result.completed).toBe(0);
317
+ expect(existsSync(marker)).toBe(false);
318
+ expect(skipRunsFor(job.id)).toHaveLength(1);
319
+ });
320
+
321
+ test("does not execute a due sourced row whose manifest no longer parses", async () => {
322
+ const job = await seedDueSourcedScript();
323
+ writeFileSync(manifest, "{ broken");
324
+
325
+ const result = await runDueSchedulesOnce();
326
+
327
+ expect(result.claimed).toBe(1);
328
+ expect(result.skipped).toBe(1);
329
+ expect(result.completed).toBe(0);
330
+ expect(existsSync(marker)).toBe(false);
331
+ expect(skipRunsFor(job.id)).toHaveLength(1);
332
+ });
333
+
334
+ test("does not execute a due sourced row whose declaration is gone", async () => {
335
+ const job = await seedDueSourcedScript();
336
+ rmSync(declarationDir, { recursive: true, force: true });
337
+
338
+ const result = await runDueSchedulesOnce();
339
+
340
+ expect(result.skipped).toBe(1);
341
+ expect(existsSync(marker)).toBe(false);
342
+ expect(skipRunsFor(job.id)).toHaveLength(1);
343
+ });
344
+
345
+ test("does not execute a due sourced row while the feature flag is off", async () => {
346
+ const job = await seedDueSourcedScript();
347
+ setOverridesForTesting({ "plugin-schedules": false });
348
+
349
+ const result = await runDueSchedulesOnce();
350
+
351
+ expect(result.claimed).toBe(1);
352
+ expect(result.skipped).toBe(1);
353
+ expect(result.completed).toBe(0);
354
+ expect(existsSync(marker)).toBe(false);
355
+ const runs = skipRunsFor(job.id);
356
+ expect(runs).toHaveLength(1);
357
+ expect(runs[0].status).toBe("error");
358
+ expect(runs[0].error).toContain("no longer declares this schedule");
359
+ });
360
+
361
+ test("a skip spends no retry budget and keeps the row on its normal cadence", async () => {
362
+ const job = await seedDueSourcedScript();
363
+ // A non-zero starting budget proves the counter is left alone rather than
364
+ // merely still reading zero.
365
+ rawDb().run("UPDATE cron_jobs SET retry_count = 2 WHERE id = ?", [job.id]);
366
+ writeFileSync(join(pluginDir, ".disabled"), "");
367
+
368
+ await runDueSchedulesOnce();
369
+
370
+ const row = rawDb()
371
+ .query("SELECT retry_count, next_run_at FROM cron_jobs WHERE id = ?")
372
+ .get(job.id) as { retry_count: number; next_run_at: number };
373
+ expect(row.retry_count).toBe(2);
374
+ // The next occurrence of `* * * * *` is at most a minute out. A retry at
375
+ // this budget would have pushed it minutes further on backoff.
376
+ expect(row.next_run_at).toBeGreaterThan(Date.now());
377
+ expect(row.next_run_at).toBeLessThanOrEqual(Date.now() + 61_000);
378
+ });
379
+
380
+ test("executes a due sourced row whose plugin is enabled", async () => {
381
+ const job = await seedDueSourcedScript();
382
+
383
+ const result = await runDueSchedulesOnce();
384
+
385
+ expect(result.completed).toBe(1);
386
+ expect(existsSync(marker)).toBe(true);
387
+ const runs = rawDb()
388
+ .query("SELECT status FROM cron_runs WHERE job_id = ?")
389
+ .all(job.id) as Array<{ status: string }>;
390
+ expect(runs).toHaveLength(1);
391
+ expect(runs[0].status).toBe("ok");
392
+ });
393
+ });
@@ -97,7 +97,7 @@ describe("Runtime attachment metadata", () => {
97
97
  );
98
98
 
99
99
  // Upload and link an attachment using "self" as the assistantId
100
- const stored = uploadAttachment("chart.png", "image/png", "iVBORw==");
100
+ const stored = await uploadAttachment("chart.png", "image/png", "iVBORw==");
101
101
  linkAttachmentToMessage(assistantMsg.id, stored.id, 0);
102
102
 
103
103
  const res = await fetch(
@@ -162,7 +162,7 @@ describe("Runtime attachment metadata", () => {
162
162
  });
163
163
 
164
164
  test("GET /attachments/:id returns attachment with payload", async () => {
165
- const stored = uploadAttachment(
165
+ const stored = await uploadAttachment(
166
166
  "report.pdf",
167
167
  "application/pdf",
168
168
  "JVBERA==",
@@ -191,7 +191,11 @@ describe("Runtime attachment metadata", () => {
191
191
  });
192
192
 
193
193
  test('GET /attachments/:id returns attachment stored under "self"', async () => {
194
- const stored = uploadAttachment("shared.txt", "text/plain", "c2hhcmVk");
194
+ const stored = await uploadAttachment(
195
+ "shared.txt",
196
+ "text/plain",
197
+ "c2hhcmVk",
198
+ );
195
199
 
196
200
  const res = await fetch(
197
201
  `http://127.0.0.1:${port}/v1/attachments/${stored.id}`,
@@ -303,12 +307,16 @@ describe("WhatsApp channel ingress attachment resolution", () => {
303
307
  test("inbound handler accepts request with valid gateway-uploaded attachment IDs", async () => {
304
308
  // Simulate what the gateway does: upload attachments then forward the
305
309
  // inbound event with attachmentIds. The handler must resolve them.
306
- const img = uploadAttachment(
310
+ const img = await uploadAttachment(
307
311
  "whatsapp-photo.jpg",
308
312
  "image/jpeg",
309
313
  "/9j/4AAQ",
310
314
  );
311
- const doc = uploadAttachment("receipt.pdf", "application/pdf", "JVBERi0x");
315
+ const doc = await uploadAttachment(
316
+ "receipt.pdf",
317
+ "application/pdf",
318
+ "JVBERi0x",
319
+ );
312
320
 
313
321
  const res = await fetch(
314
322
  `http://127.0.0.1:${ingressPort}/v1/channels/inbound`,
@@ -329,7 +337,7 @@ describe("WhatsApp channel ingress attachment resolution", () => {
329
337
  test("inbound handler rejects request when some attachment IDs are missing", async () => {
330
338
  // When the gateway fails to upload one attachment, the handler detects
331
339
  // the missing ID and returns a 400.
332
- const valid = uploadAttachment("ok.jpg", "image/jpeg", "base64ok");
340
+ const valid = await uploadAttachment("ok.jpg", "image/jpeg", "base64ok");
333
341
 
334
342
  const res = await fetch(
335
343
  `http://127.0.0.1:${ingressPort}/v1/channels/inbound`,
@@ -355,7 +363,7 @@ describe("WhatsApp channel ingress attachment resolution", () => {
355
363
 
356
364
  test("inbound handler accepts attachment-only message with no text content", async () => {
357
365
  // WhatsApp allows sending images/documents without caption text.
358
- const img = uploadAttachment("photo.jpg", "image/jpeg", "/9j/4AAQ");
366
+ const img = await uploadAttachment("photo.jpg", "image/jpeg", "/9j/4AAQ");
359
367
 
360
368
  const res = await fetch(
361
369
  `http://127.0.0.1:${ingressPort}/v1/channels/inbound`,