@vellumai/assistant 0.12.2 → 0.12.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 (772) hide show
  1. package/.env.example +2 -0
  2. package/AGENTS.md +1 -1
  3. package/ARCHITECTURE.md +43 -29
  4. package/Dockerfile +63 -0
  5. package/docs/architecture/integrations.md +7 -0
  6. package/docs/architecture/memory.md +17 -2
  7. package/docs/architecture/security.md +10 -5
  8. package/docs/architecture/turn-actor.md +2 -0
  9. package/docs/credential-execution-service.md +1 -1
  10. package/docs/desktop-browser-cli.md +50 -5
  11. package/docs/live-voice-task-outcomes.md +100 -0
  12. package/docs/mode-sessions.md +183 -0
  13. package/docs/voice-input-diagnostics.md +58 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  19. package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
  20. package/node_modules/@vellumai/environments/src/shell.ts +24 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  25. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  26. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
  28. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  29. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  30. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  31. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  32. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  33. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  34. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  35. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  36. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  37. package/openapi.yaml +716 -16
  38. package/package.json +1 -1
  39. package/scripts/smoke-desktop-browser-cli.ts +11 -26
  40. package/scripts/smoke-desktop-window-theme.ts +2 -3
  41. package/scripts/sync-llm-catalog.ts +3 -0
  42. package/scripts/voice-ttft-spike.ts +2 -2
  43. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  44. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  45. package/src/__tests__/agent-loop.test.ts +259 -0
  46. package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
  47. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  48. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  49. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  50. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  51. package/src/__tests__/anthropic-provider.test.ts +55 -0
  52. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  53. package/src/__tests__/approval-message-composer.test.ts +1 -118
  54. package/src/__tests__/approval-routes-http.test.ts +3 -0
  55. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  56. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  57. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  58. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  59. package/src/__tests__/attachments-store.test.ts +22 -3
  60. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  61. package/src/__tests__/btw-routes.test.ts +4 -1
  62. package/src/__tests__/build-persisted-content.test.ts +1 -1
  63. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  64. package/src/__tests__/call-recovery.test.ts +7 -2
  65. package/src/__tests__/call-routes-http.test.ts +12 -0
  66. package/src/__tests__/call-store.test.ts +7 -2
  67. package/src/__tests__/channel-approval.test.ts +9 -14
  68. package/src/__tests__/channel-reply-delivery.test.ts +56 -0
  69. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  70. package/src/__tests__/chat-credential-redaction.test.ts +23 -0
  71. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  72. package/src/__tests__/checker.test.ts +11 -3
  73. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  74. package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
  75. package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
  76. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  77. package/src/__tests__/computer-use-tools.test.ts +1 -233
  78. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  79. package/src/__tests__/config-schema.test.ts +16 -0
  80. package/src/__tests__/config-watcher.test.ts +24 -0
  81. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  82. package/src/__tests__/context-search-fanout.test.ts +1 -1
  83. package/src/__tests__/context-search-types.test.ts +7 -7
  84. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  85. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  86. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  87. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  88. package/src/__tests__/conversation-agent-loop.test.ts +797 -16
  89. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  90. package/src/__tests__/conversation-attachments.test.ts +106 -0
  91. package/src/__tests__/conversation-evictor.test.ts +62 -37
  92. package/src/__tests__/conversation-fork-crud.test.ts +191 -0
  93. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  94. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  96. package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
  97. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  99. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  100. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  101. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  102. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  103. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  104. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  105. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  106. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  107. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  108. package/src/__tests__/conversation-undo.test.ts +61 -0
  109. package/src/__tests__/credential-execution-client.test.ts +72 -55
  110. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  111. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  112. package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
  113. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  114. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  115. package/src/__tests__/dm-backfill.test.ts +91 -1
  116. package/src/__tests__/document-create-route.test.ts +88 -0
  117. package/src/__tests__/document-sync-tags.test.ts +27 -0
  118. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  119. package/src/__tests__/events-tail-route.test.ts +58 -0
  120. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  121. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  122. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  123. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  124. package/src/__tests__/heartbeat-service.test.ts +2 -59
  125. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  126. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  127. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  128. package/src/__tests__/history-repair.test.ts +53 -0
  129. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  130. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  131. package/src/__tests__/image-credentials.test.ts +49 -0
  132. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  133. package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
  134. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  135. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  136. package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
  137. package/src/__tests__/llm-catalog-parity.test.ts +27 -4
  138. package/src/__tests__/media-generate-image.test.ts +49 -1
  139. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  140. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  141. package/src/__tests__/mode-session-history.test.ts +245 -0
  142. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  143. package/src/__tests__/mode-session-wire.test.ts +141 -0
  144. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  145. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  146. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  147. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  148. package/src/__tests__/oauth-commands-routes.test.ts +114 -101
  149. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  150. package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
  151. package/src/__tests__/oauth-providers-routes.test.ts +3 -0
  152. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  153. package/src/__tests__/persist-media-references.test.ts +50 -0
  154. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  155. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  156. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  157. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
  158. package/src/__tests__/process-message-display-content.test.ts +56 -0
  159. package/src/__tests__/reaction-persistence.test.ts +5 -0
  160. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  161. package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
  162. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  163. package/src/__tests__/schedule-routes.test.ts +20 -0
  164. package/src/__tests__/scheduler-result-notification.test.ts +23 -4
  165. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  166. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  167. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  168. package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
  169. package/src/__tests__/secret-routes-scrub.test.ts +22 -27
  170. package/src/__tests__/secret-scanner.test.ts +20 -0
  171. package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
  172. package/src/__tests__/secure-keys.test.ts +50 -4
  173. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  174. package/src/__tests__/server-history-render.test.ts +91 -1
  175. package/src/__tests__/server-tool-pairing.test.ts +107 -0
  176. package/src/__tests__/settings-routes.test.ts +50 -1
  177. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  178. package/src/__tests__/skills.test.ts +5 -4
  179. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  180. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  181. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  182. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
  184. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  185. package/src/__tests__/terminal-tools.test.ts +8 -0
  186. package/src/__tests__/thread-backfill.test.ts +53 -0
  187. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  188. package/src/__tests__/tool-result-follow-up.test.ts +99 -0
  189. package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
  190. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  191. package/src/__tests__/twilio-routes.test.ts +1 -0
  192. package/src/__tests__/unicode.test.ts +36 -0
  193. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  194. package/src/activation/progress-store.test.ts +12 -7
  195. package/src/agent/loop.ts +136 -53
  196. package/src/agent/tool-result-follow-up.ts +70 -0
  197. package/src/api/attachment-provenance.test.ts +68 -0
  198. package/src/api/computer-use-tool.test.ts +55 -0
  199. package/src/api/computer-use-tool.ts +27 -0
  200. package/src/api/events/assistant-outbound-attachment.ts +3 -0
  201. package/src/api/events/assistant-turn-start.ts +3 -0
  202. package/src/api/events/desktop-activity-changed.ts +10 -0
  203. package/src/api/events/generation-handoff.ts +2 -0
  204. package/src/api/events/message-complete.ts +2 -0
  205. package/src/api/events/notification-conversation-created.ts +14 -16
  206. package/src/api/events/notification-intent.ts +4 -2
  207. package/src/api/events/question-request.ts +1 -0
  208. package/src/api/events/tool-result.ts +85 -0
  209. package/src/api/events/tool-use-start.ts +3 -0
  210. package/src/api/events/user-message-echo.ts +3 -0
  211. package/src/api/index.ts +42 -6
  212. package/src/api/mode-session.test.ts +131 -0
  213. package/src/api/mode-session.ts +148 -0
  214. package/src/api/remember-tool.ts +15 -0
  215. package/src/api/responses/conversation-message.ts +9 -0
  216. package/src/approvals/AGENTS.md +4 -2
  217. package/src/approvals/approval-primitive.ts +5 -2
  218. package/src/approvals/scoped-approval-grants.ts +6 -2
  219. package/src/browser/__tests__/operations.test.ts +29 -0
  220. package/src/browser/operation-meta.ts +2 -1
  221. package/src/browser/operations.ts +29 -0
  222. package/src/browser/virtual-desktop-target.ts +2 -9
  223. package/src/bundler/bundle-signer.ts +1 -3
  224. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  225. package/src/calls/__tests__/call-controller.test.ts +94 -0
  226. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  227. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  228. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  229. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  230. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  231. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  232. package/src/calls/barge-in-guard.ts +5 -0
  233. package/src/calls/call-controller.ts +196 -1
  234. package/src/calls/call-domain.ts +4 -0
  235. package/src/calls/call-store.ts +87 -2
  236. package/src/calls/guardian-action-sweep.ts +22 -8
  237. package/src/calls/media-stream-audio-transcode.ts +1 -3
  238. package/src/calls/typesafe-noul.ts +156 -0
  239. package/src/calls/voice-control-protocol.ts +6 -0
  240. package/src/calls/voice-escalation-judge.ts +145 -0
  241. package/src/calls/voice-escalation-target.ts +10 -0
  242. package/src/calls/voice-leg-coordinator.ts +121 -3
  243. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  244. package/src/calls/voice-session-bridge.ts +256 -112
  245. package/src/calls/voice-triage-escalate.ts +7 -0
  246. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  247. package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
  248. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  249. package/src/cli/commands/__tests__/plugins.test.ts +20 -1
  250. package/src/cli/commands/__tests__/schedules.test.ts +14 -0
  251. package/src/cli/commands/bash.help.ts +4 -3
  252. package/src/cli/commands/browser.help.ts +9 -6
  253. package/src/cli/commands/browser.ts +0 -1
  254. package/src/cli/commands/clients.help.ts +46 -0
  255. package/src/cli/commands/clients.ts +116 -0
  256. package/src/cli/commands/credentials.help.ts +9 -4
  257. package/src/cli/commands/notifications.help.ts +16 -2
  258. package/src/cli/commands/notifications.ts +30 -8
  259. package/src/cli/commands/oauth/index.help.ts +10 -0
  260. package/src/cli/commands/oauth/providers.ts +12 -0
  261. package/src/cli/commands/oauth/request.test.ts +179 -2
  262. package/src/cli/commands/oauth/request.ts +41 -10
  263. package/src/cli/commands/plugins.ts +12 -5
  264. package/src/cli/commands/roadmap.help.ts +18 -21
  265. package/src/cli/commands/roadmap.ts +4 -21
  266. package/src/cli/commands/schedules.ts +2 -0
  267. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  268. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
  269. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  270. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
  271. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
  272. package/src/cli/lib/bundled-marketplace.json +906 -1
  273. package/src/cli/lib/bundled-plugin-packages.json +783 -1
  274. package/src/cli/lib/inspect-plugin.ts +11 -4
  275. package/src/cli/lib/plugin-marketplace.ts +8 -0
  276. package/src/cli/lib/publish-plugin.ts +1 -2
  277. package/src/cli/lib/upgrade-plugin.ts +19 -11
  278. package/src/cli/output.ts +18 -4
  279. package/src/config/__tests__/default-provider.test.ts +6 -0
  280. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  281. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  282. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  283. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  284. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  285. package/src/config/bundled-skills/schedule/SKILL.md +6 -6
  286. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  287. package/src/config/call-site-defaults.ts +9 -0
  288. package/src/config/feature-flag-registry.json +16 -0
  289. package/src/config/loader.ts +9 -17
  290. package/src/config/platform-identity.ts +8 -8
  291. package/src/config/profile-text-generation.test.ts +51 -0
  292. package/src/config/profile-text-generation.ts +51 -0
  293. package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
  294. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  295. package/src/config/schemas/call-site-catalog.ts +14 -0
  296. package/src/config/schemas/channels.ts +0 -18
  297. package/src/config/schemas/llm.ts +9 -2
  298. package/src/config/schemas/mcp.ts +6 -1
  299. package/src/config/schemas/memory-retrospective.ts +11 -2
  300. package/src/config/schemas/memory-v3.ts +12 -0
  301. package/src/config/schemas/services.ts +15 -6
  302. package/src/config/schemas/tools.ts +10 -0
  303. package/src/config/session-groups-gate.ts +21 -0
  304. package/src/config/skills.ts +2 -6
  305. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  306. package/src/conversations/message-consolidation.ts +102 -5
  307. package/src/credential-execution/ces-connect.test.ts +69 -0
  308. package/src/credential-execution/ces-connect.ts +115 -0
  309. package/src/credential-execution/ces-runtime.ts +55 -93
  310. package/src/credential-execution/executable-discovery.ts +34 -142
  311. package/src/credential-execution/process-manager.test.ts +20 -24
  312. package/src/credential-execution/process-manager.ts +24 -19
  313. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  314. package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
  315. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  316. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
  317. package/src/daemon/assistant-attachments.ts +20 -12
  318. package/src/daemon/browser-mode-session.test.ts +402 -0
  319. package/src/daemon/browser-mode-session.ts +186 -0
  320. package/src/daemon/chat-credential-redaction.ts +16 -1
  321. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  322. package/src/daemon/computer-use-mode-session.ts +105 -0
  323. package/src/daemon/config-watcher.ts +10 -0
  324. package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
  325. package/src/daemon/conversation-agent-loop.ts +231 -25
  326. package/src/daemon/conversation-attachments.ts +93 -12
  327. package/src/daemon/conversation-evictor.ts +5 -24
  328. package/src/daemon/conversation-history.ts +10 -0
  329. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  330. package/src/daemon/conversation-interrupt.ts +7 -11
  331. package/src/daemon/conversation-messaging.ts +58 -5
  332. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  333. package/src/daemon/conversation-mode-session.ts +1008 -0
  334. package/src/daemon/conversation-process.ts +5 -0
  335. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  336. package/src/daemon/conversation-skill-tools.ts +1 -0
  337. package/src/daemon/conversation-store.ts +4 -4
  338. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  339. package/src/daemon/conversation-surfaces.ts +113 -5
  340. package/src/daemon/conversation-tool-setup.ts +79 -6
  341. package/src/daemon/conversation-turn-finalize.ts +26 -13
  342. package/src/daemon/conversation.ts +215 -58
  343. package/src/daemon/daemon-control.ts +3 -7
  344. package/src/daemon/handlers/config-model.ts +7 -5
  345. package/src/daemon/handlers/shared.ts +55 -16
  346. package/src/daemon/host-cu-proxy.ts +51 -22
  347. package/src/daemon/lifecycle.ts +30 -13
  348. package/src/daemon/mcp-reload-service.ts +1 -1
  349. package/src/daemon/message-protocol.ts +0 -1
  350. package/src/daemon/message-provenance.ts +28 -4
  351. package/src/daemon/message-types/shared.ts +1 -0
  352. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  353. package/src/daemon/mode-session-tracking.ts +54 -0
  354. package/src/daemon/orphan-reaper.ts +4 -3
  355. package/src/daemon/persist-media-references.ts +20 -3
  356. package/src/daemon/process-message.ts +13 -4
  357. package/src/daemon/tool-setup-types.ts +6 -0
  358. package/src/daemon/virtual-desktop-context.ts +21 -0
  359. package/src/daemon/wake-conversation-ops.ts +50 -15
  360. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  361. package/src/desktop/desktop-accessibility-script.ts +88 -0
  362. package/src/desktop/desktop-accessibility.test.ts +160 -0
  363. package/src/desktop/desktop-accessibility.ts +169 -0
  364. package/src/desktop/desktop-automation-lease.test.ts +302 -64
  365. package/src/desktop/desktop-automation-lease.ts +129 -54
  366. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  367. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  368. package/src/desktop/desktop-computer-use.test.ts +449 -0
  369. package/src/desktop/desktop-computer-use.ts +502 -0
  370. package/src/desktop/desktop-dependencies.ts +47 -293
  371. package/src/desktop/desktop-display.ts +2 -2
  372. package/src/desktop/desktop-help.ts +15 -0
  373. package/src/desktop/desktop-panel-config.test.ts +13 -3
  374. package/src/desktop/desktop-panel-config.ts +109 -15
  375. package/src/desktop/desktop-session-manager.test.ts +69 -21
  376. package/src/desktop/desktop-session-manager.ts +76 -22
  377. package/src/desktop/desktop-stream-bridge.test.ts +76 -132
  378. package/src/desktop/desktop-stream-bridge.ts +9 -11
  379. package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
  380. package/src/desktop/desktop-wallpaper-worker.ts +17 -0
  381. package/src/desktop/desktop-wallpaper.test.ts +48 -7
  382. package/src/desktop/desktop-wallpaper.ts +34 -102
  383. package/src/desktop/desktop-window-theme.ts +5 -25
  384. package/src/desktop/virtual-desktop-feature.ts +53 -3
  385. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  386. package/src/documents/document-store.ts +23 -0
  387. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  388. package/src/heartbeat/heartbeat-service.ts +5 -33
  389. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  390. package/src/ipc/assistant-server.ts +2 -0
  391. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  392. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  393. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  394. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  395. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  396. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  397. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  398. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  399. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  400. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  401. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  402. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  403. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  404. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  405. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  406. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  407. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  408. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  409. package/src/live-voice/camera-mode-session.test.ts +265 -0
  410. package/src/live-voice/camera-mode-session.ts +277 -0
  411. package/src/live-voice/continuation-judge.ts +123 -0
  412. package/src/live-voice/live-activity-reporter.ts +115 -6
  413. package/src/live-voice/live-voice-manager.ts +36 -1
  414. package/src/live-voice/live-voice-photo.ts +88 -7
  415. package/src/live-voice/live-voice-session-manager.ts +15 -0
  416. package/src/live-voice/live-voice-session.ts +1443 -747
  417. package/src/live-voice/live-voice-tts.ts +22 -4
  418. package/src/live-voice/microphone-idle-gate.ts +56 -0
  419. package/src/live-voice/protocol.ts +171 -4
  420. package/src/live-voice/session-controls.ts +11 -3
  421. package/src/live-voice/task-outcomes.ts +131 -0
  422. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  423. package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
  424. package/src/mcp/__tests__/startup.test.ts +30 -7
  425. package/src/mcp/__tests__/tool-caps.test.ts +134 -0
  426. package/src/mcp/manager.ts +171 -101
  427. package/src/mcp/startup.ts +33 -13
  428. package/src/mcp/tool-caps.ts +184 -0
  429. package/src/media/__tests__/image-models.test.ts +58 -0
  430. package/src/media/image-credentials.ts +5 -0
  431. package/src/media/image-models.ts +52 -0
  432. package/src/media/image-service.ts +8 -0
  433. package/src/media/openrouter-image-service.test.ts +133 -0
  434. package/src/media/openrouter-image-service.ts +153 -0
  435. package/src/media/types.ts +1 -1
  436. package/src/messaging/provider-message-metadata.ts +3 -3
  437. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  438. package/src/messaging/providers/discord/send.ts +4 -17
  439. package/src/messaging/providers/discord/transport.ts +2 -2
  440. package/src/messaging/providers/outlook/client.ts +16 -22
  441. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  442. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  443. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  444. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  445. package/src/monitoring/__tests__/control.test.ts +17 -5
  446. package/src/monitoring/control.ts +15 -5
  447. package/src/notifications/AGENTS.md +1 -1
  448. package/src/notifications/README.md +83 -99
  449. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  450. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  451. package/src/notifications/__tests__/copy-composer.test.ts +71 -1
  452. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  453. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  454. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  455. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  456. package/src/notifications/adapters/macos.ts +37 -46
  457. package/src/notifications/broadcaster.ts +5 -6
  458. package/src/notifications/channel-allowlist.ts +44 -0
  459. package/src/notifications/copy-composer.ts +11 -26
  460. package/src/notifications/decision-engine.ts +24 -14
  461. package/src/notifications/deterministic-checks.ts +1 -1
  462. package/src/notifications/emit-signal.ts +123 -37
  463. package/src/notifications/home-feed-side-effect.ts +9 -7
  464. package/src/notifications/notification-utils.ts +19 -0
  465. package/src/notifications/schedule-result-producer.ts +4 -6
  466. package/src/notifications/signal.ts +4 -19
  467. package/src/notifications/types.ts +15 -0
  468. package/src/oauth/AGENTS.md +2 -0
  469. package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
  470. package/src/oauth/connection-resolver.ts +1 -2
  471. package/src/oauth/identity-verifier.ts +24 -0
  472. package/src/oauth/oauth-store.ts +12 -4
  473. package/src/oauth/provider-serializer.ts +8 -0
  474. package/src/oauth/seed-providers.ts +42 -0
  475. package/src/onboarding/onboarding-events-store.ts +99 -12
  476. package/src/permissions/confirmation-guardian-request.test.ts +16 -0
  477. package/src/permissions/confirmation-guardian-request.ts +2 -3
  478. package/src/permissions/question-prompter.test.ts +31 -0
  479. package/src/permissions/question-prompter.ts +2 -0
  480. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  481. package/src/persistence/attachments-store.ts +84 -44
  482. package/src/persistence/client-connection-events-store.ts +377 -0
  483. package/src/persistence/conversation-crud.ts +166 -26
  484. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  485. package/src/persistence/conversation-mode-sessions.ts +460 -0
  486. package/src/persistence/conversation-plugin-facade.ts +30 -0
  487. package/src/persistence/conversation-queries.ts +6 -19
  488. package/src/persistence/conversation-tool-surface.ts +135 -0
  489. package/src/persistence/conversation-types.test.ts +32 -0
  490. package/src/persistence/conversation-types.ts +26 -4
  491. package/src/persistence/llm-usage-store.ts +3 -9
  492. package/src/persistence/message-metadata.ts +25 -0
  493. package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
  494. package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
  495. package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
  496. package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
  497. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
  498. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
  499. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  500. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  501. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  502. package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
  503. package/src/persistence/schema/conversations.ts +67 -0
  504. package/src/persistence/schema/index.ts +1 -0
  505. package/src/persistence/schema/infrastructure.ts +29 -0
  506. package/src/persistence/schema/oauth.ts +1 -0
  507. package/src/persistence/steps.ts +41 -3
  508. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  509. package/src/plugin-api/conversation-turn.ts +31 -7
  510. package/src/plugin-api/effective-context-window.ts +33 -0
  511. package/src/plugin-api/index.ts +35 -6
  512. package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
  513. package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
  514. package/src/plugin-api/plugin-name-env.ts +125 -0
  515. package/src/plugin-api/resolve-credential.ts +79 -20
  516. package/src/plugin-api/vision-support.test.ts +22 -0
  517. package/src/plugin-api/vision-support.ts +17 -5
  518. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  519. package/src/plugins/active-plugin-env.ts +51 -0
  520. package/src/plugins/defaults/index.ts +24 -0
  521. package/src/plugins/defaults/memory/AGENTS.md +39 -5
  522. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  523. package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
  524. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
  525. package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
  526. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
  527. package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
  528. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
  530. package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
  531. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  532. package/src/plugins/defaults/memory/buffer-file.ts +354 -0
  533. package/src/plugins/defaults/memory/buffer-format.ts +40 -0
  534. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  535. package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
  536. package/src/plugins/defaults/memory/context-search/format.ts +53 -8
  537. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  538. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  539. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  540. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  541. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
  542. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
  543. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  544. package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
  545. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  546. package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
  547. package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
  548. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  549. package/src/plugins/defaults/memory/host-utils.ts +0 -10
  550. package/src/plugins/defaults/memory/injectors.ts +4 -3
  551. package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
  552. package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
  553. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  554. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
  555. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  556. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
  557. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
  558. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
  559. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
  560. package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
  561. package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
  562. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
  563. package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
  564. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  565. package/src/plugins/defaults/memory/tools.ts +38 -11
  566. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
  567. package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
  568. package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
  570. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
  571. package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
  572. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
  574. package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
  575. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
  576. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
  578. package/src/plugins/defaults/memory/v3/card.ts +2 -1
  579. package/src/plugins/defaults/memory/v3/injector.ts +212 -178
  580. package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
  581. package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
  582. package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
  583. package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
  584. package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
  585. package/src/plugins/defaults/memory/v3/sections.ts +2 -1
  586. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
  587. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  588. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  589. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  590. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  591. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  592. package/src/plugins/defaults/task-progress/package.json +14 -0
  593. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  594. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  595. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
  596. package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
  597. package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
  598. package/src/prompts/delegation-gate.ts +57 -0
  599. package/src/prompts/system-prompt.ts +14 -32
  600. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  601. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  602. package/src/providers/anthropic/client.ts +10 -1
  603. package/src/providers/anthropic-gateway-shared.ts +6 -0
  604. package/src/providers/fetch-provider-catalog.ts +11 -0
  605. package/src/providers/gemini/client.ts +25 -8
  606. package/src/providers/inference/adapter-factory.ts +6 -0
  607. package/src/providers/jev/client.test.ts +270 -0
  608. package/src/providers/jev/client.ts +534 -0
  609. package/src/providers/model-catalog.ts +59 -3
  610. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  611. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  612. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  613. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  614. package/src/providers/openai/chat-completions-provider.ts +100 -29
  615. package/src/providers/openai/google-thought-signature.ts +0 -6
  616. package/src/providers/openai/responses-provider.ts +23 -1
  617. package/src/providers/ratelimit.ts +1 -3
  618. package/src/providers/search-provider-catalog.ts +24 -0
  619. package/src/providers/server-tool-pairing.ts +16 -7
  620. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  621. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  622. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  623. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  624. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  625. package/src/providers/types.ts +5 -0
  626. package/src/routes/control.ts +7 -5
  627. package/src/runtime/AGENTS.md +6 -4
  628. package/src/runtime/__tests__/agent-wake.test.ts +94 -1
  629. package/src/runtime/actor-trust-resolver.ts +3 -3
  630. package/src/runtime/agent-wake.ts +32 -5
  631. package/src/runtime/approval-message-composer.ts +3 -69
  632. package/src/runtime/assistant-event-hub.ts +73 -75
  633. package/src/runtime/assistant-event-publish-options.ts +7 -0
  634. package/src/runtime/assistant-event-targeting.ts +79 -0
  635. package/src/runtime/assistant-stream-state.ts +13 -100
  636. package/src/runtime/background-job-runner.ts +5 -5
  637. package/src/runtime/channel-retry-sweep.ts +1 -0
  638. package/src/runtime/guardian-action-message-composer.ts +8 -161
  639. package/src/runtime/guardian-action-service.ts +2 -17
  640. package/src/runtime/guardian-reply-router.ts +29 -40
  641. package/src/runtime/http-server.ts +2 -2
  642. package/src/runtime/http-types.ts +6 -0
  643. package/src/runtime/message-composer-types.ts +3 -61
  644. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  645. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
  646. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  647. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  648. package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
  649. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  650. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  651. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  652. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  653. package/src/runtime/pending-interactions.ts +29 -0
  654. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  655. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  656. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
  657. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  658. package/src/runtime/routes/browser-context.ts +31 -11
  659. package/src/runtime/routes/browser-routes.ts +43 -4
  660. package/src/runtime/routes/btw-routes.ts +9 -4
  661. package/src/runtime/routes/channel-route-shared.ts +1 -9
  662. package/src/runtime/routes/client-routes.ts +108 -0
  663. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  664. package/src/runtime/routes/conversation-routes.ts +125 -14
  665. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  666. package/src/runtime/routes/credential-routes.ts +1 -2
  667. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  668. package/src/runtime/routes/desktop-setup-routes.ts +8 -7
  669. package/src/runtime/routes/documents-routes.ts +51 -0
  670. package/src/runtime/routes/email-routes.ts +3 -7
  671. package/src/runtime/routes/events-routes.ts +75 -54
  672. package/src/runtime/routes/guardian-approval-interception.ts +24 -0
  673. package/src/runtime/routes/identity-routes.ts +1 -5
  674. package/src/runtime/routes/image-generation-routes.ts +8 -14
  675. package/src/runtime/routes/inbound-message-handler.ts +37 -41
  676. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  677. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  678. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
  679. package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
  680. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  681. package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
  682. package/src/runtime/routes/inference-profiles-routes.ts +9 -0
  683. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  684. package/src/runtime/routes/migration-routes.ts +73 -2
  685. package/src/runtime/routes/notification-routes.ts +10 -0
  686. package/src/runtime/routes/oauth-commands-routes.ts +57 -54
  687. package/src/runtime/routes/oauth-providers.ts +11 -0
  688. package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
  689. package/src/runtime/routes/oauth-request-hints.ts +149 -0
  690. package/src/runtime/routes/plugins-routes.ts +6 -0
  691. package/src/runtime/routes/roadmap-routes.ts +47 -8
  692. package/src/runtime/routes/schedule-routes.ts +2 -0
  693. package/src/runtime/routes/secret-routes.ts +99 -119
  694. package/src/runtime/routes/settings-routes.ts +10 -4
  695. package/src/runtime/routes/watcher-routes.ts +1 -3
  696. package/src/runtime/trust-class.test.ts +7 -6
  697. package/src/runtime/trust-class.ts +9 -17
  698. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  699. package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
  700. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
  701. package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
  702. package/src/schedule/run-script.ts +2 -2
  703. package/src/schedule/scheduler.ts +47 -11
  704. package/src/schedule/tool-surface-readiness.ts +65 -0
  705. package/src/schedule/worker-control.ts +15 -5
  706. package/src/schedule/worker-mcp.ts +85 -0
  707. package/src/schedule/worker.ts +9 -31
  708. package/src/security/secure-keys.ts +74 -112
  709. package/src/skills/clawhub.ts +3 -8
  710. package/src/skills/managed-store.ts +1 -5
  711. package/src/stt/types.ts +4 -0
  712. package/src/subagent/notify.ts +54 -34
  713. package/src/subagent/parent-notification.ts +6 -0
  714. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  715. package/src/telemetry/phone-call-funnel.ts +144 -0
  716. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  717. package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
  718. package/src/tools/ask-question/ask-question-tool.ts +120 -22
  719. package/src/tools/browser/browser-execution.ts +29 -60
  720. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  721. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  722. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  723. package/src/tools/client-os.ts +15 -0
  724. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  725. package/src/tools/computer-use/target.ts +42 -0
  726. package/src/tools/document/document-tool.ts +13 -18
  727. package/src/tools/execution-target.ts +14 -16
  728. package/src/tools/host-terminal/host-shell.ts +16 -7
  729. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  730. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  731. package/src/tools/network/web-fetch.ts +274 -7
  732. package/src/tools/network/web-search.ts +468 -6
  733. package/src/tools/permission-checker.ts +3 -3
  734. package/src/tools/policy-context.ts +3 -1
  735. package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
  736. package/src/tools/shared/shell-output.test.ts +10 -0
  737. package/src/tools/shared/shell-output.ts +14 -2
  738. package/src/tools/skills/load.ts +2 -1
  739. package/src/tools/skills/sandbox-runner.ts +24 -4
  740. package/src/tools/skills/scaffold-managed.ts +2 -1
  741. package/src/tools/skills/skill-script-runner.ts +7 -0
  742. package/src/tools/skills/skill-tool-factory.ts +15 -1
  743. package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
  744. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
  745. package/src/tools/terminal/safe-env.ts +39 -24
  746. package/src/tools/terminal/sanitized-bash.ts +15 -2
  747. package/src/tools/terminal/shell-launch.test.ts +162 -0
  748. package/src/tools/terminal/shell.test.ts +29 -0
  749. package/src/tools/terminal/shell.ts +15 -7
  750. package/src/tools/tool-approval-handler.ts +5 -1
  751. package/src/tools/tool-types.ts +3 -3
  752. package/src/tools/types.ts +8 -2
  753. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  754. package/src/util/abort-reasons.ts +18 -26
  755. package/src/util/browser-human-verification.ts +14 -0
  756. package/src/util/canonicalize-identity.test.ts +21 -0
  757. package/src/util/canonicalize-identity.ts +16 -0
  758. package/src/util/errors.ts +13 -3
  759. package/src/util/host-process.test.ts +17 -1
  760. package/src/util/host-process.ts +24 -0
  761. package/src/util/provider-error-patterns.ts +3 -0
  762. package/src/util/unicode.ts +29 -0
  763. package/src/util/worker-process.ts +77 -35
  764. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  765. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  766. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  767. package/src/workspace/migrations/registry.ts +2 -0
  768. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  769. package/src/api/events/heartbeat-alert.ts +0 -20
  770. package/src/daemon/message-types/web-activity.ts +0 -65
  771. package/src/desktop/desktop-dependencies.test.ts +0 -131
  772. package/src/tools/computer-use/definitions.ts +0 -607
@@ -31,6 +31,10 @@ import {
31
31
  type ConversationCreatedInfo,
32
32
  NotificationBroadcaster,
33
33
  } from "./broadcaster.js";
34
+ import {
35
+ intersectChannelAllowlist,
36
+ readChannelAllowlist,
37
+ } from "./channel-allowlist.js";
34
38
  import { enforceRoutingIntent, evaluateSignal } from "./decision-engine.js";
35
39
  import { updateDecision } from "./decisions-store.js";
36
40
  import {
@@ -51,6 +55,7 @@ import type {
51
55
  import type {
52
56
  NotificationChannel,
53
57
  NotificationDeliveryResult,
58
+ NotificationReceiptClass,
54
59
  } from "./types.js";
55
60
 
56
61
  const log = getLogger("emit-signal");
@@ -69,20 +74,27 @@ export function getBroadcaster(): NotificationBroadcaster {
69
74
  new PlatformPushAdapter(),
70
75
  ]);
71
76
 
72
- // Wire the conversation-created callback so the macOS client is notified
73
- // immediately when a vellum notification conversation is paired — before
74
- // slower channel deliveries (e.g. Telegram) delay the push.
77
+ // Wire the conversation-created callback so the event goes out as soon
78
+ // as a vellum notification conversation is paired, before slower channel
79
+ // deliveries (e.g. Telegram) run.
80
+ // A guardian-sensitive conversation's title reaches only the guardian's
81
+ // own connections, the same scoping the vellum adapter applies to the
82
+ // notification itself.
75
83
  broadcasterInstance.setOnConversationCreated((info) => {
76
- broadcastMessage({
77
- type: "notification_conversation_created",
78
- conversationId: info.conversationId,
79
- title: info.title,
80
- sourceEventName: info.sourceEventName,
81
- targetGuardianPrincipalId: info.targetGuardianPrincipalId,
82
- groupId: info.groupId,
83
- source: info.source,
84
- silent: info.silent,
85
- });
84
+ broadcastMessage(
85
+ {
86
+ type: "notification_conversation_created",
87
+ conversationId: info.conversationId,
88
+ title: info.title,
89
+ sourceEventName: info.sourceEventName,
90
+ targetGuardianPrincipalId: info.targetGuardianPrincipalId,
91
+ groupId: info.groupId,
92
+ source: info.source,
93
+ silent: info.silent,
94
+ },
95
+ undefined,
96
+ { targetActorPrincipalId: info.targetGuardianPrincipalId },
97
+ );
86
98
  log.info(
87
99
  {
88
100
  conversationId: info.conversationId,
@@ -240,7 +252,9 @@ export interface EmitSignalResult {
240
252
  deduplicated: boolean;
241
253
  dispatched: boolean;
242
254
  reason: string;
255
+ selectedChannels: NotificationChannel[];
243
256
  deliveryResults: NotificationDeliveryResult[];
257
+ receiptClass: NotificationReceiptClass;
244
258
  /**
245
259
  * True when the pipeline threw before reaching a verdict. Dispatch, dedupe,
246
260
  * suppression, and a blocked deterministic check are all verdicts. Callers
@@ -250,6 +264,55 @@ export interface EmitSignalResult {
250
264
  pipelineFailed: boolean;
251
265
  }
252
266
 
267
+ const PROVIDER_RECEIPT_CHANNELS = new Set(["telegram", "slack", "discord"]);
268
+
269
+ /**
270
+ * Strongest proof the emit path can report from adapter results. A vellum
271
+ * `sent` row means the assistant broadcast a `notification_intent`; it is
272
+ * not a client ACK that the OS posted a banner.
273
+ */
274
+ export function classifyNotificationReceipt(
275
+ results: readonly NotificationDeliveryResult[],
276
+ ): NotificationReceiptClass {
277
+ const accepted = results.filter((result) => {
278
+ return result.status === "sent" || result.status === "pending";
279
+ });
280
+ if (
281
+ accepted.some((result) => {
282
+ return PROVIDER_RECEIPT_CHANNELS.has(result.channel);
283
+ })
284
+ ) {
285
+ return "provider_accepted";
286
+ }
287
+ if (
288
+ accepted.some((result) => {
289
+ return result.channel === "platform";
290
+ })
291
+ ) {
292
+ return "gateway_accepted";
293
+ }
294
+ return "unknown";
295
+ }
296
+
297
+ function emitOutcome(
298
+ partial: Omit<
299
+ EmitSignalResult,
300
+ "deliveryResults" | "selectedChannels" | "receiptClass"
301
+ > & {
302
+ deliveryResults?: NotificationDeliveryResult[];
303
+ selectedChannels?: NotificationChannel[];
304
+ },
305
+ ): EmitSignalResult {
306
+ const deliveryResults = partial.deliveryResults ?? [];
307
+ const selectedChannels = partial.selectedChannels ?? [];
308
+ return {
309
+ ...partial,
310
+ selectedChannels,
311
+ deliveryResults,
312
+ receiptClass: classifyNotificationReceipt(deliveryResults),
313
+ };
314
+ }
315
+
253
316
  /**
254
317
  * True when at least one channel adapter has already been handed the signal.
255
318
  * `sent` is a completed delivery; `pending` is the platform push that passed
@@ -333,14 +396,13 @@ export async function emitNotificationSignal<TEventName extends string>(
333
396
  { signalId, dedupeKey: params.dedupeKey },
334
397
  "Signal deduplicated at event store level",
335
398
  );
336
- return {
399
+ return emitOutcome({
337
400
  signalId,
338
401
  deduplicated: true,
339
402
  dispatched: false,
340
403
  reason: "Signal deduplicated at event store level",
341
- deliveryResults: [],
342
404
  pipelineFailed: false,
343
- };
405
+ });
344
406
  }
345
407
  eventPersisted = true;
346
408
 
@@ -357,14 +419,13 @@ export async function emitNotificationSignal<TEventName extends string>(
357
419
  { signalId, reason: sourceActiveCheck.reason },
358
420
  "Signal suppressed before decision stage (source-active)",
359
421
  );
360
- return {
422
+ return emitOutcome({
361
423
  signalId,
362
424
  deduplicated: false,
363
425
  dispatched: false,
364
426
  reason: `Signal suppressed: ${sourceActiveCheck.reason}`,
365
- deliveryResults: [],
366
427
  pipelineFailed: false,
367
- };
428
+ });
368
429
  }
369
430
 
370
431
  // Step 2: Evaluate the signal through the decision engine
@@ -398,8 +459,31 @@ export async function emitNotificationSignal<TEventName extends string>(
398
459
  // dispatch rank, so selection order only matters to single_channel
399
460
  // enforcement's first-selected fallback (step 2.5b), which must keep
400
461
  // the in-app banner rather than a push the server may skip.
462
+ const exclusiveAllowlist = readChannelAllowlist(signal.contextPayload);
401
463
  const urgency = signal.attentionHints.urgency;
402
- if (
464
+ if (exclusiveAllowlist) {
465
+ // Exclusive allowlist wins over the default set, urgent force, and
466
+ // routing-intent expansion. Delivery is the allowlist intersected
467
+ // with connected channels.
468
+ const allowed = intersectChannelAllowlist(
469
+ exclusiveAllowlist,
470
+ connectedChannels,
471
+ );
472
+ const alreadyMatches =
473
+ allowed.length === decision.selectedChannels.length &&
474
+ allowed.every((channel) => {
475
+ return decision.selectedChannels.includes(channel);
476
+ }) &&
477
+ decision.shouldNotify === allowed.length > 0;
478
+ if (!alreadyMatches) {
479
+ decision = {
480
+ ...decision,
481
+ selectedChannels: allowed,
482
+ shouldNotify: allowed.length > 0,
483
+ reasoningSummary: `${decision.reasoningSummary} (channelAllowlist: ${allowed.join(", ") || "none available"})`,
484
+ };
485
+ }
486
+ } else if (
403
487
  (urgency === "high" || urgency === "critical") &&
404
488
  decision.shouldNotify
405
489
  ) {
@@ -427,13 +511,16 @@ export async function emitNotificationSignal<TEventName extends string>(
427
511
  }
428
512
  }
429
513
 
430
- // Step 2.5b: Enforce routing intent policy (fire-time guard)
431
- decision = enforceRoutingIntent(
432
- decision,
433
- signal.routingIntent,
434
- connectedChannels,
435
- signal.sourceChannel,
436
- );
514
+ // Step 2.5b: Enforce routing intent policy (fire-time guard).
515
+ // An exclusive allowlist already closed the channel set.
516
+ if (!exclusiveAllowlist) {
517
+ decision = enforceRoutingIntent(
518
+ decision,
519
+ signal.routingIntent,
520
+ connectedChannels,
521
+ signal.sourceChannel,
522
+ );
523
+ }
437
524
 
438
525
  // Step 2.5c: Access-request signals carry a decisionable canonical
439
526
  // guardian request created before this emit, and that row suppresses
@@ -509,22 +596,21 @@ export async function emitNotificationSignal<TEventName extends string>(
509
596
  { signalId, reason: checkResult.reason },
510
597
  "Signal blocked by deterministic checks",
511
598
  );
512
- return {
599
+ return emitOutcome({
513
600
  signalId,
514
601
  deduplicated: false,
515
602
  dispatched: false,
516
603
  reason: `Signal blocked by deterministic checks: ${checkResult.reason}`,
517
- deliveryResults: [],
518
604
  pipelineFailed: false,
519
- };
605
+ });
520
606
  }
521
607
  }
522
608
 
523
609
  // Step 4: Dispatch through the broadcaster
524
610
  // Note: notification_conversation_created events are emitted eagerly inside
525
611
  // the broadcaster as soon as vellum conversation pairing succeeds, rather
526
- // than after all channel deliveries complete. This avoids a race where
527
- // slow Telegram delivery delays the push past the macOS deep-link retry.
612
+ // than after all channel deliveries complete, so a slow Telegram delivery
613
+ // cannot delay it.
528
614
  const broadcaster = getBroadcaster();
529
615
  const dispatchResult = await dispatchDecision(
530
616
  signal,
@@ -562,14 +648,15 @@ export async function emitNotificationSignal<TEventName extends string>(
562
648
  },
563
649
  "Signal pipeline complete",
564
650
  );
565
- return {
651
+ return emitOutcome({
566
652
  signalId,
567
653
  deduplicated: false,
568
654
  dispatched: dispatchResult.dispatched,
569
655
  reason: dispatchResult.reason,
656
+ selectedChannels: decision.selectedChannels,
570
657
  deliveryResults: dispatchResult.deliveryResults,
571
658
  pipelineFailed: false,
572
- };
659
+ });
573
660
  } catch (err) {
574
661
  const errMsg = err instanceof Error ? err.message : String(err);
575
662
  log.error(
@@ -599,13 +686,12 @@ export async function emitNotificationSignal<TEventName extends string>(
599
686
  if (params.throwOnError) {
600
687
  throw err instanceof Error ? err : new Error(errMsg);
601
688
  }
602
- return {
689
+ return emitOutcome({
603
690
  signalId,
604
691
  deduplicated: false,
605
692
  dispatched: false,
606
693
  reason: `Signal pipeline failed: ${errMsg}`,
607
- deliveryResults: [],
608
694
  pipelineFailed: true,
609
- };
695
+ });
610
696
  }
611
697
  }
@@ -30,6 +30,7 @@ import {
30
30
  import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
31
31
  import { getLogger } from "../util/logger.js";
32
32
  import { normalizeTitle, stripMarkdown } from "../util/short-title.js";
33
+ import { readChannelAllowlist } from "./channel-allowlist.js";
33
34
  import { isConversationSeedSane } from "./conversation-seed-composer.js";
34
35
  import { deriveTitle } from "./copy-composer.js";
35
36
  import {
@@ -459,12 +460,10 @@ const EVENT_CATEGORY_MAP: Record<string, FeedItemCategory> = {
459
460
 
460
461
  /**
461
462
  * Map a signal's source event to a feed category, or nothing when the event
462
- * has no entry. An unmapped event used to land in `system`, a bucket named
463
- * for our architecture rather than the user's world, and every deliberate
464
- * assistant notification (`user.send_notification`) ended up there. The
465
- * category is optional on the wire, so an event without a home simply
466
- * carries none: readers that filter by category skip it, and nothing has
467
- * to guess.
463
+ * has no entry. An unmapped event, such as a deliberate assistant
464
+ * notification (`assistant.share`), carries no category rather than a
465
+ * catch-all bucket named for our architecture: readers that filter by
466
+ * category skip it, and nothing has to guess.
468
467
  */
469
468
  function deriveCategory(
470
469
  signal: NotificationSignal,
@@ -558,7 +557,10 @@ function resolveHomeFeedMirror(
558
557
  signal.sourceChannel === "assistant_tool" ||
559
558
  signal.sourceEventName === "chat.assistant_reply"
560
559
  ) {
561
- return { mirror: true, sourceConversationId, sourceScheduleJobId };
560
+ const allowlist = readChannelAllowlist(signal.contextPayload);
561
+ if (!allowlist || allowlist.includes("vellum")) {
562
+ return { mirror: true, sourceConversationId, sourceScheduleJobId };
563
+ }
562
564
  }
563
565
  if (signal.attentionHints.isAsyncBackground) {
564
566
  return { mirror: true, sourceConversationId, sourceScheduleJobId };
@@ -71,6 +71,25 @@ export function readPayloadObject(
71
71
  return isPlainObject(value) ? value : undefined;
72
72
  }
73
73
 
74
+ /**
75
+ * Safely read a string-array property from an unknown-typed payload object.
76
+ * Non-string entries are dropped. Returns `undefined` when the payload is
77
+ * not an object or the key does not hold an array.
78
+ */
79
+ export function readPayloadStringArray(
80
+ payload: unknown,
81
+ key: string,
82
+ ): string[] | undefined {
83
+ if (!isPlainObject(payload)) {
84
+ return undefined;
85
+ }
86
+ const value = payload[key];
87
+ if (!Array.isArray(value)) {
88
+ return undefined;
89
+ }
90
+ return value.filter((entry): entry is string => typeof entry === "string");
91
+ }
92
+
74
93
  /** Truncate `text` to `maxLength`, appending "…" when exceeded. */
75
94
  export function truncate(text: string, maxLength: number): string {
76
95
  if (text.length <= maxLength) {
@@ -103,12 +103,10 @@ export interface ScheduleResultNotificationParams {
103
103
  * conversation can come back too and are harmless, because only this run's
104
104
  * own call ids are matched.
105
105
  *
106
- * A Slack Web API post through bash is deliberately not a route, because its
107
- * success proves nothing about the post. Slack refuses a call with HTTP 200
108
- * and `ok: false` in the body, and the authenticated-request command fails
109
- * only on a non-2xx status, so a post Slack refused still leaves a successful
110
- * tool result. A run that posts that way gets the fallback too: at worst a
111
- * duplicate, never a silence.
106
+ * A Slack Web API post through bash is deliberately not a route. It is off
107
+ * the guided path and unrecorded, and recognizing it would mean reading a
108
+ * shell command for a method name. A run that posts that way gets the
109
+ * fallback too: at worst a duplicate, never a silence.
112
110
  */
113
111
  function deliveredThroughMessagingTool(
114
112
  conversationId: string,
@@ -59,8 +59,9 @@ export function isNotificationSourceChannel(
59
59
 
60
60
  export const NOTIFICATION_SOURCE_EVENT_NAMES = [
61
61
  {
62
- id: "user.send_notification",
63
- description: "User-initiated notification via assistant tool",
62
+ id: "assistant.share",
63
+ description:
64
+ "Assistant chose to tell the user something (`assistant notifications send`)",
64
65
  },
65
66
  {
66
67
  id: "schedule.notify",
@@ -113,28 +114,12 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
113
114
  id: "watcher.notification",
114
115
  description: "Watcher detected a notable event",
115
116
  },
116
- {
117
- id: "watcher.escalation",
118
- description: "Watcher event requiring immediate attention",
119
- },
120
- {
121
- id: "tool_confirmation.required_action",
122
- description: "Tool requires user confirmation before executing",
123
- },
124
117
  { id: "activity.complete", description: "Background activity finished" },
125
118
  {
126
119
  id: "activity.failed",
127
120
  description:
128
121
  "Background job execution failed (model_provider, exception, or timeout)",
129
122
  },
130
- {
131
- id: "quick_chat.response_ready",
132
- description: "Quick chat response ready for review",
133
- },
134
- {
135
- id: "voice.response_ready",
136
- description: "Voice response ready for playback",
137
- },
138
123
  {
139
124
  id: "credential.health_alert",
140
125
  description:
@@ -251,7 +236,7 @@ export interface NotificationSignal<TEventName extends string = string> {
251
236
  createdAt: number; // epoch ms
252
237
  sourceChannel: NotificationSourceChannel; // see NOTIFICATION_SOURCE_CHANNELS registry
253
238
  sourceContextId: string;
254
- sourceEventName: TEventName; // free-form: 'reminder_fired', 'guardian_question', etc.
239
+ sourceEventName: TEventName; // free-form; see NOTIFICATION_SOURCE_EVENT_NAMES
255
240
  contextPayload: NotificationContextPayload<TEventName>;
256
241
  attentionHints: AttentionHints;
257
242
  /**
@@ -46,6 +46,21 @@ export type NotificationDeliveryResult = z.infer<
46
46
  typeof NotificationDeliveryResultSchema
47
47
  >;
48
48
 
49
+ /**
50
+ * Strongest delivery proof the emit path can report. These are receipts,
51
+ * not intents: `client_os_posted` is reserved for a client ACK that the
52
+ * OS banner was posted, which this return path does not observe.
53
+ */
54
+ export const NotificationReceiptClassSchema = z.enum([
55
+ "provider_accepted",
56
+ "gateway_accepted",
57
+ "client_os_posted",
58
+ "unknown",
59
+ ]);
60
+ export type NotificationReceiptClass = z.infer<
61
+ typeof NotificationReceiptClassSchema
62
+ >;
63
+
49
64
  // -- Channel adapter data shapes ----------------------------------------------
50
65
 
51
66
  export const DeliveryResultSchema = z.object({
@@ -10,6 +10,8 @@ Add an entry to `PROVIDER_SEED_DATA`. Required fields: `provider`, `authorizeUrl
10
10
 
11
11
  `injectionTemplates` is also a security boundary, not only an injection rule. `assistant oauth request` and `assistant channels request` accept an absolute URL only when its host matches one of the entry's `hostPattern` values (`assertOAuthRequestUrlAllowed` in `../runtime/routes/oauth-commands-routes.ts`), so that list is the full set of hosts the credential may be sent to. A pattern matches exactly unless it starts with `*.`; reserve the wildcard for per-tenant hosts that cannot be enumerated (`*.salesforce.com`), and name a fixed host the provider documents (`files.slack.com`) by name. The guard sees only the URL the caller passes: the connection follows a redirect itself, and a cross-origin hop carries no `Authorization`, so a redirect target never receives the credential and never needs listing.
12
12
 
13
+ `responseOkField` declares the boolean a provider's API puts in every response body to report success (Slack: `ok`), and it is read in one place, `providerReportsFailure` in `identity-verifier.ts`. It is not `identityOkField`, which governs only the identity call and stays the documented `--identity-ok-field` contract. Both request doors and `oauth ping` treat an explicit `false` under a 2xx as a failed call, since such a provider hides refusals behind a successful status; a body without the field leaves the status as the verdict. Declare it on every row that calls such an API, the bot row included.
14
+
13
15
  If the provider will support managed mode, set `managedServiceConfigKey` to a slug matching the key you will add to `ServicesSchema` (e.g. `"acme-oauth"`).
14
16
 
15
17
  ### 2. _(managed only)_ Add a service schema — `../config/schemas/services.ts`
@@ -1,6 +1,9 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
- import { verifyIdentity } from "../identity-verifier.js";
3
+ import {
4
+ providerReportsFailure,
5
+ verifyIdentity,
6
+ } from "../identity-verifier.js";
4
7
  import type { OAuthProviderRow } from "../oauth-store.js";
5
8
 
6
9
  // ---------------------------------------------------------------------------
@@ -66,6 +69,7 @@ function makeProviderRow(
66
69
  identityResponsePaths: null,
67
70
  identityFormat: null,
68
71
  identityOkField: null,
72
+ responseOkField: null,
69
73
  featureFlag: null,
70
74
  createdAt: now,
71
75
  updatedAt: now,
@@ -469,3 +473,34 @@ describe("verifyIdentity", () => {
469
473
  });
470
474
  });
471
475
  });
476
+
477
+ describe("providerReportsFailure", () => {
478
+ test("reads an explicit false in the declared field as failure", () => {
479
+ expect(
480
+ providerReportsFailure(
481
+ { responseOkField: "ok" },
482
+ { ok: false, error: "invalid_auth" },
483
+ ),
484
+ ).toBe(true);
485
+ expect(
486
+ providerReportsFailure({ responseOkField: "ok" }, { ok: true }),
487
+ ).toBe(false);
488
+ });
489
+
490
+ test("a body without the field says nothing", () => {
491
+ // A download or an endpoint outside the envelope; the status decides.
492
+ expect(providerReportsFailure({ responseOkField: "ok" }, null)).toBe(false);
493
+ expect(
494
+ providerReportsFailure({ responseOkField: "ok" }, Buffer.from("png")),
495
+ ).toBe(false);
496
+ expect(
497
+ providerReportsFailure({ responseOkField: "ok" }, { data: {} }),
498
+ ).toBe(false);
499
+ });
500
+
501
+ test("a provider that declares no field never reports failure", () => {
502
+ expect(
503
+ providerReportsFailure({ responseOkField: null }, { ok: false }),
504
+ ).toBe(false);
505
+ });
506
+ });
@@ -467,12 +467,11 @@ async function fetchPlatformConnections(options: {
467
467
  }
468
468
 
469
469
  const body = (await response.json()) as unknown;
470
- const connections = (
470
+ return (
471
471
  Array.isArray(body)
472
472
  ? body
473
473
  : ((body as Record<string, unknown>).results ?? [])
474
474
  ) as PlatformConnectionEntry[];
475
- return connections;
476
475
  }
477
476
 
478
477
  /**
@@ -27,6 +27,30 @@ function getNestedValue(obj: unknown, dotPath: string): unknown {
27
27
  return current;
28
28
  }
29
29
 
30
+ /**
31
+ * Whether a response body says the call failed, read through the ok field the
32
+ * provider declares (`responseOkField`).
33
+ *
34
+ * Some APIs report failure inside a successful HTTP exchange: Slack documents
35
+ * that every Web API response is a JSON object with a top-level boolean `ok`,
36
+ * false on failure, so the status code alone reads a refused call as a
37
+ * success. The provider row is where that envelope is declared, and this is
38
+ * the one reader of it for calls whose endpoint is not known in advance (ping
39
+ * and the authenticated-request doors). Only an explicit `false` counts: a
40
+ * body without the field, such as a file download or an endpoint outside the
41
+ * envelope, says nothing, and the status stays the verdict. The identity
42
+ * verifier reads its own field, `identityOkField`, for the one call it makes.
43
+ */
44
+ export function providerReportsFailure(
45
+ providerRow: Pick<OAuthProviderRow, "responseOkField">,
46
+ body: unknown,
47
+ ): boolean {
48
+ if (!providerRow.responseOkField) {
49
+ return false;
50
+ }
51
+ return getNestedValue(body, providerRow.responseOkField) === false;
52
+ }
53
+
30
54
  /** Safely parse a JSON string, returning a fallback on failure or null/undefined input. */
31
55
  function safeJsonParse<T>(value: string | null | undefined, fallback: T): T {
32
56
  if (value == null) {
@@ -59,7 +59,7 @@ export type OAuthConnectionRow = typeof oauthConnections.$inferSelect;
59
59
  * managedServiceConfigKey,
60
60
  * loopbackPort, injectionTemplates, appType, setupNotes,
61
61
  * identityUrl, identityMethod, identityHeaders, identityBody,
62
- * identityResponsePaths, identityFormat, identityOkField, featureFlag,
62
+ * identityResponsePaths, identityFormat, identityOkField, responseOkField, featureFlag,
63
63
  * scopeSeparator, defaultScopes, availableScopes)
64
64
  * and display metadata (displayLabel, description, dashboardUrl,
65
65
  * clientIdPlaceholder, logoUrl, requiresClientSecret) propagate to existing
@@ -111,6 +111,7 @@ export function seedProviders(
111
111
  identityResponsePaths?: string[];
112
112
  identityFormat?: string;
113
113
  identityOkField?: string;
114
+ responseOkField?: string;
114
115
  featureFlag?: string;
115
116
  }>,
116
117
  ): void {
@@ -175,6 +176,7 @@ export function seedProviders(
175
176
  : null;
176
177
  const identityFormat = p.identityFormat ?? null;
177
178
  const identityOkField = p.identityOkField ?? null;
179
+ const responseOkField = p.responseOkField ?? null;
178
180
  const featureFlag = p.featureFlag ?? null;
179
181
 
180
182
  db.insert(oauthProviders)
@@ -216,6 +218,7 @@ export function seedProviders(
216
218
  identityResponsePaths,
217
219
  identityFormat,
218
220
  identityOkField,
221
+ responseOkField,
219
222
  featureFlag,
220
223
  createdAt: now,
221
224
  updatedAt: now,
@@ -259,6 +262,7 @@ export function seedProviders(
259
262
  identityResponsePaths,
260
263
  identityFormat,
261
264
  identityOkField,
265
+ responseOkField,
262
266
  featureFlag,
263
267
  updatedAt: now,
264
268
  },
@@ -359,6 +363,7 @@ export function registerProvider(params: {
359
363
  identityResponsePaths?: string[];
360
364
  identityFormat?: string;
361
365
  identityOkField?: string;
366
+ responseOkField?: string;
362
367
  featureFlag?: string;
363
368
  }): OAuthProviderRow {
364
369
  const db = getDb();
@@ -425,6 +430,7 @@ export function registerProvider(params: {
425
430
  : null,
426
431
  identityFormat: params.identityFormat ?? null,
427
432
  identityOkField: params.identityOkField ?? null,
433
+ responseOkField: params.responseOkField ?? null,
428
434
  featureFlag: params.featureFlag ?? null,
429
435
  createdAt: now,
430
436
  updatedAt: now,
@@ -486,6 +492,7 @@ export function updateProvider(
486
492
  identityResponsePaths: string[];
487
493
  identityFormat: string;
488
494
  identityOkField: string;
495
+ responseOkField: string;
489
496
  featureFlag: string;
490
497
  managedServiceIsPaid: boolean;
491
498
  }>,
@@ -610,6 +617,9 @@ export function updateProvider(
610
617
  if (params.identityOkField !== undefined) {
611
618
  set.identityOkField = params.identityOkField;
612
619
  }
620
+ if (params.responseOkField !== undefined) {
621
+ set.responseOkField = params.responseOkField;
622
+ }
613
623
  if (params.featureFlag !== undefined) {
614
624
  set.featureFlag = params.featureFlag;
615
625
  }
@@ -668,8 +678,6 @@ export async function upsertApp(
668
678
  );
669
679
  }
670
680
 
671
- const defaultCredPath = (appId: string) => oauthAppClientSecretPath(appId);
672
-
673
681
  // Verify the credential path points to an existing secret.
674
682
  if (clientSecretCredentialPath) {
675
683
  const existing = await getSecureKeyAsync(clientSecretCredentialPath);
@@ -729,7 +737,7 @@ export async function upsertApp(
729
737
 
730
738
  const now = Date.now();
731
739
  const id = uuid();
732
- const credPath = clientSecretCredentialPath ?? defaultCredPath(id);
740
+ const credPath = clientSecretCredentialPath ?? oauthAppClientSecretPath(id);
733
741
 
734
742
  const row = {
735
743
  id,
@@ -19,6 +19,7 @@ export type SerializedProvider = ReturnType<typeof serializeProvider> &
19
19
  Record<string, unknown>;
20
20
 
21
21
  import { isChannelBotProvider } from "@vellumai/service-contracts/channels";
22
+ import type { IntegrationCategory } from "@vellumai/service-contracts/integration-categories";
22
23
 
23
24
  import { PROVIDER_SEED_DATA } from "./seed-providers.js";
24
25
 
@@ -38,6 +39,11 @@ export interface SerializedProviderSummary {
38
39
  supports_managed_mode: boolean;
39
40
  managed_service_is_paid: boolean;
40
41
  feature_flag: string | null;
42
+ /**
43
+ * Where the integrations catalog files the provider. `null` for a row with
44
+ * no seed entry, such as a provider a user registered by hand.
45
+ */
46
+ category: IntegrationCategory | null;
41
47
  /**
42
48
  * Per-tenant providers only (Shopify): what a client must collect before
43
49
  * starting a managed connect, since the provider's OAuth endpoints live on
@@ -141,6 +147,7 @@ function _serializeProvider(
141
147
  : null,
142
148
  identityFormat: row.identityFormat ?? null,
143
149
  identityOkField: row.identityOkField ?? null,
150
+ responseOkField: row.responseOkField ?? null,
144
151
  featureFlag: row.featureFlag ?? null,
145
152
  redirectUri:
146
153
  options?.redirectUri !== undefined ? options.redirectUri : null,
@@ -172,6 +179,7 @@ export function serializeProviderSummary(
172
179
  supports_managed_mode: !!row.managedServiceConfigKey,
173
180
  managed_service_is_paid: !!row.managedServiceIsPaid,
174
181
  feature_flag: row.featureFlag ?? null,
182
+ category: PROVIDER_SEED_DATA[row.provider]?.category ?? null,
175
183
  tenant_host: PROVIDER_SEED_DATA[row.provider]?.tenantHost ?? null,
176
184
  acts_as: isChannelBotProvider(row.provider) ? "assistant" : "user",
177
185
  };