@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
@@ -154,6 +154,173 @@ export async function dispatchInsertText(
154
154
  await cdp.send("Input.insertText", { text }, signal);
155
155
  }
156
156
 
157
+ interface TextInsertionOptions {
158
+ clearFirst: boolean;
159
+ verify?: boolean;
160
+ }
161
+
162
+ /**
163
+ * Select editable content, insert text through CDP, and confirm that the live
164
+ * target contains the requested text. Controls without text-selection support
165
+ * are cleared through their native value setter and an input event.
166
+ */
167
+ export async function insertTextIntoElement(
168
+ cdp: CdpClient,
169
+ backendNodeId: number,
170
+ text: string,
171
+ options: TextInsertionOptions,
172
+ signal?: AbortSignal,
173
+ ): Promise<void> {
174
+ await focusElement(cdp, backendNodeId, signal);
175
+
176
+ const { object } = await cdp.send<{ object: { objectId: string } }>(
177
+ "DOM.resolveNode",
178
+ { backendNodeId },
179
+ signal,
180
+ );
181
+ const selection = await cdp.send<{
182
+ result?: {
183
+ value?: { initialLength?: number; needsRefocus?: boolean };
184
+ };
185
+ exceptionDetails?: { text?: string; exception?: { description?: string } };
186
+ }>(
187
+ "Runtime.callFunctionOn",
188
+ {
189
+ objectId: object.objectId,
190
+ functionDeclaration: `function(clearFirst) {
191
+ if (typeof this.value === "string") {
192
+ const value = this.value;
193
+ if (clearFirst && typeof this.select === "function") {
194
+ try {
195
+ this.select();
196
+ if (this.selectionStart === 0 && this.selectionEnd === value.length) {
197
+ return { needsRefocus: false };
198
+ }
199
+ } catch {}
200
+
201
+ const view = this.ownerDocument?.defaultView;
202
+ const constructor = this.tagName === "INPUT"
203
+ ? view?.HTMLInputElement
204
+ : this.tagName === "TEXTAREA"
205
+ ? view?.HTMLTextAreaElement
206
+ : undefined;
207
+ const valueSetter = constructor
208
+ ? Object.getOwnPropertyDescriptor(constructor.prototype, "value")?.set
209
+ : undefined;
210
+ if (!valueSetter || !view?.InputEvent) {
211
+ throw new Error("Element does not support replacing its text");
212
+ }
213
+ valueSetter.call(this, "");
214
+ this.dispatchEvent(new view.InputEvent("input", {
215
+ bubbles: true,
216
+ inputType: "deleteContentBackward",
217
+ data: null,
218
+ }));
219
+ return { needsRefocus: true };
220
+ }
221
+ if (typeof this.setSelectionRange === "function") {
222
+ const end = this.value.length;
223
+ try {
224
+ this.setSelectionRange(clearFirst ? 0 : end, end);
225
+ } catch (error) {
226
+ if (clearFirst) {
227
+ throw error;
228
+ }
229
+ }
230
+ return clearFirst
231
+ ? { needsRefocus: false }
232
+ : { initialLength: value.length, needsRefocus: false };
233
+ }
234
+ }
235
+ if (this.isContentEditable) {
236
+ const value = this.textContent ?? "";
237
+ const selection = this.ownerDocument.getSelection();
238
+ const range = this.ownerDocument.createRange();
239
+ range.selectNodeContents(this);
240
+ if (!clearFirst) {
241
+ range.collapse(false);
242
+ }
243
+ selection.removeAllRanges();
244
+ selection.addRange(range);
245
+ return clearFirst
246
+ ? { needsRefocus: false }
247
+ : { initialLength: value.length, needsRefocus: false };
248
+ }
249
+ throw new Error("Element is not an editable text target");
250
+ }`,
251
+ arguments: [{ value: options.clearFirst }],
252
+ returnByValue: true,
253
+ },
254
+ signal,
255
+ );
256
+ if (selection.exceptionDetails) {
257
+ const message =
258
+ selection.exceptionDetails.exception?.description ??
259
+ selection.exceptionDetails.text ??
260
+ "Unable to select editable text";
261
+ throw new CdpError("cdp_error", message, {
262
+ cdpMethod: "Runtime.callFunctionOn",
263
+ cdpParams: { backendNodeId },
264
+ });
265
+ }
266
+
267
+ if (selection.result?.value?.needsRefocus === true) {
268
+ await focusElement(cdp, backendNodeId, signal);
269
+ }
270
+ await dispatchInsertText(cdp, text, signal);
271
+ if (options.verify === false) {
272
+ return;
273
+ }
274
+
275
+ for (let attempt = 0; attempt < 3; attempt += 1) {
276
+ const verification = await cdp.send<{
277
+ result?: { value?: { connected?: boolean; matches?: boolean } };
278
+ }>(
279
+ "Runtime.callFunctionOn",
280
+ {
281
+ objectId: object.objectId,
282
+ functionDeclaration: `function(insertedText, clearFirst, initialLength) {
283
+ const text = typeof this.value === "string"
284
+ ? this.value
285
+ : (this.textContent ?? "");
286
+ const normalizedInsertedText = this.tagName === "TEXTAREA"
287
+ ? insertedText.replace(/\\r\\n?/g, "\\n")
288
+ : insertedText;
289
+ const matches = clearFirst
290
+ ? text === normalizedInsertedText
291
+ : Number.isInteger(initialLength)
292
+ && text.length === initialLength + normalizedInsertedText.length
293
+ && text.endsWith(normalizedInsertedText);
294
+ return { connected: this.isConnected, matches };
295
+ }`,
296
+ arguments: [
297
+ { value: text },
298
+ { value: options.clearFirst },
299
+ { value: selection.result?.value?.initialLength ?? null },
300
+ ],
301
+ returnByValue: true,
302
+ },
303
+ signal,
304
+ );
305
+ const result = verification.result?.value;
306
+ if (result?.connected === true && result.matches === true) {
307
+ return;
308
+ }
309
+ if (attempt < 2) {
310
+ await new Promise((resolve) => setTimeout(resolve, 50));
311
+ }
312
+ }
313
+
314
+ throw new CdpError(
315
+ "cdp_error",
316
+ "Text insertion did not persist in the editable element.",
317
+ {
318
+ cdpMethod: "Input.insertText",
319
+ cdpParams: { backendNodeId },
320
+ },
321
+ );
322
+ }
323
+
157
324
  /**
158
325
  * Per-key descriptor used by {@link dispatchKeyPress}. Mirrors the
159
326
  * fields CDP's `Input.dispatchKeyEvent` accepts. `text` is set only
@@ -166,6 +333,116 @@ interface KeyDescriptor {
166
333
  text?: string;
167
334
  }
168
335
 
336
+ interface ModifierDescriptor {
337
+ bit: number;
338
+ descriptor: KeyDescriptor;
339
+ }
340
+
341
+ const ALT_MODIFIER: ModifierDescriptor = {
342
+ bit: 1,
343
+ descriptor: { key: "Alt", code: "AltLeft", windowsVirtualKeyCode: 18 },
344
+ };
345
+ const CONTROL_MODIFIER: ModifierDescriptor = {
346
+ bit: 2,
347
+ descriptor: {
348
+ key: "Control",
349
+ code: "ControlLeft",
350
+ windowsVirtualKeyCode: 17,
351
+ },
352
+ };
353
+ const META_MODIFIER: ModifierDescriptor = {
354
+ bit: 4,
355
+ descriptor: { key: "Meta", code: "MetaLeft", windowsVirtualKeyCode: 91 },
356
+ };
357
+ const SHIFT_MODIFIER: ModifierDescriptor = {
358
+ bit: 8,
359
+ descriptor: {
360
+ key: "Shift",
361
+ code: "ShiftLeft",
362
+ windowsVirtualKeyCode: 16,
363
+ },
364
+ };
365
+
366
+ const MODIFIER_DESCRIPTORS: Record<string, ModifierDescriptor> = {
367
+ alt: ALT_MODIFIER,
368
+ option: ALT_MODIFIER,
369
+ control: CONTROL_MODIFIER,
370
+ ctrl: CONTROL_MODIFIER,
371
+ meta: META_MODIFIER,
372
+ command: META_MODIFIER,
373
+ cmd: META_MODIFIER,
374
+ shift: SHIFT_MODIFIER,
375
+ };
376
+
377
+ const PUNCTUATION_KEYS = [
378
+ {
379
+ unshifted: "`",
380
+ shifted: "~",
381
+ code: "Backquote",
382
+ windowsVirtualKeyCode: 192,
383
+ },
384
+ {
385
+ unshifted: "-",
386
+ shifted: "_",
387
+ code: "Minus",
388
+ windowsVirtualKeyCode: 189,
389
+ },
390
+ {
391
+ unshifted: "=",
392
+ shifted: "+",
393
+ code: "Equal",
394
+ windowsVirtualKeyCode: 187,
395
+ },
396
+ {
397
+ unshifted: "[",
398
+ shifted: "{",
399
+ code: "BracketLeft",
400
+ windowsVirtualKeyCode: 219,
401
+ },
402
+ {
403
+ unshifted: "]",
404
+ shifted: "}",
405
+ code: "BracketRight",
406
+ windowsVirtualKeyCode: 221,
407
+ },
408
+ {
409
+ unshifted: "\\",
410
+ shifted: "|",
411
+ code: "Backslash",
412
+ windowsVirtualKeyCode: 220,
413
+ },
414
+ {
415
+ unshifted: ";",
416
+ shifted: ":",
417
+ code: "Semicolon",
418
+ windowsVirtualKeyCode: 186,
419
+ },
420
+ {
421
+ unshifted: "'",
422
+ shifted: '"',
423
+ code: "Quote",
424
+ windowsVirtualKeyCode: 222,
425
+ },
426
+ {
427
+ unshifted: ",",
428
+ shifted: "<",
429
+ code: "Comma",
430
+ windowsVirtualKeyCode: 188,
431
+ },
432
+ {
433
+ unshifted: ".",
434
+ shifted: ">",
435
+ code: "Period",
436
+ windowsVirtualKeyCode: 190,
437
+ },
438
+ {
439
+ unshifted: "/",
440
+ shifted: "?",
441
+ code: "Slash",
442
+ windowsVirtualKeyCode: 191,
443
+ },
444
+ ] as const;
445
+
169
446
  /**
170
447
  * Subset of the US keyboard layout used to populate
171
448
  * `Input.dispatchKeyEvent` params. Without these fields, sites that
@@ -182,7 +459,7 @@ const KEY_DESCRIPTORS: Record<string, KeyDescriptor> = {
182
459
  windowsVirtualKeyCode: 13,
183
460
  text: "\r",
184
461
  },
185
- Tab: { key: "Tab", code: "Tab", windowsVirtualKeyCode: 9, text: "\t" },
462
+ Tab: { key: "Tab", code: "Tab", windowsVirtualKeyCode: 9 },
186
463
  Escape: { key: "Escape", code: "Escape", windowsVirtualKeyCode: 27 },
187
464
  Backspace: {
188
465
  key: "Backspace",
@@ -251,6 +528,17 @@ function resolveKeyDescriptor(key: string): KeyDescriptor | null {
251
528
  if (fromMap) {
252
529
  return fromMap;
253
530
  }
531
+ const punctuation = PUNCTUATION_KEYS.find(
532
+ ({ unshifted, shifted }) => key === unshifted || key === shifted,
533
+ );
534
+ if (punctuation) {
535
+ return {
536
+ key,
537
+ code: punctuation.code,
538
+ windowsVirtualKeyCode: punctuation.windowsVirtualKeyCode,
539
+ text: key,
540
+ };
541
+ }
254
542
  if (key.length !== 1) {
255
543
  return null;
256
544
  }
@@ -291,60 +579,168 @@ function resolveKeyDescriptor(key: string): KeyDescriptor | null {
291
579
  return null;
292
580
  }
293
581
 
582
+ function describeKeyEvent(
583
+ descriptor: KeyDescriptor,
584
+ type: "rawKeyDown" | "char" | "keyUp",
585
+ modifiers: number,
586
+ unmodifiedText = descriptor.text,
587
+ ): Record<string, unknown> {
588
+ const params: Record<string, unknown> = {
589
+ type,
590
+ key: descriptor.key,
591
+ code: descriptor.code,
592
+ windowsVirtualKeyCode: descriptor.windowsVirtualKeyCode,
593
+ };
594
+ if (modifiers !== 0) {
595
+ params.modifiers = modifiers;
596
+ }
597
+ if (type === "char" && descriptor.text !== undefined) {
598
+ params.text = descriptor.text;
599
+ params.unmodifiedText = unmodifiedText;
600
+ }
601
+ return params;
602
+ }
603
+
604
+ const SHIFTED_CHARACTERS: Record<string, string> = {
605
+ "1": "!",
606
+ "2": "@",
607
+ "3": "#",
608
+ "4": "$",
609
+ "5": "%",
610
+ "6": "^",
611
+ "7": "&",
612
+ "8": "*",
613
+ "9": "(",
614
+ "0": ")",
615
+ ...Object.fromEntries(
616
+ PUNCTUATION_KEYS.map(({ unshifted, shifted }) => [unshifted, shifted]),
617
+ ),
618
+ };
619
+
620
+ function applyShift(descriptor: KeyDescriptor): KeyDescriptor {
621
+ if (descriptor.text === undefined) {
622
+ return descriptor;
623
+ }
624
+ const shifted =
625
+ descriptor.text >= "a" && descriptor.text <= "z"
626
+ ? descriptor.text.toUpperCase()
627
+ : (SHIFTED_CHARACTERS[descriptor.text] ?? descriptor.text);
628
+ return { ...descriptor, key: shifted, text: shifted };
629
+ }
630
+
294
631
  /**
295
- * Press a single key (keyDown + optional `char` + keyUp). Resolves
296
- * the key name to a {@link KeyDescriptor} so CDP receives the right
297
- * `code` / `windowsVirtualKeyCode` / `text` fields — required by
298
- * sites that check `event.keyCode` (e.g. Enter-to-submit) or
299
- * `event.code`. For printable keys we also dispatch a `char` event
300
- * between keyDown and keyUp so the character is actually inserted
301
- * into focused inputs.
632
+ * Press a key or modifier chord using the same `Modifier+Key` spelling as
633
+ * Playwright. Printable keys use rawKeyDown + char + keyUp, with text only on
634
+ * the char event, so the browser inserts exactly one character.
302
635
  */
303
636
  export async function dispatchKeyPress(
304
637
  cdp: CdpClient,
305
638
  key: string,
306
639
  signal?: AbortSignal,
307
640
  ): Promise<void> {
308
- const desc = resolveKeyDescriptor(key);
309
- if (!desc) {
310
- // Unknown multi-character key (e.g. F-keys we have not mapped).
311
- // Fall back to the minimal payload so callers still see a
312
- // keyDown/keyUp pair, and warn so we can extend the map.
313
-
314
- console.warn(
315
- `dispatchKeyPress: no descriptor for key "${key}", sending minimal event`,
316
- );
317
- await cdp.send("Input.dispatchKeyEvent", { type: "keyDown", key }, signal);
318
- await cdp.send("Input.dispatchKeyEvent", { type: "keyUp", key }, signal);
319
- return;
641
+ const parts = key === "+" ? [key] : key.split("+");
642
+ const primaryKey = parts.at(-1) ?? "";
643
+ const modifierTokens = parts.slice(0, -1);
644
+ const modifiers: ModifierDescriptor[] = [];
645
+ let modifierBits = 0;
646
+
647
+ for (const token of modifierTokens) {
648
+ const modifier = MODIFIER_DESCRIPTORS[token.toLowerCase()];
649
+ if (!modifier || (modifierBits & modifier.bit) !== 0) {
650
+ throw new CdpError("cdp_error", `Unsupported key chord: ${key}`);
651
+ }
652
+ modifierBits |= modifier.bit;
653
+ modifiers.push(modifier);
320
654
  }
321
655
 
322
- const baseParams: Record<string, unknown> = {
323
- key: desc.key,
324
- code: desc.code,
325
- windowsVirtualKeyCode: desc.windowsVirtualKeyCode,
326
- };
327
- if (desc.text !== undefined) {
328
- baseParams.text = desc.text;
656
+ const standaloneModifier = MODIFIER_DESCRIPTORS[primaryKey.toLowerCase()];
657
+ if (standaloneModifier && (modifierBits & standaloneModifier.bit) !== 0) {
658
+ throw new CdpError("cdp_error", `Unsupported key chord: ${key}`);
659
+ }
660
+ const unmodifiedDescriptor =
661
+ standaloneModifier?.descriptor ?? resolveKeyDescriptor(primaryKey);
662
+ if (!unmodifiedDescriptor) {
663
+ throw new CdpError("cdp_error", `Unsupported key: ${primaryKey || key}`);
329
664
  }
665
+ const descriptor =
666
+ (modifierBits & SHIFT_MODIFIER.bit) !== 0
667
+ ? applyShift(unmodifiedDescriptor)
668
+ : unmodifiedDescriptor;
669
+ const primaryDownModifiers = modifierBits | (standaloneModifier?.bit ?? 0);
330
670
 
331
- await cdp.send(
332
- "Input.dispatchKeyEvent",
333
- { ...baseParams, type: "keyDown" },
334
- signal,
335
- );
336
- if (desc.text !== undefined) {
671
+ let activeModifiers = 0;
672
+ const pressedModifiers: ModifierDescriptor[] = [];
673
+ let primaryPressed = false;
674
+ try {
675
+ for (const modifier of modifiers) {
676
+ const nextModifiers = activeModifiers | modifier.bit;
677
+ activeModifiers = nextModifiers;
678
+ pressedModifiers.push(modifier);
679
+ await cdp.send(
680
+ "Input.dispatchKeyEvent",
681
+ describeKeyEvent(modifier.descriptor, "rawKeyDown", nextModifiers),
682
+ signal,
683
+ );
684
+ }
685
+
686
+ const suppressText = (modifierBits & (1 | 2 | 4)) !== 0;
687
+ primaryPressed = true;
337
688
  await cdp.send(
338
689
  "Input.dispatchKeyEvent",
339
- { ...baseParams, type: "char" },
690
+ describeKeyEvent(descriptor, "rawKeyDown", primaryDownModifiers),
340
691
  signal,
341
692
  );
693
+ if (descriptor.text !== undefined && !suppressText) {
694
+ await cdp.send(
695
+ "Input.dispatchKeyEvent",
696
+ describeKeyEvent(
697
+ descriptor,
698
+ "char",
699
+ modifierBits,
700
+ unmodifiedDescriptor.text,
701
+ ),
702
+ signal,
703
+ );
704
+ }
705
+ await cdp.send(
706
+ "Input.dispatchKeyEvent",
707
+ describeKeyEvent(descriptor, "keyUp", modifierBits),
708
+ signal,
709
+ );
710
+ primaryPressed = false;
711
+
712
+ while (pressedModifiers.length > 0) {
713
+ const modifier = pressedModifiers.at(-1)!;
714
+ const nextModifiers = activeModifiers & ~modifier.bit;
715
+ await cdp.send(
716
+ "Input.dispatchKeyEvent",
717
+ describeKeyEvent(modifier.descriptor, "keyUp", nextModifiers),
718
+ signal,
719
+ );
720
+ activeModifiers = nextModifiers;
721
+ pressedModifiers.pop();
722
+ }
723
+ } finally {
724
+ if (primaryPressed) {
725
+ try {
726
+ await cdp.send(
727
+ "Input.dispatchKeyEvent",
728
+ describeKeyEvent(descriptor, "keyUp", activeModifiers),
729
+ );
730
+ } catch {}
731
+ }
732
+
733
+ while (pressedModifiers.length > 0) {
734
+ const modifier = pressedModifiers.pop()!;
735
+ activeModifiers &= ~modifier.bit;
736
+ try {
737
+ await cdp.send(
738
+ "Input.dispatchKeyEvent",
739
+ describeKeyEvent(modifier.descriptor, "keyUp", activeModifiers),
740
+ );
741
+ } catch {}
742
+ }
342
743
  }
343
- await cdp.send(
344
- "Input.dispatchKeyEvent",
345
- { ...baseParams, type: "keyUp" },
346
- signal,
347
- );
348
744
  }
349
745
 
350
746
  /** Dispatch a wheel scroll delta at the given viewport point. */
@@ -406,14 +406,7 @@ export class CdpInspectClient implements ScopedCdpClient {
406
406
  httpError: unknown,
407
407
  signal: AbortSignal,
408
408
  ): Promise<AttachedSession> {
409
- let wsUrl: string;
410
- try {
411
- wsUrl = this.helpers.buildBrowserWsUrl(host, port);
412
- } catch (err) {
413
- // buildBrowserWsUrl enforces loopback — if it throws, the host
414
- // is non-loopback and we should not attempt any WS connection.
415
- throw err;
416
- }
409
+ const wsUrl = this.helpers.buildBrowserWsUrl(host, port);
417
410
 
418
411
  let transport: CdpWsTransport;
419
412
  try {
@@ -5,9 +5,15 @@ import {
5
5
  parseClientOs,
6
6
  supportsHostProxy,
7
7
  } from "../channels/types.js";
8
+ import {
9
+ canUseVirtualDesktop,
10
+ supportsVirtualDesktopComputerUse,
11
+ } from "../desktop/virtual-desktop-feature.js";
8
12
  import { assistantEventHub } from "../runtime/assistant-event-hub.js";
13
+ import type { ToolContext } from "./types.js";
9
14
 
10
15
  interface HostClientContext {
16
+ trustClass?: ToolContext["trustClass"];
11
17
  clientOs?: ClientOs;
12
18
  transportInterface?: InterfaceId;
13
19
  sourceActorPrincipalId?: string;
@@ -85,6 +91,15 @@ export function supportsClientOsForSkillTool(
85
91
  toolName: string,
86
92
  context: HostClientContext,
87
93
  ): boolean {
94
+ if (
95
+ supportsVirtualDesktopComputerUse(toolName) &&
96
+ canUseVirtualDesktop({
97
+ ...context,
98
+ trustClass: context.trustClass ?? "unknown",
99
+ })
100
+ ) {
101
+ return true;
102
+ }
88
103
  if (supportedClientOs === undefined) {
89
104
  return true;
90
105
  }
@@ -2,7 +2,7 @@
2
2
  * Shared helper for computer-use skill wrapper scripts.
3
3
  *
4
4
  * Each wrapper calls forwardComputerUseProxyTool() to delegate execution to
5
- * the proxy resolver, which forwards the call to the connected desktop client.
5
+ * the proxy resolver, which selects the connected or virtual desktop.
6
6
  */
7
7
 
8
8
  import { formatDesktopAppRequired } from "../capability-offer.js";
@@ -0,0 +1,42 @@
1
+ import {
2
+ isVirtualDesktopPlatform,
3
+ shouldUseVirtualDesktop,
4
+ } from "../../desktop/virtual-desktop-feature.js";
5
+ import type { ExecutionTarget } from "../tool-types.js";
6
+
7
+ export function computerUseTarget(
8
+ input: Record<string, unknown>,
9
+ context?: Parameters<typeof shouldUseVirtualDesktop>[0],
10
+ ): "connected-computer" | "assistant-desktop" {
11
+ // Availability is checked at dispatch, so revocation cannot switch computers.
12
+ const target =
13
+ input.target ??
14
+ (input.target_client_id === undefined &&
15
+ context &&
16
+ shouldUseVirtualDesktop(context, isVirtualDesktopPlatform())
17
+ ? "assistant-desktop"
18
+ : "connected-computer");
19
+ if (target !== "connected-computer" && target !== "assistant-desktop") {
20
+ throw new Error("Choose target connected-computer or assistant-desktop");
21
+ }
22
+ if (target === "assistant-desktop" && input.target_client_id !== undefined) {
23
+ throw new Error("target_client_id only applies to a connected computer");
24
+ }
25
+ if (target === "connected-computer" && input.observation_id !== undefined) {
26
+ throw new Error("observation_id only applies to the assistant desktop");
27
+ }
28
+ return target;
29
+ }
30
+
31
+ export function computerUseExecutionTarget(
32
+ input: Record<string, unknown>,
33
+ context?: Parameters<typeof shouldUseVirtualDesktop>[0],
34
+ ): ExecutionTarget {
35
+ try {
36
+ return computerUseTarget(input, context) === "assistant-desktop"
37
+ ? "sandbox"
38
+ : "host";
39
+ } catch {
40
+ return "host";
41
+ }
42
+ }