@vellumai/assistant 0.12.3-staging.1 → 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 (560) hide show
  1. package/ARCHITECTURE.md +43 -29
  2. package/Dockerfile +63 -0
  3. package/docs/architecture/security.md +10 -5
  4. package/docs/architecture/turn-actor.md +2 -0
  5. package/docs/desktop-browser-cli.md +45 -4
  6. package/docs/live-voice-task-outcomes.md +100 -0
  7. package/docs/mode-sessions.md +183 -0
  8. package/docs/voice-input-diagnostics.md +58 -0
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  15. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  17. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  18. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  19. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  20. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  22. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  23. package/openapi.yaml +665 -14
  24. package/package.json +1 -1
  25. package/scripts/smoke-desktop-browser-cli.ts +10 -26
  26. package/scripts/smoke-desktop-window-theme.ts +2 -3
  27. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  28. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  29. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  30. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  31. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  32. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  33. package/src/__tests__/approval-message-composer.test.ts +1 -118
  34. package/src/__tests__/approval-routes-http.test.ts +3 -0
  35. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  37. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  38. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  39. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  40. package/src/__tests__/btw-routes.test.ts +4 -1
  41. package/src/__tests__/build-persisted-content.test.ts +1 -1
  42. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  43. package/src/__tests__/call-recovery.test.ts +7 -2
  44. package/src/__tests__/call-routes-http.test.ts +12 -0
  45. package/src/__tests__/call-store.test.ts +7 -2
  46. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  47. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  48. package/src/__tests__/checker.test.ts +11 -3
  49. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  50. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  51. package/src/__tests__/computer-use-tools.test.ts +1 -233
  52. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  53. package/src/__tests__/config-schema.test.ts +16 -0
  54. package/src/__tests__/config-watcher.test.ts +24 -0
  55. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  56. package/src/__tests__/context-search-fanout.test.ts +1 -1
  57. package/src/__tests__/context-search-types.test.ts +7 -7
  58. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  59. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  60. package/src/__tests__/conversation-agent-loop.test.ts +546 -16
  61. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  62. package/src/__tests__/conversation-evictor.test.ts +62 -37
  63. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  64. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  65. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  66. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  67. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  68. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  69. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  70. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  72. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  73. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  74. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  75. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  76. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  77. package/src/__tests__/conversation-undo.test.ts +61 -0
  78. package/src/__tests__/credential-execution-client.test.ts +6 -6
  79. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  80. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  81. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  82. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  83. package/src/__tests__/dm-backfill.test.ts +91 -1
  84. package/src/__tests__/document-create-route.test.ts +88 -0
  85. package/src/__tests__/document-sync-tags.test.ts +27 -0
  86. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  87. package/src/__tests__/events-tail-route.test.ts +25 -0
  88. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  89. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  90. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  91. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  92. package/src/__tests__/heartbeat-service.test.ts +2 -59
  93. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  94. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  95. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  96. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  97. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  98. package/src/__tests__/image-credentials.test.ts +49 -0
  99. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  100. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  101. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  102. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  103. package/src/__tests__/llm-catalog-parity.test.ts +2 -2
  104. package/src/__tests__/media-generate-image.test.ts +49 -1
  105. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  106. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  107. package/src/__tests__/mode-session-history.test.ts +245 -0
  108. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  109. package/src/__tests__/mode-session-wire.test.ts +141 -0
  110. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  111. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  112. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +12 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  115. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  116. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  117. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  118. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  119. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -0
  120. package/src/__tests__/process-message-display-content.test.ts +56 -0
  121. package/src/__tests__/reaction-persistence.test.ts +5 -0
  122. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  123. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  124. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  125. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  126. package/src/__tests__/secure-keys.test.ts +43 -1
  127. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  128. package/src/__tests__/server-history-render.test.ts +91 -1
  129. package/src/__tests__/settings-routes.test.ts +50 -1
  130. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  131. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  132. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  133. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  134. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  135. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  136. package/src/__tests__/thread-backfill.test.ts +53 -0
  137. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  138. package/src/__tests__/tool-result-metadata-plumbing.test.ts +3 -1
  139. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  140. package/src/__tests__/twilio-routes.test.ts +1 -0
  141. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  142. package/src/activation/progress-store.test.ts +12 -7
  143. package/src/agent/loop.ts +99 -41
  144. package/src/api/events/assistant-turn-start.ts +3 -0
  145. package/src/api/events/generation-handoff.ts +2 -0
  146. package/src/api/events/message-complete.ts +2 -0
  147. package/src/api/events/notification-conversation-created.ts +14 -16
  148. package/src/api/events/notification-intent.ts +4 -2
  149. package/src/api/events/tool-result.ts +85 -0
  150. package/src/api/events/tool-use-start.ts +3 -0
  151. package/src/api/events/user-message-echo.ts +3 -0
  152. package/src/api/index.ts +31 -6
  153. package/src/api/mode-session.test.ts +131 -0
  154. package/src/api/mode-session.ts +148 -0
  155. package/src/api/remember-tool.ts +15 -0
  156. package/src/api/responses/conversation-message.ts +6 -0
  157. package/src/approvals/AGENTS.md +4 -2
  158. package/src/browser/__tests__/operations.test.ts +29 -0
  159. package/src/browser/operation-meta.ts +2 -1
  160. package/src/browser/operations.ts +29 -0
  161. package/src/browser/virtual-desktop-target.ts +2 -8
  162. package/src/bundler/bundle-signer.ts +1 -3
  163. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  164. package/src/calls/__tests__/call-controller.test.ts +94 -0
  165. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  166. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  167. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  168. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  169. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  170. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  171. package/src/calls/barge-in-guard.ts +5 -0
  172. package/src/calls/call-controller.ts +196 -1
  173. package/src/calls/call-domain.ts +4 -0
  174. package/src/calls/call-store.ts +87 -2
  175. package/src/calls/guardian-action-sweep.ts +22 -8
  176. package/src/calls/media-stream-audio-transcode.ts +1 -3
  177. package/src/calls/typesafe-noul.ts +156 -0
  178. package/src/calls/voice-control-protocol.ts +6 -0
  179. package/src/calls/voice-escalation-judge.ts +145 -0
  180. package/src/calls/voice-escalation-target.ts +10 -0
  181. package/src/calls/voice-leg-coordinator.ts +121 -3
  182. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  183. package/src/calls/voice-session-bridge.ts +256 -112
  184. package/src/calls/voice-triage-escalate.ts +7 -0
  185. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  186. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  187. package/src/cli/commands/browser.help.ts +4 -5
  188. package/src/cli/commands/browser.ts +0 -1
  189. package/src/cli/commands/clients.help.ts +46 -0
  190. package/src/cli/commands/clients.ts +116 -0
  191. package/src/cli/commands/credentials.help.ts +6 -1
  192. package/src/cli/commands/notifications.help.ts +16 -2
  193. package/src/cli/commands/notifications.ts +30 -8
  194. package/src/cli/commands/roadmap.help.ts +18 -21
  195. package/src/cli/commands/roadmap.ts +4 -21
  196. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  197. package/src/cli/lib/bundled-marketplace.json +84 -34
  198. package/src/cli/lib/plugin-marketplace.ts +8 -0
  199. package/src/cli/lib/publish-plugin.ts +1 -2
  200. package/src/config/__tests__/default-provider.test.ts +3 -1
  201. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  202. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  203. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  204. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  205. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  206. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  207. package/src/config/call-site-defaults.ts +9 -0
  208. package/src/config/feature-flag-registry.json +16 -0
  209. package/src/config/profile-text-generation.test.ts +2 -2
  210. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  211. package/src/config/schemas/call-site-catalog.ts +14 -0
  212. package/src/config/schemas/channels.ts +0 -18
  213. package/src/config/schemas/llm.ts +3 -1
  214. package/src/config/schemas/mcp.ts +2 -1
  215. package/src/config/schemas/memory-retrospective.ts +11 -2
  216. package/src/config/schemas/services.ts +15 -6
  217. package/src/config/schemas/tools.ts +10 -0
  218. package/src/config/session-groups-gate.ts +21 -0
  219. package/src/config/skills.ts +2 -6
  220. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  221. package/src/conversations/message-consolidation.ts +102 -5
  222. package/src/credential-execution/ces-connect.test.ts +69 -0
  223. package/src/credential-execution/ces-connect.ts +115 -0
  224. package/src/credential-execution/ces-runtime.ts +55 -93
  225. package/src/credential-execution/executable-discovery.ts +1 -11
  226. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  227. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  228. package/src/daemon/browser-mode-session.test.ts +402 -0
  229. package/src/daemon/browser-mode-session.ts +186 -0
  230. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  231. package/src/daemon/computer-use-mode-session.ts +105 -0
  232. package/src/daemon/config-watcher.ts +10 -0
  233. package/src/daemon/conversation-agent-loop-handlers.ts +58 -10
  234. package/src/daemon/conversation-agent-loop.ts +219 -25
  235. package/src/daemon/conversation-evictor.ts +5 -24
  236. package/src/daemon/conversation-history.ts +10 -0
  237. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  238. package/src/daemon/conversation-interrupt.ts +7 -11
  239. package/src/daemon/conversation-messaging.ts +58 -5
  240. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  241. package/src/daemon/conversation-mode-session.ts +1008 -0
  242. package/src/daemon/conversation-process.ts +5 -0
  243. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  244. package/src/daemon/conversation-skill-tools.ts +1 -0
  245. package/src/daemon/conversation-store.ts +4 -4
  246. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  247. package/src/daemon/conversation-surfaces.ts +113 -5
  248. package/src/daemon/conversation-tool-setup.ts +8 -3
  249. package/src/daemon/conversation.ts +143 -41
  250. package/src/daemon/handlers/config-model.ts +7 -5
  251. package/src/daemon/handlers/shared.ts +55 -16
  252. package/src/daemon/host-cu-proxy.ts +51 -22
  253. package/src/daemon/lifecycle.ts +30 -13
  254. package/src/daemon/message-protocol.ts +0 -1
  255. package/src/daemon/message-provenance.ts +28 -4
  256. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  257. package/src/daemon/mode-session-tracking.ts +54 -0
  258. package/src/daemon/process-message.ts +13 -4
  259. package/src/daemon/virtual-desktop-context.ts +21 -0
  260. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  261. package/src/desktop/desktop-accessibility-script.ts +88 -0
  262. package/src/desktop/desktop-accessibility.test.ts +160 -0
  263. package/src/desktop/desktop-accessibility.ts +169 -0
  264. package/src/desktop/desktop-automation-lease.test.ts +76 -68
  265. package/src/desktop/desktop-automation-lease.ts +41 -50
  266. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  267. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  268. package/src/desktop/desktop-computer-use.test.ts +449 -0
  269. package/src/desktop/desktop-computer-use.ts +502 -0
  270. package/src/desktop/desktop-dependencies.ts +47 -293
  271. package/src/desktop/desktop-display.ts +2 -2
  272. package/src/desktop/desktop-panel-config.test.ts +13 -3
  273. package/src/desktop/desktop-panel-config.ts +109 -15
  274. package/src/desktop/desktop-session-manager.test.ts +69 -21
  275. package/src/desktop/desktop-session-manager.ts +76 -22
  276. package/src/desktop/desktop-stream-bridge.test.ts +11 -122
  277. package/src/desktop/desktop-stream-bridge.ts +6 -8
  278. package/src/desktop/desktop-window-theme.ts +5 -25
  279. package/src/desktop/virtual-desktop-feature.ts +52 -2
  280. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  281. package/src/documents/document-store.ts +23 -0
  282. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  283. package/src/heartbeat/heartbeat-service.ts +5 -33
  284. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  285. package/src/ipc/assistant-server.ts +2 -0
  286. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  287. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  288. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  289. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  290. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  291. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  292. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  293. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  294. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  295. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  296. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  297. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  298. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  299. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  300. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  301. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  302. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  303. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  304. package/src/live-voice/camera-mode-session.test.ts +265 -0
  305. package/src/live-voice/camera-mode-session.ts +277 -0
  306. package/src/live-voice/continuation-judge.ts +123 -0
  307. package/src/live-voice/live-activity-reporter.ts +115 -6
  308. package/src/live-voice/live-voice-manager.ts +36 -1
  309. package/src/live-voice/live-voice-photo.ts +88 -7
  310. package/src/live-voice/live-voice-session-manager.ts +15 -0
  311. package/src/live-voice/live-voice-session.ts +1443 -747
  312. package/src/live-voice/live-voice-tts.ts +22 -4
  313. package/src/live-voice/microphone-idle-gate.ts +56 -0
  314. package/src/live-voice/protocol.ts +171 -4
  315. package/src/live-voice/session-controls.ts +11 -3
  316. package/src/live-voice/task-outcomes.ts +131 -0
  317. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  318. package/src/mcp/__tests__/manager-tool-caps.test.ts +63 -18
  319. package/src/mcp/__tests__/tool-caps.test.ts +28 -1
  320. package/src/mcp/manager.ts +3 -0
  321. package/src/mcp/tool-caps.ts +12 -4
  322. package/src/media/__tests__/image-models.test.ts +58 -0
  323. package/src/media/image-credentials.ts +5 -0
  324. package/src/media/image-models.ts +52 -0
  325. package/src/media/image-service.ts +8 -0
  326. package/src/media/openrouter-image-service.test.ts +133 -0
  327. package/src/media/openrouter-image-service.ts +153 -0
  328. package/src/media/types.ts +1 -1
  329. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  330. package/src/messaging/providers/discord/send.ts +4 -17
  331. package/src/messaging/providers/discord/transport.ts +2 -2
  332. package/src/messaging/providers/outlook/client.ts +16 -22
  333. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  334. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  335. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  336. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  337. package/src/monitoring/__tests__/control.test.ts +17 -5
  338. package/src/monitoring/control.ts +15 -5
  339. package/src/notifications/AGENTS.md +1 -1
  340. package/src/notifications/README.md +83 -99
  341. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  342. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  343. package/src/notifications/__tests__/copy-composer.test.ts +1 -1
  344. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  345. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  346. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  347. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  348. package/src/notifications/adapters/macos.ts +37 -46
  349. package/src/notifications/broadcaster.ts +5 -6
  350. package/src/notifications/channel-allowlist.ts +44 -0
  351. package/src/notifications/copy-composer.ts +0 -23
  352. package/src/notifications/decision-engine.ts +24 -14
  353. package/src/notifications/deterministic-checks.ts +1 -1
  354. package/src/notifications/emit-signal.ts +123 -37
  355. package/src/notifications/home-feed-side-effect.ts +9 -7
  356. package/src/notifications/notification-utils.ts +19 -0
  357. package/src/notifications/signal.ts +4 -19
  358. package/src/notifications/types.ts +15 -0
  359. package/src/oauth/connection-resolver.ts +1 -2
  360. package/src/oauth/oauth-store.ts +1 -3
  361. package/src/oauth/provider-serializer.ts +7 -0
  362. package/src/oauth/seed-providers.ts +30 -0
  363. package/src/onboarding/onboarding-events-store.ts +99 -12
  364. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  365. package/src/persistence/client-connection-events-store.ts +377 -0
  366. package/src/persistence/conversation-crud.ts +55 -6
  367. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  368. package/src/persistence/conversation-mode-sessions.ts +460 -0
  369. package/src/persistence/conversation-queries.ts +6 -19
  370. package/src/persistence/llm-usage-store.ts +3 -9
  371. package/src/persistence/message-metadata.ts +25 -0
  372. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  373. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  374. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  375. package/src/persistence/schema/conversations.ts +67 -0
  376. package/src/persistence/schema/infrastructure.ts +29 -0
  377. package/src/persistence/steps.ts +17 -0
  378. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  379. package/src/plugin-api/effective-context-window.ts +33 -0
  380. package/src/plugin-api/index.ts +24 -5
  381. package/src/plugin-api/plugin-name-env.ts +125 -0
  382. package/src/plugin-api/resolve-credential.ts +79 -20
  383. package/src/plugin-api/vision-support.test.ts +22 -0
  384. package/src/plugin-api/vision-support.ts +17 -5
  385. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  386. package/src/plugins/active-plugin-env.ts +51 -0
  387. package/src/plugins/defaults/index.ts +24 -0
  388. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  389. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  390. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  391. package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
  392. package/src/plugins/defaults/memory/context-search/format.ts +51 -7
  393. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  394. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  395. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  396. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  397. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  398. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  399. package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
  400. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  401. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  402. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
  403. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  404. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
  405. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  406. package/src/plugins/defaults/memory/tools.ts +38 -11
  407. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
  408. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  409. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
  410. package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
  411. package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
  412. package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
  413. package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
  414. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  415. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  416. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  417. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  418. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  419. package/src/plugins/defaults/task-progress/package.json +14 -0
  420. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  421. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  422. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  423. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  424. package/src/providers/anthropic/client.ts +10 -1
  425. package/src/providers/anthropic-gateway-shared.ts +6 -0
  426. package/src/providers/fetch-provider-catalog.ts +11 -0
  427. package/src/providers/gemini/client.ts +25 -8
  428. package/src/providers/inference/adapter-factory.ts +1 -1
  429. package/src/providers/jev/client.test.ts +10 -0
  430. package/src/providers/jev/client.ts +20 -4
  431. package/src/providers/model-catalog.ts +4 -3
  432. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  433. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  434. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  435. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  436. package/src/providers/openai/chat-completions-provider.ts +100 -29
  437. package/src/providers/openai/google-thought-signature.ts +0 -6
  438. package/src/providers/openai/responses-provider.ts +23 -1
  439. package/src/providers/ratelimit.ts +1 -3
  440. package/src/providers/search-provider-catalog.ts +24 -0
  441. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  442. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  443. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  444. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  445. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  446. package/src/providers/types.ts +5 -0
  447. package/src/routes/control.ts +7 -5
  448. package/src/runtime/AGENTS.md +4 -2
  449. package/src/runtime/actor-trust-resolver.ts +3 -3
  450. package/src/runtime/agent-wake.ts +1 -1
  451. package/src/runtime/approval-message-composer.ts +3 -69
  452. package/src/runtime/assistant-event-hub.ts +73 -75
  453. package/src/runtime/assistant-event-publish-options.ts +7 -0
  454. package/src/runtime/assistant-event-targeting.ts +79 -0
  455. package/src/runtime/assistant-stream-state.ts +13 -100
  456. package/src/runtime/background-job-runner.ts +5 -5
  457. package/src/runtime/channel-retry-sweep.ts +1 -0
  458. package/src/runtime/guardian-action-message-composer.ts +8 -161
  459. package/src/runtime/guardian-reply-router.ts +28 -32
  460. package/src/runtime/http-types.ts +6 -0
  461. package/src/runtime/message-composer-types.ts +3 -61
  462. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  463. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  464. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  465. package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
  466. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  467. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  468. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  469. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  470. package/src/runtime/pending-interactions.ts +29 -0
  471. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  472. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  473. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +1 -1
  474. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  475. package/src/runtime/routes/browser-context.ts +31 -11
  476. package/src/runtime/routes/browser-routes.ts +43 -4
  477. package/src/runtime/routes/btw-routes.ts +9 -4
  478. package/src/runtime/routes/client-routes.ts +108 -0
  479. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  480. package/src/runtime/routes/conversation-routes.ts +113 -27
  481. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  482. package/src/runtime/routes/credential-routes.ts +1 -2
  483. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  484. package/src/runtime/routes/desktop-setup-routes.ts +4 -6
  485. package/src/runtime/routes/documents-routes.ts +51 -0
  486. package/src/runtime/routes/email-routes.ts +3 -7
  487. package/src/runtime/routes/events-routes.ts +75 -54
  488. package/src/runtime/routes/identity-routes.ts +1 -5
  489. package/src/runtime/routes/image-generation-routes.ts +8 -14
  490. package/src/runtime/routes/inbound-message-handler.ts +35 -38
  491. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  492. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  493. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +38 -9
  494. package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
  495. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  496. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  497. package/src/runtime/routes/migration-routes.ts +73 -2
  498. package/src/runtime/routes/notification-routes.ts +10 -0
  499. package/src/runtime/routes/oauth-providers.ts +7 -0
  500. package/src/runtime/routes/plugins-routes.ts +6 -0
  501. package/src/runtime/routes/roadmap-routes.ts +47 -8
  502. package/src/runtime/routes/secret-routes.ts +1 -1
  503. package/src/runtime/routes/settings-routes.ts +10 -4
  504. package/src/runtime/routes/watcher-routes.ts +1 -3
  505. package/src/runtime/trust-class.test.ts +7 -6
  506. package/src/runtime/trust-class.ts +9 -17
  507. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  508. package/src/schedule/worker-control.ts +15 -5
  509. package/src/security/secure-keys.ts +53 -103
  510. package/src/skills/clawhub.ts +3 -8
  511. package/src/skills/managed-store.ts +1 -5
  512. package/src/stt/types.ts +4 -0
  513. package/src/subagent/notify.ts +54 -34
  514. package/src/subagent/parent-notification.ts +6 -0
  515. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  516. package/src/telemetry/phone-call-funnel.ts +144 -0
  517. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  518. package/src/tools/ask-question/ask-question-tool.ts +6 -4
  519. package/src/tools/browser/browser-execution.ts +22 -59
  520. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  521. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  522. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  523. package/src/tools/client-os.ts +15 -0
  524. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  525. package/src/tools/computer-use/target.ts +42 -0
  526. package/src/tools/document/document-tool.ts +13 -18
  527. package/src/tools/execution-target.ts +14 -16
  528. package/src/tools/host-terminal/host-shell.ts +4 -1
  529. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  530. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  531. package/src/tools/network/web-fetch.ts +274 -7
  532. package/src/tools/network/web-search.ts +468 -6
  533. package/src/tools/permission-checker.ts +3 -3
  534. package/src/tools/policy-context.ts +3 -1
  535. package/src/tools/skills/load.ts +2 -1
  536. package/src/tools/skills/sandbox-runner.ts +11 -2
  537. package/src/tools/skills/skill-script-runner.ts +7 -0
  538. package/src/tools/skills/skill-tool-factory.ts +15 -1
  539. package/src/tools/terminal/__tests__/safe-env.test.ts +11 -0
  540. package/src/tools/terminal/safe-env.ts +4 -0
  541. package/src/tools/terminal/shell.ts +2 -0
  542. package/src/tools/tool-approval-handler.ts +5 -1
  543. package/src/tools/tool-types.ts +3 -3
  544. package/src/tools/types.ts +8 -2
  545. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  546. package/src/util/abort-reasons.ts +18 -26
  547. package/src/util/canonicalize-identity.test.ts +21 -0
  548. package/src/util/canonicalize-identity.ts +16 -0
  549. package/src/util/errors.ts +13 -3
  550. package/src/util/provider-error-patterns.ts +3 -0
  551. package/src/util/worker-process.ts +77 -35
  552. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  553. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  554. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  555. package/src/workspace/migrations/registry.ts +2 -0
  556. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  557. package/src/api/events/heartbeat-alert.ts +0 -20
  558. package/src/daemon/message-types/web-activity.ts +0 -65
  559. package/src/desktop/desktop-dependencies.test.ts +0 -131
  560. package/src/tools/computer-use/definitions.ts +0 -607
@@ -1,3 +1,5 @@
1
+ import type { IntegrationCategory } from "@vellumai/service-contracts/integration-categories";
2
+
1
3
  import type { AvailableScopes } from "./connect-types.js";
2
4
  import { migrateProviderBaseUrl, seedProviders } from "./oauth-store.js";
3
5
 
@@ -78,6 +80,8 @@ export const PROVIDER_SEED_DATA: Record<
78
80
  managedServiceIsPaid?: boolean;
79
81
  displayLabel: string;
80
82
  description: string;
83
+ /** Where the integrations catalog files this provider. */
84
+ category: IntegrationCategory;
81
85
  dashboardUrl: string | null;
82
86
  clientIdPlaceholder: string | null;
83
87
  requiresClientSecret?: boolean;
@@ -132,6 +136,7 @@ export const PROVIDER_SEED_DATA: Record<
132
136
  baseUrl: "https://www.googleapis.com",
133
137
  displayLabel: "Google",
134
138
  description: "Gmail, Calendar, Drive, Docs, Sheets, Slides, and Contacts",
139
+ category: "productivity",
135
140
  dashboardUrl: "https://console.cloud.google.com/apis/credentials",
136
141
  clientIdPlaceholder: "123456789.apps.googleusercontent.com",
137
142
  logoUrl: "https://cdn.simpleicons.org/google",
@@ -218,6 +223,7 @@ export const PROVIDER_SEED_DATA: Record<
218
223
  baseUrl: "https://slack.com/api",
219
224
  displayLabel: "Slack",
220
225
  description: "Workspace messaging",
226
+ category: "communication",
221
227
  dashboardUrl: "https://api.slack.com/apps",
222
228
  clientIdPlaceholder: null,
223
229
  logoUrl:
@@ -278,6 +284,7 @@ export const PROVIDER_SEED_DATA: Record<
278
284
  baseUrl: "https://api.notion.com",
279
285
  displayLabel: "Notion",
280
286
  description: "Pages and databases",
287
+ category: "productivity",
281
288
  dashboardUrl: "https://www.notion.so/my-integrations",
282
289
  clientIdPlaceholder: null,
283
290
  logoUrl: "https://cdn.simpleicons.org/notion",
@@ -312,6 +319,7 @@ export const PROVIDER_SEED_DATA: Record<
312
319
  baseUrl: "https://api.x.com",
313
320
  displayLabel: "Twitter",
314
321
  description: "Posts and direct messages",
322
+ category: "communication",
315
323
  dashboardUrl: "https://developer.twitter.com/en/portal/dashboard",
316
324
  clientIdPlaceholder: null,
317
325
  logoUrl: "https://cdn.simpleicons.org/x",
@@ -357,6 +365,7 @@ export const PROVIDER_SEED_DATA: Record<
357
365
  baseUrl: "https://api.github.com",
358
366
  displayLabel: "GitHub",
359
367
  description: "Repositories and issues",
368
+ category: "engineering",
360
369
  dashboardUrl: "https://github.com/settings/developers",
361
370
  clientIdPlaceholder: null,
362
371
  logoUrl: "https://cdn.simpleicons.org/github",
@@ -390,6 +399,7 @@ export const PROVIDER_SEED_DATA: Record<
390
399
  baseUrl: "https://api.linear.app",
391
400
  displayLabel: "Linear",
392
401
  description: "Issues and projects",
402
+ category: "engineering",
393
403
  dashboardUrl: "https://linear.app/settings/api",
394
404
  clientIdPlaceholder: null,
395
405
  logoUrl: "https://cdn.simpleicons.org/linear",
@@ -438,6 +448,7 @@ export const PROVIDER_SEED_DATA: Record<
438
448
  baseUrl: "https://api.spotify.com/v1",
439
449
  displayLabel: "Spotify",
440
450
  description: "Music and playlists",
451
+ category: "productivity",
441
452
  dashboardUrl: "https://developer.spotify.com/dashboard",
442
453
  clientIdPlaceholder: null,
443
454
  logoUrl: "https://cdn.simpleicons.org/spotify",
@@ -477,6 +488,7 @@ export const PROVIDER_SEED_DATA: Record<
477
488
  baseUrl: "https://api.todoist.com/rest/v2",
478
489
  displayLabel: "Todoist",
479
490
  description: "Tasks and projects",
491
+ category: "productivity",
480
492
  dashboardUrl: "https://developer.todoist.com/appconsole.html",
481
493
  clientIdPlaceholder: null,
482
494
  logoUrl: "https://cdn.simpleicons.org/todoist",
@@ -523,6 +535,7 @@ export const PROVIDER_SEED_DATA: Record<
523
535
  // documents `messages.read` as local RPC only, so requesting it would put
524
536
  // a permission on the consent screen that grants nothing here.
525
537
  description: "Your servers and profile",
538
+ category: "communication",
526
539
  dashboardUrl: "https://discord.com/developers/applications",
527
540
  clientIdPlaceholder: null,
528
541
  logoUrl: "https://cdn.simpleicons.org/discord",
@@ -553,6 +566,7 @@ export const PROVIDER_SEED_DATA: Record<
553
566
  baseUrl: "https://api.dropboxapi.com/2",
554
567
  displayLabel: "Dropbox",
555
568
  description: "Files and folders",
569
+ category: "productivity",
556
570
  dashboardUrl: "https://www.dropbox.com/developers/apps",
557
571
  clientIdPlaceholder: null,
558
572
  logoUrl: "https://cdn.simpleicons.org/dropbox",
@@ -593,6 +607,7 @@ export const PROVIDER_SEED_DATA: Record<
593
607
  baseUrl: "https://app.asana.com/api/1.0",
594
608
  displayLabel: "Asana",
595
609
  description: "Tasks and projects",
610
+ category: "productivity",
596
611
  dashboardUrl: "https://app.asana.com/0/my-apps",
597
612
  clientIdPlaceholder: null,
598
613
  logoUrl: "https://cdn.simpleicons.org/asana",
@@ -621,6 +636,7 @@ export const PROVIDER_SEED_DATA: Record<
621
636
  baseUrl: "https://api.airtable.com/v0",
622
637
  displayLabel: "Airtable",
623
638
  description: "Bases and records",
639
+ category: "productivity",
624
640
  dashboardUrl: "https://airtable.com/create/tokens",
625
641
  clientIdPlaceholder: null,
626
642
  logoUrl: "https://cdn.simpleicons.org/airtable",
@@ -653,6 +669,7 @@ export const PROVIDER_SEED_DATA: Record<
653
669
  baseUrl: "https://api.hubapi.com",
654
670
  displayLabel: "HubSpot",
655
671
  description: "CRM contacts and deals",
672
+ category: "sales",
656
673
  dashboardUrl: "https://developers.hubspot.com/",
657
674
  clientIdPlaceholder: null,
658
675
  logoUrl: "https://cdn.simpleicons.org/hubspot",
@@ -696,6 +713,7 @@ export const PROVIDER_SEED_DATA: Record<
696
713
  baseUrl: "https://login.salesforce.com",
697
714
  displayLabel: "Salesforce",
698
715
  description: "CRM contacts, leads, and opportunities",
716
+ category: "sales",
699
717
  dashboardUrl:
700
718
  "https://help.salesforce.com/s/articleView?id=sf.connected_app_create.htm&type=5",
701
719
  clientIdPlaceholder: null,
@@ -744,6 +762,7 @@ export const PROVIDER_SEED_DATA: Record<
744
762
  baseUrl: "https://api.monday.com",
745
763
  displayLabel: "monday.com",
746
764
  description: "Boards, items, docs, and updates",
765
+ category: "productivity",
747
766
  dashboardUrl: "https://auth.monday.com/apps",
748
767
  clientIdPlaceholder: null,
749
768
  // Simple Icons does not host a monday.com mark (both `monday` and
@@ -868,6 +887,7 @@ export const PROVIDER_SEED_DATA: Record<
868
887
  baseUrl: "https://www.eventbriteapi.com",
869
888
  displayLabel: "Eventbrite",
870
889
  description: "Events, attendees, and ticket orders",
890
+ category: "commerce",
871
891
  dashboardUrl: "https://www.eventbrite.com/platform/api-keys/",
872
892
  clientIdPlaceholder: null,
873
893
  // Simple Icons does not host an Eventbrite mark (cdn.simpleicons.org
@@ -904,6 +924,7 @@ export const PROVIDER_SEED_DATA: Record<
904
924
  baseUrl: "https://api.calendly.com",
905
925
  displayLabel: "Calendly",
906
926
  description: "Scheduling links and meetings",
927
+ category: "meetings",
907
928
  dashboardUrl: "https://calendly.com/integrations/api_webhooks",
908
929
  clientIdPlaceholder: null,
909
930
  logoUrl: "https://cdn.simpleicons.org/calendly",
@@ -1003,6 +1024,7 @@ export const PROVIDER_SEED_DATA: Record<
1003
1024
  baseUrl: "https://api.figma.com/v1",
1004
1025
  displayLabel: "Figma",
1005
1026
  description: "Design files and comments",
1027
+ category: "engineering",
1006
1028
  dashboardUrl: "https://www.figma.com/developers/apps",
1007
1029
  clientIdPlaceholder: null,
1008
1030
  logoUrl: "https://cdn.simpleicons.org/figma",
@@ -1178,6 +1200,7 @@ export const PROVIDER_SEED_DATA: Record<
1178
1200
  baseUrl: "https://graph.microsoft.com",
1179
1201
  displayLabel: "Outlook / Microsoft",
1180
1202
  description: "Email and calendar",
1203
+ category: "productivity",
1181
1204
  dashboardUrl:
1182
1205
  "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade",
1183
1206
  clientIdPlaceholder: "Application (client) ID from Azure portal",
@@ -1236,6 +1259,7 @@ export const PROVIDER_SEED_DATA: Record<
1236
1259
  baseUrl: "https://slack.com/api",
1237
1260
  displayLabel: "Slack Channel",
1238
1261
  description: "Channel bot token",
1262
+ category: "communication",
1239
1263
  dashboardUrl: null,
1240
1264
  clientIdPlaceholder: null,
1241
1265
  requiresClientSecret: false,
@@ -1259,6 +1283,7 @@ export const PROVIDER_SEED_DATA: Record<
1259
1283
  baseUrl: "https://discord.com/api/v10",
1260
1284
  displayLabel: "Discord Server",
1261
1285
  description: "A bot in your server",
1286
+ category: "communication",
1262
1287
  dashboardUrl: "https://discord.com/developers/applications",
1263
1288
  clientIdPlaceholder: null,
1264
1289
  requiresClientSecret: false,
@@ -1281,6 +1306,7 @@ export const PROVIDER_SEED_DATA: Record<
1281
1306
  baseUrl: "https://api.telegram.org",
1282
1307
  displayLabel: "Telegram",
1283
1308
  description: "Bot messaging",
1309
+ category: "communication",
1284
1310
  dashboardUrl: null,
1285
1311
  clientIdPlaceholder: null,
1286
1312
  requiresClientSecret: false,
@@ -1295,6 +1321,7 @@ export const PROVIDER_SEED_DATA: Record<
1295
1321
  baseUrl: "https://api.sanity.io",
1296
1322
  displayLabel: "Sanity",
1297
1323
  description: "Content management platform",
1324
+ category: "marketing",
1298
1325
  dashboardUrl: "https://www.sanity.io/manage",
1299
1326
  clientIdPlaceholder: null,
1300
1327
  requiresClientSecret: false,
@@ -1323,6 +1350,7 @@ export const PROVIDER_SEED_DATA: Record<
1323
1350
  baseUrl: "https://api.link.com",
1324
1351
  displayLabel: "Link by Stripe",
1325
1352
  description: "Wallet payment methods for agent purchases",
1353
+ category: "commerce",
1326
1354
  dashboardUrl: "https://dashboard.stripe.com",
1327
1355
  // Link issues OAuth clients by request rather than through a self-serve
1328
1356
  // dashboard, so there is no placeholder shape to suggest.
@@ -1386,6 +1414,7 @@ export const PROVIDER_SEED_DATA: Record<
1386
1414
  baseUrl: "https://{tenant_host}",
1387
1415
  displayLabel: "Shopify",
1388
1416
  description: "Products, orders, customers, and inventory",
1417
+ category: "commerce",
1389
1418
  dashboardUrl: "https://shopify.dev/dashboard",
1390
1419
  clientIdPlaceholder: null,
1391
1420
  logoUrl: "https://cdn.simpleicons.org/shopify",
@@ -1611,6 +1640,7 @@ export const PROVIDER_SEED_DATA: Record<
1611
1640
  // managed sandbox connection to the production host).
1612
1641
  displayLabel: "QuickBooks",
1613
1642
  description: "Invoices, customers, vendors, and accounting data",
1643
+ category: "finance",
1614
1644
  dashboardUrl: "https://developer.intuit.com/app/developer/dashboard",
1615
1645
  clientIdPlaceholder: null,
1616
1646
  logoUrl: "https://cdn.simpleicons.org/quickbooks",
@@ -11,6 +11,12 @@ import {
11
11
  type LiveVoiceSessionOutcome,
12
12
  type LiveVoiceStepName,
13
13
  } from "../telemetry/live-voice-funnel.js";
14
+ import {
15
+ PHONE_CALL_FUNNEL_VERSION,
16
+ PHONE_CALL_STEPS,
17
+ type PhoneCallOutcome,
18
+ type PhoneCallStepName,
19
+ } from "../telemetry/phone-call-funnel.js";
14
20
  import { recordTelemetryOutboxEvent } from "../telemetry/telemetry-events-outbox.js";
15
21
  import type { OnboardingTelemetryEvent } from "../telemetry/types.js";
16
22
  import { getLogger } from "../util/logger.js";
@@ -136,12 +142,13 @@ export function recordActivationEvent(params: {
136
142
  * database is unavailable.
137
143
  *
138
144
  * **Never throws.** These fire from `LiveVoiceSession.start()` and `.close()`,
139
- * which are the user's call itself: the outbox insert raises on a telemetry DB
140
- * that is missing, locked, or mid-migration, and an uncaught raise there would
141
- * fail the session rather than the measurement. A dropped row costs a gap in a
142
- * chart; a raised one costs the user their conversation.
145
+ * and from the call store's create and status writes, which are the user's
146
+ * call itself: the outbox insert raises on a telemetry DB that is missing,
147
+ * locked, or mid-migration, and an uncaught raise there would fail the session
148
+ * rather than the measurement. A dropped row costs a gap in a chart; a raised
149
+ * one costs the user their conversation.
143
150
  */
144
- function recordLiveVoiceEventSafely(
151
+ function recordVoiceFunnelEventSafely(
145
152
  record: () => OnboardingEvent | null,
146
153
  ): OnboardingEvent | null {
147
154
  try {
@@ -155,28 +162,51 @@ function recordLiveVoiceEventSafely(
155
162
  }
156
163
  }
157
164
 
158
- export function recordLiveVoiceSessionEvent(params: {
159
- stepName: LiveVoiceStepName;
165
+ /**
166
+ * Build one voice funnel row. The live-voice and phone-call funnels differ
167
+ * only in their version stamp and step vocabulary, so they share the row
168
+ * shape: same substrate, same session-keyed pairing, same duration math.
169
+ */
170
+ function recordVoiceFunnelEvent(params: {
171
+ funnelVersion: string;
172
+ stepName: string;
160
173
  stepIndex: number;
161
174
  sessionId: string;
162
- screen?: string;
163
- outcome?: LiveVoiceSessionOutcome;
175
+ screen: string;
176
+ outcome?: string;
164
177
  }): OnboardingEvent | null {
165
- return recordLiveVoiceEventSafely(() =>
178
+ return recordVoiceFunnelEventSafely(() =>
166
179
  recordTelemetryOutboxEvent("onboarding", (id, createdAt) =>
167
180
  buildOnboardingTelemetryEvent(id, createdAt, {
168
- screen: params.screen ?? params.stepName,
181
+ screen: params.screen,
169
182
  sessionId: params.sessionId,
170
183
  stepName: params.stepName,
171
184
  stepIndex: params.stepIndex,
172
185
  completedAt: new Date(createdAt).toISOString(),
173
- funnelVersion: LIVE_VOICE_FUNNEL_VERSION,
186
+ funnelVersion: params.funnelVersion,
174
187
  ...(params.outcome ? { outcome: params.outcome } : {}),
175
188
  }),
176
189
  ),
177
190
  );
178
191
  }
179
192
 
193
+ export function recordLiveVoiceSessionEvent(params: {
194
+ stepName: LiveVoiceStepName;
195
+ stepIndex: number;
196
+ sessionId: string;
197
+ screen?: string;
198
+ outcome?: LiveVoiceSessionOutcome;
199
+ }): OnboardingEvent | null {
200
+ return recordVoiceFunnelEvent({
201
+ funnelVersion: LIVE_VOICE_FUNNEL_VERSION,
202
+ stepName: params.stepName,
203
+ stepIndex: params.stepIndex,
204
+ sessionId: params.sessionId,
205
+ screen: params.screen ?? params.stepName,
206
+ ...(params.outcome ? { outcome: params.outcome } : {}),
207
+ });
208
+ }
209
+
180
210
  /**
181
211
  * Record the "a live-voice session was attempted" milestone, with where it
182
212
  * was attempted from.
@@ -207,3 +237,60 @@ export function recordLiveVoiceSessionEnded(params: {
207
237
  outcome: params.outcome,
208
238
  });
209
239
  }
240
+
241
+ /**
242
+ * Record a phone-call milestone (started / ended) on the same substrate as the
243
+ * live-voice pair, keyed by the call session id so the two events pair up
244
+ * downstream. See `telemetry/phone-call-funnel.ts` for why duration and turn
245
+ * count are derived from that pairing rather than carried as fields.
246
+ *
247
+ * Returns null when usage data collection is disabled or the telemetry
248
+ * database is unavailable, and never throws: these fire from the call store's
249
+ * writes, on the call's own path.
250
+ */
251
+ function recordPhoneCallEvent(params: {
252
+ stepName: PhoneCallStepName;
253
+ stepIndex: number;
254
+ callSessionId: string;
255
+ screen: string;
256
+ outcome?: PhoneCallOutcome;
257
+ }): OnboardingEvent | null {
258
+ return recordVoiceFunnelEvent({
259
+ funnelVersion: PHONE_CALL_FUNNEL_VERSION,
260
+ stepName: params.stepName,
261
+ stepIndex: params.stepIndex,
262
+ sessionId: params.callSessionId,
263
+ screen: params.screen,
264
+ ...(params.outcome ? { outcome: params.outcome } : {}),
265
+ });
266
+ }
267
+
268
+ /**
269
+ * Record the "a phone call was attempted" milestone, with how it was placed.
270
+ */
271
+ export function recordPhoneCallStarted(params: {
272
+ callSessionId: string;
273
+ screen: string;
274
+ }): OnboardingEvent | null {
275
+ return recordPhoneCallEvent({
276
+ stepName: PHONE_CALL_STEPS.callStarted.stepName,
277
+ stepIndex: PHONE_CALL_STEPS.callStarted.stepIndex,
278
+ callSessionId: params.callSessionId,
279
+ screen: params.screen,
280
+ });
281
+ }
282
+
283
+ /** Record the "a phone call ended" milestone, with how it ended. */
284
+ export function recordPhoneCallEnded(params: {
285
+ callSessionId: string;
286
+ screen: string;
287
+ outcome: PhoneCallOutcome;
288
+ }): OnboardingEvent | null {
289
+ return recordPhoneCallEvent({
290
+ stepName: PHONE_CALL_STEPS.callEnded.stepName,
291
+ stepIndex: PHONE_CALL_STEPS.callEnded.stepIndex,
292
+ callSessionId: params.callSessionId,
293
+ screen: params.screen,
294
+ outcome: params.outcome,
295
+ });
296
+ }
@@ -0,0 +1,322 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { describe, expect, test } from "bun:test";
3
+
4
+ import { drizzle } from "drizzle-orm/bun-sqlite";
5
+
6
+ import {
7
+ CLIENT_CONNECTION_EVENT_RETENTION_MS,
8
+ CLIENT_CONNECTION_FLAP_WINDOW_MS,
9
+ type ClientConnectionEvent,
10
+ coalesceClientConnectionSessions,
11
+ listClientConnectionHistory,
12
+ recordClientConnectionEvent,
13
+ } from "../client-connection-events-store.js";
14
+ import { migrateCreateClientConnectionEvents } from "../migrations/382-create-client-connection-events.js";
15
+ import * as schema from "../schema.js";
16
+
17
+ function createTestDb() {
18
+ const sqlite = new Database(":memory:");
19
+ sqlite.exec("PRAGMA journal_mode=WAL");
20
+ const db = drizzle(sqlite, { schema });
21
+ migrateCreateClientConnectionEvents(db);
22
+ return db;
23
+ }
24
+
25
+ function event(
26
+ overrides: Partial<ClientConnectionEvent> &
27
+ Pick<ClientConnectionEvent, "reason" | "occurredAt">,
28
+ ): ClientConnectionEvent {
29
+ return {
30
+ id: overrides.id ?? `evt-${overrides.occurredAt}`,
31
+ clientId: overrides.clientId ?? "client-123",
32
+ interfaceId: overrides.interfaceId ?? "chrome-extension",
33
+ connectionId: overrides.connectionId ?? `conn-${overrides.occurredAt}`,
34
+ reason: overrides.reason,
35
+ occurredAt: overrides.occurredAt,
36
+ actorPrincipalId: overrides.actorPrincipalId ?? "user-123",
37
+ clientVersion: overrides.clientVersion ?? "0.12.1",
38
+ sseWatchdog: overrides.sseWatchdog ?? true,
39
+ machineName: overrides.machineName ?? null,
40
+ };
41
+ }
42
+
43
+ describe("coalesceClientConnectionSessions", () => {
44
+ test("merges a reconnect shorter than the flap window", () => {
45
+ const sessions = coalesceClientConnectionSessions(
46
+ [
47
+ event({
48
+ reason: "sse_open",
49
+ occurredAt: 1_000,
50
+ connectionId: "conn-1",
51
+ }),
52
+ event({
53
+ reason: "stale_replaced",
54
+ occurredAt: 2_000,
55
+ connectionId: "conn-1",
56
+ }),
57
+ event({
58
+ reason: "sse_open",
59
+ occurredAt: 2_000 + CLIENT_CONNECTION_FLAP_WINDOW_MS - 1,
60
+ connectionId: "conn-2",
61
+ }),
62
+ ],
63
+ 10_000 + CLIENT_CONNECTION_FLAP_WINDOW_MS,
64
+ );
65
+
66
+ expect(sessions).toHaveLength(1);
67
+ expect(sessions[0].flapCount).toBe(1);
68
+ expect(sessions[0].endedAt).toBeNull();
69
+ expect(sessions[0].connectionIds).toHaveLength(2);
70
+ });
71
+
72
+ test("keeps a gap at or beyond the flap window as a separate session", () => {
73
+ const sessions = coalesceClientConnectionSessions([
74
+ event({ reason: "sse_open", occurredAt: 1_000 }),
75
+ event({ reason: "sse_close", occurredAt: 2_000 }),
76
+ event({
77
+ reason: "sse_open",
78
+ occurredAt: 2_000 + CLIENT_CONNECTION_FLAP_WINDOW_MS,
79
+ }),
80
+ ]);
81
+
82
+ expect(sessions).toHaveLength(2);
83
+ expect(sessions.every((session) => session.flapCount === 0)).toBe(true);
84
+ });
85
+
86
+ test("leaves an unmatched open as a still-connected session", () => {
87
+ const now = 8_000;
88
+ const sessions = coalesceClientConnectionSessions(
89
+ [event({ reason: "sse_open", occurredAt: 1_000 })],
90
+ now,
91
+ );
92
+
93
+ expect(sessions).toHaveLength(1);
94
+ expect(sessions[0].endedAt).toBeNull();
95
+ expect(sessions[0].durationMs).toBe(7_000);
96
+ expect(sessions[0].closeReason).toBeNull();
97
+ });
98
+
99
+ test("ends an orphaned open when a later open arrives with no close", () => {
100
+ const sessions = coalesceClientConnectionSessions(
101
+ [
102
+ event({
103
+ reason: "sse_open",
104
+ occurredAt: 1_000,
105
+ connectionId: "conn-1",
106
+ }),
107
+ event({
108
+ reason: "sse_open",
109
+ occurredAt: 5_000,
110
+ connectionId: "conn-2",
111
+ }),
112
+ ],
113
+ 8_000,
114
+ );
115
+
116
+ expect(sessions).toHaveLength(2);
117
+ expect(sessions[1].startedAt).toBe(1_000);
118
+ expect(sessions[1].endedAt).toBe(5_000);
119
+ expect(sessions[1].closeReason).toBe("implicit_replaced");
120
+ expect(sessions[1].durationMs).toBe(4_000);
121
+ expect(sessions[0].startedAt).toBe(5_000);
122
+ expect(sessions[0].endedAt).toBeNull();
123
+ expect(sessions[0].durationMs).toBe(3_000);
124
+ });
125
+ });
126
+
127
+ describe("recordClientConnectionEvent / listClientConnectionHistory", () => {
128
+ test("writes events and returns coalesced sessions", () => {
129
+ const db = createTestDb();
130
+ const t0 = 1_700_000_000_000;
131
+
132
+ recordClientConnectionEvent(
133
+ {
134
+ clientId: "client-123",
135
+ interfaceId: "chrome-extension",
136
+ connectionId: "conn-1",
137
+ reason: "sse_open",
138
+ occurredAt: t0,
139
+ actorPrincipalId: "user-123",
140
+ clientVersion: "0.12.1",
141
+ sseWatchdog: true,
142
+ },
143
+ db,
144
+ );
145
+ recordClientConnectionEvent(
146
+ {
147
+ clientId: "client-123",
148
+ interfaceId: "chrome-extension",
149
+ connectionId: "conn-1",
150
+ reason: "stale_replaced",
151
+ occurredAt: t0 + 5_000,
152
+ actorPrincipalId: "user-123",
153
+ },
154
+ db,
155
+ );
156
+ recordClientConnectionEvent(
157
+ {
158
+ clientId: "client-123",
159
+ interfaceId: "chrome-extension",
160
+ connectionId: "conn-2",
161
+ reason: "sse_open",
162
+ occurredAt: t0 + 6_000,
163
+ actorPrincipalId: "user-123",
164
+ clientVersion: "0.12.1",
165
+ sseWatchdog: true,
166
+ },
167
+ db,
168
+ );
169
+
170
+ const history = listClientConnectionHistory(
171
+ { clientId: "client-123", now: t0 + 10_000 },
172
+ db,
173
+ );
174
+
175
+ expect(history.events).toHaveLength(3);
176
+ expect(history.sessions).toHaveLength(1);
177
+ expect(history.sessions[0].flapCount).toBe(1);
178
+ expect(history.sessions[0].endedAt).toBeNull();
179
+ expect(history.sessions[0].sseWatchdog).toBe(true);
180
+ expect(history.sessions[0].clientVersion).toBe("0.12.1");
181
+ });
182
+
183
+ test("prunes rows older than the retention window", () => {
184
+ const db = createTestDb();
185
+ const now = 1_700_000_000_000;
186
+
187
+ recordClientConnectionEvent(
188
+ {
189
+ clientId: "client-123",
190
+ interfaceId: "chrome-extension",
191
+ connectionId: "conn-old",
192
+ reason: "sse_open",
193
+ occurredAt: now - CLIENT_CONNECTION_EVENT_RETENTION_MS - 1,
194
+ },
195
+ db,
196
+ );
197
+ recordClientConnectionEvent(
198
+ {
199
+ clientId: "client-123",
200
+ interfaceId: "chrome-extension",
201
+ connectionId: "conn-new",
202
+ reason: "sse_open",
203
+ occurredAt: now,
204
+ },
205
+ db,
206
+ );
207
+
208
+ const history = listClientConnectionHistory({ now }, db);
209
+ expect(history.events).toHaveLength(1);
210
+ expect(history.events[0].connectionId).toBe("conn-new");
211
+ });
212
+
213
+ test("does not throw when listing without an injected database", () => {
214
+ const history = listClientConnectionHistory();
215
+ expect(Array.isArray(history.events)).toBe(true);
216
+ expect(Array.isArray(history.sessions)).toBe(true);
217
+ });
218
+
219
+ test("preserves a session that opened before the since bound", () => {
220
+ const db = createTestDb();
221
+ const t0 = 1_700_000_000_000;
222
+
223
+ recordClientConnectionEvent(
224
+ {
225
+ clientId: "client-123",
226
+ interfaceId: "chrome-extension",
227
+ connectionId: "conn-1",
228
+ reason: "sse_open",
229
+ occurredAt: t0,
230
+ actorPrincipalId: "user-123",
231
+ },
232
+ db,
233
+ );
234
+ recordClientConnectionEvent(
235
+ {
236
+ clientId: "client-123",
237
+ interfaceId: "chrome-extension",
238
+ connectionId: "conn-1",
239
+ reason: "sse_close",
240
+ occurredAt: t0 + 8_000,
241
+ actorPrincipalId: "user-123",
242
+ },
243
+ db,
244
+ );
245
+
246
+ const history = listClientConnectionHistory(
247
+ { clientId: "client-123", since: t0 + 5_000, now: t0 + 10_000 },
248
+ db,
249
+ );
250
+
251
+ expect(history.sessions).toHaveLength(1);
252
+ expect(history.sessions[0].startedAt).toBe(t0);
253
+ expect(history.sessions[0].endedAt).toBe(t0 + 8_000);
254
+ expect(history.sessions[0].durationMs).toBe(8_000);
255
+ expect(history.events).toHaveLength(1);
256
+ expect(history.events[0].reason).toBe("sse_close");
257
+ });
258
+
259
+ test("keeps a still-open session whose only event is before since", () => {
260
+ const db = createTestDb();
261
+ const t0 = 1_700_000_000_000;
262
+
263
+ recordClientConnectionEvent(
264
+ {
265
+ clientId: "client-123",
266
+ interfaceId: "chrome-extension",
267
+ connectionId: "conn-1",
268
+ reason: "sse_open",
269
+ occurredAt: t0,
270
+ actorPrincipalId: "user-123",
271
+ },
272
+ db,
273
+ );
274
+
275
+ const history = listClientConnectionHistory(
276
+ { clientId: "client-123", since: t0 + 5_000, now: t0 + 10_000 },
277
+ db,
278
+ );
279
+
280
+ expect(history.sessions).toHaveLength(1);
281
+ expect(history.sessions[0].startedAt).toBe(t0);
282
+ expect(history.sessions[0].endedAt).toBeNull();
283
+ expect(history.sessions[0].durationMs).toBe(10_000);
284
+ expect(history.events).toHaveLength(0);
285
+ });
286
+
287
+ test("omits a session that ended before the since bound", () => {
288
+ const db = createTestDb();
289
+ const t0 = 1_700_000_000_000;
290
+
291
+ recordClientConnectionEvent(
292
+ {
293
+ clientId: "client-123",
294
+ interfaceId: "chrome-extension",
295
+ connectionId: "conn-old",
296
+ reason: "sse_open",
297
+ occurredAt: t0,
298
+ actorPrincipalId: "user-123",
299
+ },
300
+ db,
301
+ );
302
+ recordClientConnectionEvent(
303
+ {
304
+ clientId: "client-123",
305
+ interfaceId: "chrome-extension",
306
+ connectionId: "conn-old",
307
+ reason: "sse_close",
308
+ occurredAt: t0 + 1_000,
309
+ actorPrincipalId: "user-123",
310
+ },
311
+ db,
312
+ );
313
+
314
+ const history = listClientConnectionHistory(
315
+ { clientId: "client-123", since: t0 + 5_000, now: t0 + 10_000 },
316
+ db,
317
+ );
318
+
319
+ expect(history.sessions).toHaveLength(0);
320
+ expect(history.events).toHaveLength(0);
321
+ });
322
+ });