@vellumai/assistant 0.12.2 → 0.12.3-dev.202609220224.aacf886

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 (792) hide show
  1. package/.env.example +2 -0
  2. package/AGENTS.md +1 -1
  3. package/ARCHITECTURE.md +43 -29
  4. package/Dockerfile +63 -0
  5. package/README.md +12 -12
  6. package/docs/architecture/integrations.md +7 -0
  7. package/docs/architecture/memory.md +17 -2
  8. package/docs/architecture/security.md +10 -5
  9. package/docs/architecture/turn-actor.md +2 -0
  10. package/docs/credential-execution-service.md +1 -1
  11. package/docs/desktop-browser-cli.md +50 -5
  12. package/docs/live-voice-task-outcomes.md +100 -0
  13. package/docs/mode-sessions.md +183 -0
  14. package/docs/voice-input-diagnostics.md +58 -0
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  19. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  20. package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
  21. package/node_modules/@vellumai/environments/src/shell.ts +24 -0
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  25. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  26. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  27. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  28. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
  29. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  30. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  31. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  32. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  33. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  34. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  35. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  36. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  37. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  38. package/openapi.yaml +716 -16
  39. package/package.json +1 -1
  40. package/scripts/smoke-desktop-browser-cli.ts +11 -26
  41. package/scripts/smoke-desktop-window-theme.ts +2 -3
  42. package/scripts/sync-llm-catalog.ts +3 -0
  43. package/scripts/voice-ttft-spike.ts +2 -2
  44. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  45. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  46. package/src/__tests__/agent-loop.test.ts +259 -0
  47. package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
  48. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  49. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  50. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  51. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  52. package/src/__tests__/anthropic-provider.test.ts +55 -0
  53. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  54. package/src/__tests__/approval-message-composer.test.ts +1 -118
  55. package/src/__tests__/approval-routes-http.test.ts +7 -2
  56. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  57. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  58. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  59. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  60. package/src/__tests__/attachments-store.test.ts +22 -3
  61. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  62. package/src/__tests__/btw-routes.test.ts +4 -1
  63. package/src/__tests__/build-persisted-content.test.ts +1 -1
  64. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  65. package/src/__tests__/call-recovery.test.ts +7 -2
  66. package/src/__tests__/call-routes-http.test.ts +16 -2
  67. package/src/__tests__/call-store.test.ts +7 -2
  68. package/src/__tests__/channel-approval.test.ts +9 -14
  69. package/src/__tests__/channel-reply-delivery.test.ts +56 -0
  70. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  71. package/src/__tests__/chat-credential-redaction.test.ts +23 -0
  72. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  73. package/src/__tests__/checker.test.ts +11 -3
  74. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  75. package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
  76. package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
  77. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  78. package/src/__tests__/computer-use-tools.test.ts +1 -233
  79. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  80. package/src/__tests__/config-schema.test.ts +16 -0
  81. package/src/__tests__/config-watcher.test.ts +24 -0
  82. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  83. package/src/__tests__/context-search-fanout.test.ts +1 -1
  84. package/src/__tests__/context-search-types.test.ts +7 -7
  85. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  86. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  87. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  88. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  89. package/src/__tests__/conversation-agent-loop.test.ts +797 -16
  90. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  91. package/src/__tests__/conversation-attachments.test.ts +106 -0
  92. package/src/__tests__/conversation-evictor.test.ts +62 -37
  93. package/src/__tests__/conversation-fork-crud.test.ts +191 -0
  94. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  95. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  96. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  97. package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
  98. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  99. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  100. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  101. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  102. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  103. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  104. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  105. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  106. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  107. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  108. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  109. package/src/__tests__/conversation-undo.test.ts +61 -0
  110. package/src/__tests__/credential-execution-client.test.ts +72 -55
  111. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  112. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  113. package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
  114. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  115. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  116. package/src/__tests__/dm-backfill.test.ts +91 -1
  117. package/src/__tests__/document-create-route.test.ts +88 -0
  118. package/src/__tests__/document-sync-tags.test.ts +27 -0
  119. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  120. package/src/__tests__/events-tail-route.test.ts +58 -0
  121. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  122. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  123. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  124. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  125. package/src/__tests__/heartbeat-service.test.ts +2 -59
  126. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  127. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  128. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  129. package/src/__tests__/history-repair.test.ts +53 -0
  130. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  131. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  132. package/src/__tests__/image-credentials.test.ts +49 -0
  133. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  134. package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
  135. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  136. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  137. package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
  138. package/src/__tests__/llm-catalog-parity.test.ts +27 -4
  139. package/src/__tests__/media-generate-image.test.ts +49 -1
  140. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  141. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  142. package/src/__tests__/mode-session-history.test.ts +245 -0
  143. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  144. package/src/__tests__/mode-session-wire.test.ts +141 -0
  145. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  146. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  147. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  148. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  149. package/src/__tests__/oauth-commands-routes.test.ts +114 -101
  150. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  151. package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
  152. package/src/__tests__/oauth-providers-routes.test.ts +3 -0
  153. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  154. package/src/__tests__/persist-media-references.test.ts +50 -0
  155. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  156. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  157. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  158. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
  159. package/src/__tests__/process-message-display-content.test.ts +56 -0
  160. package/src/__tests__/provider-platform-proxy-integration.test.ts +45 -15
  161. package/src/__tests__/reaction-persistence.test.ts +5 -0
  162. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  163. package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
  164. package/src/__tests__/runtime-attachment-metadata.test.ts +4 -2
  165. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  166. package/src/__tests__/schedule-routes.test.ts +20 -0
  167. package/src/__tests__/scheduler-result-notification.test.ts +23 -4
  168. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  169. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  170. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  171. package/src/__tests__/secret-routes-platform-proxy.test.ts +87 -31
  172. package/src/__tests__/secret-routes-scrub.test.ts +22 -27
  173. package/src/__tests__/secret-scanner.test.ts +20 -0
  174. package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
  175. package/src/__tests__/secure-keys.test.ts +50 -4
  176. package/src/__tests__/send-endpoint-busy.test.ts +167 -3
  177. package/src/__tests__/server-history-render.test.ts +91 -1
  178. package/src/__tests__/server-tool-pairing.test.ts +107 -0
  179. package/src/__tests__/settings-routes.test.ts +50 -1
  180. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  181. package/src/__tests__/skills.test.ts +5 -4
  182. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  183. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  184. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  185. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  186. package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
  187. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  188. package/src/__tests__/terminal-tools.test.ts +8 -0
  189. package/src/__tests__/thread-backfill.test.ts +53 -0
  190. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  191. package/src/__tests__/tool-result-follow-up.test.ts +99 -0
  192. package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
  193. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  194. package/src/__tests__/twilio-routes.test.ts +1 -0
  195. package/src/__tests__/unicode.test.ts +36 -0
  196. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  197. package/src/activation/progress-store.test.ts +12 -7
  198. package/src/agent/loop.ts +136 -53
  199. package/src/agent/tool-result-follow-up.ts +70 -0
  200. package/src/api/attachment-provenance.test.ts +68 -0
  201. package/src/api/computer-use-tool.test.ts +55 -0
  202. package/src/api/computer-use-tool.ts +27 -0
  203. package/src/api/events/assistant-outbound-attachment.ts +3 -0
  204. package/src/api/events/assistant-turn-start.ts +3 -0
  205. package/src/api/events/desktop-activity-changed.ts +10 -0
  206. package/src/api/events/generation-handoff.ts +2 -0
  207. package/src/api/events/message-complete.ts +2 -0
  208. package/src/api/events/notification-conversation-created.ts +14 -16
  209. package/src/api/events/notification-intent.ts +4 -2
  210. package/src/api/events/question-request.ts +1 -0
  211. package/src/api/events/tool-result.ts +85 -0
  212. package/src/api/events/tool-use-start.ts +3 -0
  213. package/src/api/events/user-message-echo.ts +3 -0
  214. package/src/api/index.ts +42 -6
  215. package/src/api/mode-session.test.ts +131 -0
  216. package/src/api/mode-session.ts +148 -0
  217. package/src/api/remember-tool.ts +15 -0
  218. package/src/api/responses/conversation-message.ts +9 -0
  219. package/src/approvals/AGENTS.md +4 -2
  220. package/src/approvals/approval-primitive.ts +5 -2
  221. package/src/approvals/scoped-approval-grants.ts +6 -2
  222. package/src/browser/__tests__/operations.test.ts +29 -0
  223. package/src/browser/operation-meta.ts +2 -1
  224. package/src/browser/operations.ts +29 -0
  225. package/src/browser/virtual-desktop-target.ts +2 -9
  226. package/src/bundler/bundle-signer.ts +1 -3
  227. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  228. package/src/calls/__tests__/call-controller.test.ts +94 -0
  229. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  230. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  231. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  232. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  233. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  234. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  235. package/src/calls/barge-in-guard.ts +5 -0
  236. package/src/calls/call-controller.ts +196 -1
  237. package/src/calls/call-domain.ts +4 -0
  238. package/src/calls/call-store.ts +87 -2
  239. package/src/calls/guardian-action-sweep.ts +22 -8
  240. package/src/calls/media-stream-audio-transcode.ts +1 -3
  241. package/src/calls/typesafe-noul.ts +156 -0
  242. package/src/calls/voice-control-protocol.ts +6 -0
  243. package/src/calls/voice-escalation-judge.ts +145 -0
  244. package/src/calls/voice-escalation-target.ts +10 -0
  245. package/src/calls/voice-leg-coordinator.ts +121 -3
  246. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  247. package/src/calls/voice-session-bridge.ts +256 -112
  248. package/src/calls/voice-triage-escalate.ts +7 -0
  249. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  250. package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
  251. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  252. package/src/cli/commands/__tests__/plugins.test.ts +20 -1
  253. package/src/cli/commands/__tests__/schedules.test.ts +14 -0
  254. package/src/cli/commands/bash.help.ts +4 -3
  255. package/src/cli/commands/browser.help.ts +9 -6
  256. package/src/cli/commands/browser.ts +0 -1
  257. package/src/cli/commands/channel-verification-sessions.help.ts +12 -2
  258. package/src/cli/commands/clients.help.ts +46 -0
  259. package/src/cli/commands/clients.ts +116 -0
  260. package/src/cli/commands/credentials.help.ts +9 -4
  261. package/src/cli/commands/notifications.help.ts +16 -2
  262. package/src/cli/commands/notifications.ts +30 -8
  263. package/src/cli/commands/oauth/index.help.ts +10 -0
  264. package/src/cli/commands/oauth/providers.ts +12 -0
  265. package/src/cli/commands/oauth/request.test.ts +179 -2
  266. package/src/cli/commands/oauth/request.ts +41 -10
  267. package/src/cli/commands/plugins.ts +12 -5
  268. package/src/cli/commands/roadmap.help.ts +18 -21
  269. package/src/cli/commands/roadmap.ts +4 -21
  270. package/src/cli/commands/schedules.ts +2 -0
  271. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  272. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
  273. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  274. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
  275. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
  276. package/src/cli/lib/bundled-marketplace.json +906 -1
  277. package/src/cli/lib/bundled-plugin-packages.json +783 -1
  278. package/src/cli/lib/inspect-plugin.ts +11 -4
  279. package/src/cli/lib/plugin-marketplace.ts +8 -0
  280. package/src/cli/lib/publish-plugin.ts +1 -2
  281. package/src/cli/lib/upgrade-plugin.ts +19 -11
  282. package/src/cli/output.ts +18 -4
  283. package/src/config/__tests__/default-provider.test.ts +6 -0
  284. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  285. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  286. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  287. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  288. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  289. package/src/config/bundled-skills/schedule/SKILL.md +6 -6
  290. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  291. package/src/config/call-site-defaults.ts +9 -0
  292. package/src/config/feature-flag-registry.json +16 -8
  293. package/src/config/loader.ts +9 -17
  294. package/src/config/platform-identity.ts +8 -8
  295. package/src/config/profile-text-generation.test.ts +51 -0
  296. package/src/config/profile-text-generation.ts +51 -0
  297. package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
  298. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  299. package/src/config/schemas/call-site-catalog.ts +14 -0
  300. package/src/config/schemas/channels.ts +0 -18
  301. package/src/config/schemas/llm.ts +9 -2
  302. package/src/config/schemas/mcp.ts +6 -1
  303. package/src/config/schemas/memory-retrospective.ts +11 -2
  304. package/src/config/schemas/memory-v3.ts +12 -0
  305. package/src/config/schemas/services.ts +15 -6
  306. package/src/config/schemas/tools.ts +10 -0
  307. package/src/config/session-groups-gate.ts +21 -0
  308. package/src/config/skills.ts +2 -6
  309. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  310. package/src/conversations/message-consolidation.ts +102 -5
  311. package/src/credential-execution/ces-connect.test.ts +69 -0
  312. package/src/credential-execution/ces-connect.ts +115 -0
  313. package/src/credential-execution/ces-runtime.ts +55 -93
  314. package/src/credential-execution/executable-discovery.ts +34 -142
  315. package/src/credential-execution/process-manager.test.ts +20 -24
  316. package/src/credential-execution/process-manager.ts +24 -19
  317. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  318. package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
  319. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  320. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
  321. package/src/daemon/assistant-attachments.ts +20 -12
  322. package/src/daemon/browser-mode-session.test.ts +402 -0
  323. package/src/daemon/browser-mode-session.ts +186 -0
  324. package/src/daemon/chat-credential-redaction.ts +16 -1
  325. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  326. package/src/daemon/computer-use-mode-session.ts +105 -0
  327. package/src/daemon/config-watcher.ts +10 -0
  328. package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
  329. package/src/daemon/conversation-agent-loop.ts +231 -25
  330. package/src/daemon/conversation-attachments.ts +93 -12
  331. package/src/daemon/conversation-evictor.ts +5 -24
  332. package/src/daemon/conversation-history.ts +10 -0
  333. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  334. package/src/daemon/conversation-interrupt.ts +7 -11
  335. package/src/daemon/conversation-messaging.ts +58 -5
  336. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  337. package/src/daemon/conversation-mode-session.ts +1008 -0
  338. package/src/daemon/conversation-process.ts +5 -0
  339. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  340. package/src/daemon/conversation-skill-tools.ts +1 -0
  341. package/src/daemon/conversation-store.ts +4 -4
  342. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  343. package/src/daemon/conversation-surfaces.ts +113 -5
  344. package/src/daemon/conversation-tool-setup.ts +79 -6
  345. package/src/daemon/conversation-turn-finalize.ts +26 -13
  346. package/src/daemon/conversation.ts +215 -58
  347. package/src/daemon/daemon-control.ts +3 -7
  348. package/src/daemon/handlers/config-channels.ts +3 -1
  349. package/src/daemon/handlers/config-model.ts +7 -5
  350. package/src/daemon/handlers/shared.ts +55 -16
  351. package/src/daemon/host-cu-proxy.ts +51 -22
  352. package/src/daemon/lifecycle.ts +30 -13
  353. package/src/daemon/mcp-reload-service.ts +1 -1
  354. package/src/daemon/message-protocol.ts +0 -1
  355. package/src/daemon/message-provenance.ts +28 -4
  356. package/src/daemon/message-types/shared.ts +1 -0
  357. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  358. package/src/daemon/mode-session-tracking.ts +54 -0
  359. package/src/daemon/orphan-reaper.ts +4 -3
  360. package/src/daemon/persist-media-references.ts +20 -3
  361. package/src/daemon/process-message.ts +13 -4
  362. package/src/daemon/tool-setup-types.ts +6 -0
  363. package/src/daemon/virtual-desktop-context.ts +21 -0
  364. package/src/daemon/wake-conversation-ops.ts +50 -15
  365. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  366. package/src/desktop/desktop-accessibility-script.ts +88 -0
  367. package/src/desktop/desktop-accessibility.test.ts +160 -0
  368. package/src/desktop/desktop-accessibility.ts +169 -0
  369. package/src/desktop/desktop-automation-lease.test.ts +302 -64
  370. package/src/desktop/desktop-automation-lease.ts +129 -54
  371. package/src/desktop/desktop-browser-endpoint.ts +5 -0
  372. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  373. package/src/desktop/desktop-computer-use.test.ts +449 -0
  374. package/src/desktop/desktop-computer-use.ts +502 -0
  375. package/src/desktop/desktop-dependencies.ts +47 -293
  376. package/src/desktop/desktop-display.ts +2 -2
  377. package/src/desktop/desktop-help.ts +15 -0
  378. package/src/desktop/desktop-panel-config.test.ts +13 -3
  379. package/src/desktop/desktop-panel-config.ts +109 -15
  380. package/src/desktop/desktop-session-manager.test.ts +69 -21
  381. package/src/desktop/desktop-session-manager.ts +76 -22
  382. package/src/desktop/desktop-stream-bridge.test.ts +76 -132
  383. package/src/desktop/desktop-stream-bridge.ts +9 -11
  384. package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
  385. package/src/desktop/desktop-wallpaper-worker.ts +17 -0
  386. package/src/desktop/desktop-wallpaper.test.ts +48 -7
  387. package/src/desktop/desktop-wallpaper.ts +34 -102
  388. package/src/desktop/desktop-window-theme.ts +5 -25
  389. package/src/desktop/virtual-desktop-feature.ts +53 -3
  390. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  391. package/src/documents/document-store.ts +23 -0
  392. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  393. package/src/heartbeat/heartbeat-service.ts +5 -33
  394. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  395. package/src/ipc/assistant-server.ts +2 -0
  396. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  397. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  398. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  399. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  400. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  401. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  402. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  403. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  404. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  405. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  406. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  407. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  408. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  409. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  410. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  411. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  412. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  413. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  414. package/src/live-voice/camera-mode-session.test.ts +265 -0
  415. package/src/live-voice/camera-mode-session.ts +277 -0
  416. package/src/live-voice/continuation-judge.ts +123 -0
  417. package/src/live-voice/live-activity-reporter.ts +115 -6
  418. package/src/live-voice/live-voice-manager.ts +36 -1
  419. package/src/live-voice/live-voice-photo.ts +88 -7
  420. package/src/live-voice/live-voice-session-manager.ts +15 -0
  421. package/src/live-voice/live-voice-session.ts +1443 -747
  422. package/src/live-voice/live-voice-tts.ts +22 -4
  423. package/src/live-voice/microphone-idle-gate.ts +56 -0
  424. package/src/live-voice/protocol.ts +171 -4
  425. package/src/live-voice/session-controls.ts +11 -3
  426. package/src/live-voice/task-outcomes.ts +131 -0
  427. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  428. package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
  429. package/src/mcp/__tests__/startup.test.ts +30 -7
  430. package/src/mcp/__tests__/tool-caps.test.ts +134 -0
  431. package/src/mcp/manager.ts +171 -101
  432. package/src/mcp/startup.ts +33 -13
  433. package/src/mcp/tool-caps.ts +184 -0
  434. package/src/media/__tests__/image-models.test.ts +58 -0
  435. package/src/media/image-credentials.ts +5 -0
  436. package/src/media/image-models.ts +52 -0
  437. package/src/media/image-service.ts +8 -0
  438. package/src/media/openrouter-image-service.test.ts +133 -0
  439. package/src/media/openrouter-image-service.ts +153 -0
  440. package/src/media/types.ts +1 -1
  441. package/src/messaging/provider-message-metadata.ts +3 -3
  442. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  443. package/src/messaging/providers/discord/send.ts +4 -17
  444. package/src/messaging/providers/discord/transport.ts +2 -2
  445. package/src/messaging/providers/outlook/client.ts +16 -22
  446. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  447. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  448. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  449. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  450. package/src/monitoring/__tests__/control.test.ts +17 -5
  451. package/src/monitoring/control.ts +15 -5
  452. package/src/notifications/AGENTS.md +1 -1
  453. package/src/notifications/README.md +83 -99
  454. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  455. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  456. package/src/notifications/__tests__/copy-composer.test.ts +71 -1
  457. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  458. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  459. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  460. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  461. package/src/notifications/adapters/macos.ts +37 -46
  462. package/src/notifications/broadcaster.ts +5 -6
  463. package/src/notifications/channel-allowlist.ts +44 -0
  464. package/src/notifications/copy-composer.ts +11 -26
  465. package/src/notifications/decision-engine.ts +24 -14
  466. package/src/notifications/deterministic-checks.ts +1 -1
  467. package/src/notifications/emit-signal.ts +123 -37
  468. package/src/notifications/home-feed-side-effect.ts +9 -7
  469. package/src/notifications/notification-utils.ts +19 -0
  470. package/src/notifications/schedule-result-producer.ts +4 -6
  471. package/src/notifications/signal.ts +4 -19
  472. package/src/notifications/types.ts +15 -0
  473. package/src/oauth/AGENTS.md +2 -0
  474. package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
  475. package/src/oauth/connection-resolver.ts +1 -2
  476. package/src/oauth/identity-verifier.ts +24 -0
  477. package/src/oauth/oauth-store.ts +12 -4
  478. package/src/oauth/provider-serializer.ts +8 -0
  479. package/src/oauth/seed-providers.ts +42 -0
  480. package/src/onboarding/onboarding-events-store.ts +99 -12
  481. package/src/permissions/confirmation-guardian-request.test.ts +16 -0
  482. package/src/permissions/confirmation-guardian-request.ts +2 -3
  483. package/src/permissions/question-prompter.test.ts +31 -0
  484. package/src/permissions/question-prompter.ts +2 -0
  485. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  486. package/src/persistence/attachments-store.ts +84 -44
  487. package/src/persistence/client-connection-events-store.ts +377 -0
  488. package/src/persistence/conversation-crud.ts +166 -26
  489. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  490. package/src/persistence/conversation-mode-sessions.ts +460 -0
  491. package/src/persistence/conversation-plugin-facade.ts +30 -0
  492. package/src/persistence/conversation-queries.ts +6 -19
  493. package/src/persistence/conversation-tool-surface.ts +135 -0
  494. package/src/persistence/conversation-types.test.ts +32 -0
  495. package/src/persistence/conversation-types.ts +26 -4
  496. package/src/persistence/embeddings/__tests__/embedding-local-lifecycle.test.ts +157 -32
  497. package/src/persistence/embeddings/embedding-backend-shutdown.test.ts +47 -0
  498. package/src/persistence/embeddings/embedding-backend.ts +23 -41
  499. package/src/persistence/embeddings/embedding-gemini.test.ts +17 -0
  500. package/src/persistence/embeddings/embedding-gemini.ts +3 -1
  501. package/src/persistence/embeddings/embedding-local.ts +72 -17
  502. package/src/persistence/embeddings/embedding-types.ts +0 -19
  503. package/src/persistence/llm-usage-store.ts +3 -9
  504. package/src/persistence/message-metadata.ts +25 -0
  505. package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
  506. package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
  507. package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
  508. package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
  509. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
  510. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
  511. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  512. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  513. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  514. package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
  515. package/src/persistence/schema/conversations.ts +67 -0
  516. package/src/persistence/schema/index.ts +1 -0
  517. package/src/persistence/schema/infrastructure.ts +29 -0
  518. package/src/persistence/schema/oauth.ts +1 -0
  519. package/src/persistence/steps.ts +41 -3
  520. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  521. package/src/plugin-api/conversation-turn.ts +31 -7
  522. package/src/plugin-api/effective-context-window.ts +33 -0
  523. package/src/plugin-api/index.ts +35 -6
  524. package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
  525. package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
  526. package/src/plugin-api/plugin-name-env.ts +125 -0
  527. package/src/plugin-api/resolve-credential.ts +79 -20
  528. package/src/plugin-api/vision-support.test.ts +22 -0
  529. package/src/plugin-api/vision-support.ts +17 -5
  530. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  531. package/src/plugins/active-plugin-env.ts +51 -0
  532. package/src/plugins/defaults/index.ts +24 -0
  533. package/src/plugins/defaults/memory/AGENTS.md +39 -5
  534. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  535. package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
  536. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
  537. package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
  538. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
  539. package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
  540. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
  541. package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
  542. package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
  543. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  544. package/src/plugins/defaults/memory/buffer-file.ts +354 -0
  545. package/src/plugins/defaults/memory/buffer-format.ts +40 -0
  546. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  547. package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
  548. package/src/plugins/defaults/memory/context-search/format.ts +53 -8
  549. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  550. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  551. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  552. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  553. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
  554. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
  555. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  556. package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
  557. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  558. package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
  559. package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
  560. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  561. package/src/plugins/defaults/memory/host-utils.ts +0 -10
  562. package/src/plugins/defaults/memory/injectors.ts +4 -3
  563. package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
  564. package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
  565. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  566. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
  567. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  568. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
  569. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
  570. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
  571. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
  572. package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
  573. package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
  574. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
  575. package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
  576. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  577. package/src/plugins/defaults/memory/tools.ts +38 -11
  578. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
  579. package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
  580. package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
  581. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
  582. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
  583. package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
  584. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
  585. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
  586. package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
  587. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
  588. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  589. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
  590. package/src/plugins/defaults/memory/v3/card.ts +2 -1
  591. package/src/plugins/defaults/memory/v3/injector.ts +212 -178
  592. package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
  593. package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
  594. package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
  595. package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
  596. package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
  597. package/src/plugins/defaults/memory/v3/sections.ts +2 -1
  598. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
  599. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  600. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  601. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  602. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  603. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  604. package/src/plugins/defaults/task-progress/package.json +14 -0
  605. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  606. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  607. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
  608. package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
  609. package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
  610. package/src/prompts/delegation-gate.ts +57 -0
  611. package/src/prompts/system-prompt.ts +14 -32
  612. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  613. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  614. package/src/providers/anthropic/client.ts +10 -1
  615. package/src/providers/anthropic-gateway-shared.ts +6 -0
  616. package/src/providers/fetch-provider-catalog.ts +11 -0
  617. package/src/providers/gemini/client.ts +25 -8
  618. package/src/providers/inference/adapter-factory.ts +6 -0
  619. package/src/providers/jev/client.test.ts +270 -0
  620. package/src/providers/jev/client.ts +534 -0
  621. package/src/providers/model-catalog.ts +59 -3
  622. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  623. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  624. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  625. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  626. package/src/providers/openai/chat-completions-provider.ts +100 -29
  627. package/src/providers/openai/google-thought-signature.ts +0 -6
  628. package/src/providers/openai/responses-provider.ts +23 -1
  629. package/src/providers/platform-proxy/constants.ts +5 -0
  630. package/src/providers/ratelimit.ts +1 -3
  631. package/src/providers/search-provider-catalog.ts +24 -0
  632. package/src/providers/server-tool-pairing.ts +16 -7
  633. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  634. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  635. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  636. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  637. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  638. package/src/providers/types.ts +5 -0
  639. package/src/providers/vellum-model-routing.test.ts +1 -0
  640. package/src/routes/control.ts +7 -5
  641. package/src/runtime/AGENTS.md +6 -4
  642. package/src/runtime/__tests__/agent-wake.test.ts +94 -1
  643. package/src/runtime/actor-trust-resolver.ts +3 -3
  644. package/src/runtime/agent-wake.ts +32 -5
  645. package/src/runtime/approval-message-composer.ts +3 -69
  646. package/src/runtime/assistant-event-hub.ts +73 -75
  647. package/src/runtime/assistant-event-publish-options.ts +7 -0
  648. package/src/runtime/assistant-event-targeting.ts +79 -0
  649. package/src/runtime/assistant-stream-state.ts +13 -100
  650. package/src/runtime/auth/__tests__/middleware.test.ts +138 -0
  651. package/src/runtime/auth/middleware.ts +15 -11
  652. package/src/runtime/background-job-runner.ts +5 -5
  653. package/src/runtime/channel-retry-sweep.ts +1 -0
  654. package/src/runtime/guardian-action-message-composer.ts +8 -161
  655. package/src/runtime/guardian-action-service.ts +2 -17
  656. package/src/runtime/guardian-reply-router.ts +29 -40
  657. package/src/runtime/http-server.ts +2 -2
  658. package/src/runtime/http-types.ts +6 -0
  659. package/src/runtime/message-composer-types.ts +3 -61
  660. package/src/runtime/middleware/auth.ts +7 -1
  661. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  662. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
  663. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  664. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  665. package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
  666. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  667. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  668. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  669. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  670. package/src/runtime/pending-interactions.ts +29 -0
  671. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  672. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  673. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
  674. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  675. package/src/runtime/routes/browser-context.ts +31 -11
  676. package/src/runtime/routes/browser-routes.ts +43 -4
  677. package/src/runtime/routes/btw-routes.ts +9 -4
  678. package/src/runtime/routes/channel-route-shared.ts +1 -9
  679. package/src/runtime/routes/client-routes.ts +108 -0
  680. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  681. package/src/runtime/routes/conversation-routes.ts +125 -14
  682. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  683. package/src/runtime/routes/credential-routes.ts +1 -2
  684. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  685. package/src/runtime/routes/desktop-setup-routes.ts +8 -7
  686. package/src/runtime/routes/documents-routes.ts +51 -0
  687. package/src/runtime/routes/email-routes.ts +3 -7
  688. package/src/runtime/routes/events-routes.ts +75 -54
  689. package/src/runtime/routes/guardian-approval-interception.ts +24 -0
  690. package/src/runtime/routes/identity-routes.ts +1 -5
  691. package/src/runtime/routes/image-generation-routes.ts +8 -14
  692. package/src/runtime/routes/inbound-message-handler.ts +37 -41
  693. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  694. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  695. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
  696. package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
  697. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  698. package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
  699. package/src/runtime/routes/inference-profiles-routes.ts +9 -0
  700. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  701. package/src/runtime/routes/migration-routes.ts +73 -2
  702. package/src/runtime/routes/notification-routes.ts +10 -0
  703. package/src/runtime/routes/oauth-commands-routes.ts +57 -54
  704. package/src/runtime/routes/oauth-providers.ts +11 -0
  705. package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
  706. package/src/runtime/routes/oauth-request-hints.ts +149 -0
  707. package/src/runtime/routes/plugins-routes.ts +6 -0
  708. package/src/runtime/routes/roadmap-routes.ts +47 -8
  709. package/src/runtime/routes/schedule-routes.ts +2 -0
  710. package/src/runtime/routes/secret-routes.ts +99 -119
  711. package/src/runtime/routes/settings-routes.ts +10 -4
  712. package/src/runtime/routes/watcher-routes.ts +1 -3
  713. package/src/runtime/trust-class.test.ts +7 -6
  714. package/src/runtime/trust-class.ts +9 -17
  715. package/src/runtime/verification-outbound-actions.ts +2 -2
  716. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  717. package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
  718. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
  719. package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
  720. package/src/schedule/run-script.ts +2 -2
  721. package/src/schedule/scheduler.ts +47 -11
  722. package/src/schedule/tool-surface-readiness.ts +65 -0
  723. package/src/schedule/worker-control.ts +15 -5
  724. package/src/schedule/worker-mcp.ts +85 -0
  725. package/src/schedule/worker.ts +9 -31
  726. package/src/security/secure-keys.ts +74 -112
  727. package/src/skills/clawhub.ts +3 -8
  728. package/src/skills/managed-store.ts +1 -5
  729. package/src/stt/types.ts +4 -0
  730. package/src/subagent/notify.ts +54 -34
  731. package/src/subagent/parent-notification.ts +6 -0
  732. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  733. package/src/telemetry/phone-call-funnel.ts +144 -0
  734. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  735. package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
  736. package/src/tools/ask-question/ask-question-tool.ts +120 -22
  737. package/src/tools/browser/browser-execution.ts +29 -60
  738. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  739. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  740. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  741. package/src/tools/client-os.ts +15 -0
  742. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  743. package/src/tools/computer-use/target.ts +42 -0
  744. package/src/tools/document/document-tool.ts +13 -18
  745. package/src/tools/execution-target.ts +14 -16
  746. package/src/tools/host-terminal/host-shell.ts +16 -7
  747. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  748. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  749. package/src/tools/network/web-fetch.ts +274 -7
  750. package/src/tools/network/web-search.ts +468 -6
  751. package/src/tools/permission-checker.ts +3 -3
  752. package/src/tools/policy-context.ts +3 -1
  753. package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
  754. package/src/tools/shared/shell-output.test.ts +10 -0
  755. package/src/tools/shared/shell-output.ts +14 -2
  756. package/src/tools/skills/load.ts +2 -1
  757. package/src/tools/skills/sandbox-runner.ts +24 -4
  758. package/src/tools/skills/scaffold-managed.ts +2 -1
  759. package/src/tools/skills/skill-script-runner.ts +7 -0
  760. package/src/tools/skills/skill-tool-factory.ts +15 -1
  761. package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
  762. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
  763. package/src/tools/terminal/safe-env.ts +39 -24
  764. package/src/tools/terminal/sanitized-bash.ts +15 -2
  765. package/src/tools/terminal/shell-launch.test.ts +162 -0
  766. package/src/tools/terminal/shell.test.ts +29 -0
  767. package/src/tools/terminal/shell.ts +15 -7
  768. package/src/tools/tool-approval-handler.ts +5 -1
  769. package/src/tools/tool-types.ts +3 -3
  770. package/src/tools/types.ts +8 -2
  771. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  772. package/src/util/abort-reasons.ts +18 -26
  773. package/src/util/browser-human-verification.ts +14 -0
  774. package/src/util/canonicalize-identity.test.ts +21 -0
  775. package/src/util/canonicalize-identity.ts +16 -0
  776. package/src/util/errors.ts +13 -3
  777. package/src/util/host-process.test.ts +17 -1
  778. package/src/util/host-process.ts +24 -0
  779. package/src/util/provider-error-patterns.ts +3 -0
  780. package/src/util/unicode.ts +29 -0
  781. package/src/util/worker-pipe.test.ts +100 -0
  782. package/src/util/worker-pipe.ts +44 -0
  783. package/src/util/worker-process.ts +77 -35
  784. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  785. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  786. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  787. package/src/workspace/migrations/registry.ts +2 -0
  788. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  789. package/src/api/events/heartbeat-alert.ts +0 -20
  790. package/src/daemon/message-types/web-activity.ts +0 -65
  791. package/src/desktop/desktop-dependencies.test.ts +0 -131
  792. package/src/tools/computer-use/definitions.ts +0 -607
package/.env.example CHANGED
@@ -2,6 +2,8 @@
2
2
  ANTHROPIC_API_KEY=sk-ant-...
3
3
  OPENAI_API_KEY=sk-...
4
4
  GEMINI_API_KEY=...
5
+ # Optional. TypeSafe / Jev System One decision model.
6
+ TYPESAFE_API_KEY=...
5
7
  # Optional for authenticated/proxied Ollama deployments
6
8
  OLLAMA_API_KEY=
7
9
  # Optional override (defaults to http://127.0.0.1:11434/v1)
package/AGENTS.md CHANGED
@@ -16,7 +16,7 @@ When you introduce a new env var that the assistant process needs to read at run
16
16
 
17
17
  **Default to including it.** If the var doesn't contain secrets (e.g. a URL, a feature flag, a path, a mode string), add it. Only omit it if it carries credential material (tokens, passwords, private keys) — those must stay isolated to CES.
18
18
 
19
- `CES_LOCAL_SOCKET` is intentionally included despite the socket exposing credential RPCs: assistant subprocesses are expected to reach CES. Credential protection is rules-based access control inside CES, not socket-path secrecy (see root `AGENTS.md`). `CES_SERVICE_TOKEN` and `CES_CREDENTIAL_URL` are also forwarded: managed children still resolve connections through CES HTTP, and the socket path is not a sufficient substitute yet. See the comment on those keys in `src/tools/terminal/safe-env.ts` before attempting to strip them.
19
+ `CES_BOOTSTRAP_SOCKET_DIR` is forwarded so children can reach CES over IPC. `CES_SERVICE_TOKEN` and `CES_CREDENTIAL_URL` are also forwarded so children can fail over to CES HTTP until that transport is removed. Credential protection is rules-based access control inside CES, not socket-path secrecy (see root `AGENTS.md`).
20
20
 
21
21
  ## Daemon startup philosophy
22
22
 
package/ARCHITECTURE.md CHANGED
@@ -96,7 +96,7 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
96
96
 
97
97
  **Credential storage:** Only hashed tokens are persisted. Access token hashes go in `credential_records`; refresh token hashes in `refresh_token_records`. Raw tokens are returned once and never stored server-side.
98
98
 
99
- **Notification scoping:** Guardian-sensitive notifications are annotated with `targetGuardianPrincipalId` for identity-scoped delivery.
99
+ **Notification scoping:** Guardian-sensitive notifications (`notification_intent`, `notification_conversation_created`) are published with `targetActorPrincipalId`, so the event hub delivers them, live, on reconnect replay, and from the `events/tail` recovery route, only to SSE connections whose verified `actorPrincipalId` is the guardian's. Connections without a principal never receive them. The payload's `targetGuardianPrincipalId` records the scoping.
100
100
 
101
101
  **Key source files:**
102
102
 
@@ -289,32 +289,35 @@ The WhatsApp channel enables inbound and outbound messaging via the Meta WhatsAp
289
289
 
290
290
  **Ingress** (`GET /webhooks/whatsapp` — verification, `POST /webhooks/whatsapp` — messages):
291
291
 
292
- 1. **Webhook verification**: Meta sends a `GET` with `hub.mode=subscribe`, `hub.verify_token`, and `hub.challenge`. The gateway compares `hub.verify_token` against `WHATSAPP_WEBHOOK_VERIFY_TOKEN` and echoes `hub.challenge` as plain text.
293
- 2. On `POST`, the gateway verifies the `X-Hub-Signature-256` header (HMAC-SHA256 of the raw request body using `WHATSAPP_APP_SECRET`) when the app secret is configured. Fail-closed: requests are rejected when the secret is set but the signature fails.
292
+ 1. **Webhook verification**: Meta sends a `GET` with `hub.mode=subscribe`, `hub.verify_token`, and `hub.challenge`. The gateway compares `hub.verify_token` against the `webhook_verify_token` credential and echoes `hub.challenge` as plain text.
293
+ 2. On `POST`, the gateway verifies the `X-Hub-Signature-256` header (HMAC-SHA256 of the raw request body using the `app_secret` credential). Fail-closed: a request is rejected with 500 when no app secret is configured, and with 403 when the signature does not match.
294
294
  3. **Normalization**: Text and media messages (image, audio, video, document, sticker) from `messages` change fields are forwarded. Delivery receipts, read receipts, and unsupported message types (contacts, location) are silently acknowledged with `{ ok: true }`. Media attachments are downloaded from the WhatsApp Cloud API, uploaded to the runtime attachment store, and their IDs are passed alongside the message content.
295
295
  4. **`/new` command**: When the message body is `/new` (case-insensitive), the gateway resolves routing, resets the conversation, and sends a confirmation message without forwarding to the runtime.
296
296
  5. The payload is normalized into a `GatewayInboundEvent` with `sourceChannel: "whatsapp"` and `conversationExternalId` set to the sender's WhatsApp phone number (E.164).
297
297
  6. WhatsApp message IDs are deduplicated via `StringDedupCache` (24-hour TTL).
298
298
  7. The gateway marks each inbound message as read (best-effort, fire-and-forget).
299
- 8. The event is forwarded to the runtime via `POST /channels/inbound` with WhatsApp-specific transport hints and a `replyCallbackUrl` pointing to `/deliver/whatsapp`.
299
+ 8. The event is forwarded to the runtime via `POST /channels/inbound` with WhatsApp-specific transport hints and a `replyCallbackUrl` of `<gatewayInternalBaseUrl>/deliver/whatsapp`. The gateway serves no route at that path: the daemon uses the URL only to address the reply (see Egress).
300
300
 
301
- **Egress** (`POST /deliver/whatsapp`):
301
+ **Egress** (daemon WhatsApp transport, `src/messaging/providers/whatsapp/`):
302
302
 
303
- 1. The runtime calls the gateway's `/deliver/whatsapp` endpoint with `{ to, text }` or `{ chatId, text }` (alias).
304
- 2. The gateway authenticates the request via bearer token (same fail-closed model as other deliver endpoints).
305
- 3. The gateway sends the message via the WhatsApp Cloud API `/{phoneNumberId}/messages` endpoint using the configured access token.
306
- 4. Text is split at 4096 characters if needed.
303
+ 1. Replies, approval prompts, and proactive sends go out through the daemon's `whatsappTransport` (`transport.ts`), which calls the Meta Cloud API itself. `isDirectDelivery()` in `src/messaging/providers/index.ts` resolves the `/deliver/whatsapp` callback URL to this transport through `channelForCallback()` (`src/messaging/providers/callback-routing.ts`), so the daemon never posts back to the gateway or dials the URL's host and port. The gateway's own replies to invite and verification codes it intercepts at ingress reach this transport the same way: `deliverVerificationReply` (`gateway/src/verification/reply-delivery.ts`) hands the reply and the inbound message's callback URL to the daemon's IPC-only `deliver_gateway_reply` method (`src/ipc/routes/channel-reply-ipc-routes.ts`), which resolves the transport from that URL.
304
+ 2. `api.ts` reads `phone_number_id` and `access_token` from the secure store and sends through the Cloud API `/{phoneNumberId}/messages` endpoint.
305
+ 3. `send.ts` splits text into 4096-character chunks, preferring newline and then whitespace boundaries.
306
+ 4. An approval prompt renders as an interactive message with up to three reply buttons whose ids follow the shared `apr:<requestId>:<action>` convention. When the cap forces a cut, the reject and block actions are kept. The gateway normalizes the guardian's `button_reply` back into callback data on ingress.
307
+ 5. Attachments up to 25 MB are uploaded to the Cloud API media endpoint and sent as image, video, or document messages. Any that fail are listed in a follow-up text notice.
307
308
 
308
- **Required credentials**:
309
+ The gateway sends only its own notices to WhatsApp (the `/new` confirmation and routing-rejection notices), through `gateway/src/whatsapp/send.ts`.
309
310
 
310
- - `WHATSAPP_PHONE_NUMBER_ID` — the numeric WhatsApp Business phone number ID from Meta
311
- - `WHATSAPP_ACCESS_TOKEN` — System User or temporary access token
312
- - `WHATSAPP_APP_SECRET` — App secret for webhook signature verification
313
- - `WHATSAPP_WEBHOOK_VERIFY_TOKEN` — Token for the Meta webhook subscription handshake
311
+ **Required credentials** (credential vault, `whatsapp` service):
314
312
 
315
- These can be set via environment variables or stored in the credential vault (CES / encrypted store) under the `whatsapp` service prefix.
313
+ - `phone_number_id`: the numeric WhatsApp Business phone number ID from Meta
314
+ - `access_token`: System User or temporary access token
315
+ - `app_secret`: app secret for webhook signature verification
316
+ - `webhook_verify_token`: token for the Meta webhook subscription handshake
316
317
 
317
- **Limitations (v1)**: Rich approval UI (inline buttons) is not supported. Contacts and location message types are acknowledged but not forwarded.
318
+ The daemon reads `phone_number_id` and `access_token` to send. The gateway reads all four: the last two for ingress, and the first two for its own notices.
319
+
320
+ **Limitations**: Contacts and location message types are acknowledged but not forwarded.
318
321
 
319
322
  **Channel Readiness**: The channel readiness HTTP endpoints (`GET /v1/channels/readiness`, `POST /v1/channels/readiness/refresh`) backed by `ChannelReadinessService` in `src/runtime/channel-readiness-service.ts` provide a unified readiness subsystem for all channels. Each channel registers a `ChannelProbe` that runs synchronous local checks (credential presence, ingress config) and optional async remote checks with a 5-minute TTL cache. Built-in probes: Telegram (bot token, webhook secret, ingress). The GET endpoint returns cached snapshots; the refresh endpoint invalidates the cache first. Unknown channels return `unsupported_channel`. Route handlers live in `src/runtime/routes/channel-readiness-routes.ts`.
320
323
 
@@ -614,6 +617,8 @@ Transcription mode is selected once per session in `media-stream-stt-session.ts`
614
617
 
615
618
  Every phone turn runs the same two-leg triage as live voice through `startVoiceTurn` (`src/calls/voice-session-bridge.ts`): `call-controller.ts` opens on a toolless front-door leg (`routingLeg: "front-door"`, the `voiceFrontDoor` call site) and drives it through the shared `createFrontDoorLegCoordinator` (`src/calls/voice-leg-coordinator.ts`), which reads the stream through the verdict machine and sequences the hand-off (pause narration, abort the leg, resolve and speak the bridge, mark it as the floor holder, start the escalated leg pinned to the conversation's own model, re-arm narration); each driver supplies only a host for how text and the bridge are spoken, how a leg is started or aborted, and (live voice only) the speculative hold and commit. Phone has no partial transcripts, so the hold verdict is never taught and routing is escalate-only. The controller also passes the bridge's turn callbacks (tool activity is recorded as `tool_use_started` / `tool_use_completed` call events, persisted row ids ride the `assistant_spoke` event), `launchedAtMs` for dispatch timing, and a `voiceTelemetry` bag keyed by the call session with a `phone_inbound` / `phone_outbound` entry. Both drivers share the spoken progress narration cadence (`src/calls/voice-progress-cadence.ts`, tuned by `voice.frontModel.progress`): the cadence owns the tool-activity log, the triggers (an ops burst, a long operation completing, a full interval of audible silence with news, the `maxSilenceMs` heartbeat) and the generated or static phrase, while each driver supplies its own view of audible silence (live voice from its TTS queue and playback-tail estimate; the media-stream transport from `isPlaybackIdle()` and a running sum of sent frame durations) and how to speak a phrase.
616
619
 
620
+ Both drivers also share the per-turn latency marks (`src/calls/voice-metrics.ts`). The controller opens a turn's marks when it dispatches, seeded with when the caller's transcript arrived, and stamps the leg dispatch, the first assistant delta, the first audible audio, a barge-in, and how the turn settled. Live voice streams a snapshot to its client on every mark; a call has no client on the line, so the aggregate is logged once per turn, cancelled turns included. Each call also records a `phone_call_started` / `phone_call_ended` pair on the onboarding telemetry substrate (`src/telemetry/phone-call-funnel.ts`), written by the call store at session creation and at the single terminal status transition: duration is the gap between the two rows, and a call that took no caller turn carries why on the end row (`silent_no_connect` when it never connected, `silent_no_turn` when it did and nobody spoke).
621
+
617
622
  A credential preflight (`resolveTelephonyCredentialReadiness()` in `src/calls/telephony-credential-preflight.ts`) gates every call: it requires a credentialed, telephony-capable STT provider **and** a media-stream-playable TTS provider (the configured one or a credentialed playable fallback). Inbound calls that fail the preflight receive `<Say>` setup-required copy plus `<Hangup/>` instead of a doomed stream; outbound placement fails before dialing via `preflightVoiceIngress()` with the same user-facing message.
618
623
 
619
624
  Key modules:
@@ -623,6 +628,7 @@ Key modules:
623
628
  | `src/calls/twilio-routes.ts` | Voice webhook handler; generates `<Connect><Stream>` TwiML, enforces the inbound credential preflight |
624
629
  | `src/calls/telephony-credential-preflight.ts` | Combined STT + TTS credential-readiness resolver |
625
630
  | `src/calls/media-stream-parser.ts` | Twilio Media Streams protocol parser |
631
+ | `src/calls/voice-metrics.ts` | Per-turn latency marks, shared with live voice |
626
632
  | `src/calls/media-turn-detector.ts` | Energy-based VAD turn detector for raw audio (batch mode) |
627
633
  | `src/calls/media-stream-stt-session.ts` | STT session — streaming/batch mode selection and transcription via `services.stt` |
628
634
  | `src/calls/media-stream-audio-transcode.ts` | Mu-law ↔ PCM16 codecs and resampling |
@@ -729,7 +735,7 @@ The assistant-side live voice module is intentionally bounded under `src/live-vo
729
735
  | `live-voice-session.ts` | Session orchestration: streaming STT, push-to-talk release, voice turn bridge callbacks, assistant text deltas, TTS, archive, metrics, interrupt, and close |
730
736
  | `live-voice-tts.ts` | Streaming TTS helper that resolves `services.tts`, requires `TtsProvider.synthesizeStream()`, and forwards audio chunks as `tts_audio` frames |
731
737
  | `live-voice-archive.ts` | Audio artifact creation/linking for user utterance and assistant response message IDs |
732
- | `live-voice-metrics.ts` | Per-session and per-turn latency snapshots emitted as `metrics` frames |
738
+ | `../calls/voice-metrics.ts` | Shared per-session and per-turn latency marks; live voice emits each snapshot as a `metrics` frame, phone calls log the per-turn aggregate |
733
739
 
734
740
  Live voice STT uses the same `resolveStreamingTranscriber()` path as conversation streaming, dialed with the provider the `liveVoice` STT role resolves to after managed-speech defaulting (`resolveEffectiveSpeechProviders`, see `config/managed-speech-defaults.ts`). For V1 latency-sensitive behavior, that provider must resolve to a `daemon-streaming` transcriber whose catalog entry has `conversationStreamingMode: "realtime-ws"` and usable credentials. Providers that only support batch or incremental-batch transcription remain valid for other voice surfaces, but do not satisfy live voice's streaming STT requirement.
735
741
 
@@ -1924,12 +1930,14 @@ Keep-alive heartbeats (every 30 s by default):
1924
1930
 
1925
1931
  ### Key Source Files
1926
1932
 
1927
- | File | Role |
1928
- | ----------------------------------------------- | ------------------------------------------------------------------------------ |
1929
- | `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers |
1930
- | `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton |
1931
- | `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()` — SSE route handler |
1932
- | `assistant/src/daemon/server.ts` | Session event paths that publish to the hub (`send` → `publishAssistantEvent`) |
1933
+ | File | Role |
1934
+ | ---------------------------------------------------- | ------------------------------------------------------------------------------------- |
1935
+ | `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers |
1936
+ | `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton |
1937
+ | `assistant/src/runtime/assistant-event-targeting.ts` | `matchesTargeting()`, the targeting check live fanout and replay share |
1938
+ | `assistant/src/runtime/assistant-stream-state.ts` | Per-assistant `seq` counter and ring buffer behind reconnect and `events/tail` replay |
1939
+ | `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()`, the SSE route handler |
1940
+ | `assistant/src/daemon/server.ts` | Session event paths that publish to the hub (`send` → `publishAssistantEvent`) |
1933
1941
 
1934
1942
  ---
1935
1943
 
@@ -1990,7 +1998,7 @@ An SSE push event surfaces new conversations in the macOS client sidebar:
1990
1998
 
1991
1999
  - **`notification_conversation_created`** — Emitted by `broadcaster.ts` when a notification delivery **creates** a new vellum conversation (strategy `start_new_conversation`, `createdNewConversation: true`). **Not** emitted when a conversation is reused. Payload: `{ conversationId, title, sourceEventName }`.
1992
2000
 
1993
- The event follows this pattern: the daemon creates a server-side conversation, persists an initial message, and broadcasts the SSE event so the macOS `ConversationManager` can create a visible conversation in the sidebar.
2001
+ The daemon persists the conversation and its initial message before broadcasting, so a client that receives the event can fetch the conversation immediately. A guardian-sensitive conversation is announced only to the guardian's own connections.
1994
2002
 
1995
2003
  ### Conversation Routing Decision Flow
1996
2004
 
@@ -2028,12 +2036,15 @@ Reminders carry optional `routingIntent` (`single_channel` | `multi_channel` | `
2028
2036
 
2029
2037
  ### Channel Delivery
2030
2038
 
2031
- Notifications are delivered to three channel types:
2039
+ Notifications are delivered to five channel types. The daemon sends to external channels itself, calling each provider's API through the send modules in `src/messaging/providers/<channel>/`; nothing goes through the gateway.
2032
2040
 
2033
2041
  - **Vellum (always connected)**: SSE via the daemon's broadcast mechanism. The `VellumAdapter` emits a `notification_intent` message with rendered copy and optional `deepLinkMetadata` (includes `conversationId` for conversation navigation and `messageId` for message-level scroll anchoring).
2034
- - **Telegram (when guardian binding exists)**: HTTP POST to the gateway's `/deliver/telegram` endpoint. Requires an active guardian binding for the assistant.
2042
+ - **Platform (always connected)**: the `PlatformPushAdapter` posts the notification to the platform's `/v1/assistants/{id}/push/dispatch/` endpoint for native mobile push. Without platform credentials the delivery is recorded as failed.
2043
+ - **Telegram (when the guardian has a chat ID)**: the `TelegramAdapter` calls the Telegram Bot API through `telegram-bot/send.ts`. Approval cards carry inline keyboard buttons and fall back to plain text with typed-reply instructions if the rich send fails.
2044
+ - **Slack (when the guardian's chat is a DM)**: the `SlackAdapter` posts through `slack/send.ts`. Only `D`-prefixed DM channels qualify, so a binding made from a shared channel never receives notifications.
2045
+ - **Discord (when the guardian binding names a user)**: the `DiscordAdapter` opens the guardian's DM through the Discord REST API and sends through `discord/send.ts`.
2035
2046
 
2036
- Connected channels are resolved at signal emission time: vellum is always included, and binding-based channels (Telegram) are included only when an active guardian binding exists for the assistant.
2047
+ Connected channels are resolved at signal emission time by `getConnectedChannels()` in `emit-signal.ts`, from the guardian delivery list (`getGuardianDelivery()`): vellum and platform are always included, and Telegram, Slack, and Discord are included only when that list gives the guardian a deliverable endpoint on the channel.
2037
2048
 
2038
2049
  **Key modules:**
2039
2050
 
@@ -2047,8 +2058,11 @@ Connected channels are resolved at signal emission time: vellum is always includ
2047
2058
  | `assistant/src/notifications/conversation-pairing.ts` | Materializes conversation + message per delivery; executes conversation reuse decisions |
2048
2059
  | `assistant/src/notifications/conversation-candidates.ts` | Builds per-channel candidate set of recent conversations for the decision engine |
2049
2060
  | `assistant/src/notifications/adapters/macos.ts` | Vellum adapter — broadcasts `notification_intent` via SSE with deep-link metadata |
2050
- | `assistant/src/notifications/adapters/telegram.ts` | Telegram adapter — POSTs to gateway `/deliver/telegram` |
2051
- | `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints (vellum SSE, Telegram chat ID from guardian binding) |
2061
+ | `assistant/src/notifications/adapters/platform.ts` | Platform adapter: posts to the platform push-dispatch endpoint for native mobile push |
2062
+ | `assistant/src/notifications/adapters/telegram.ts` | Telegram adapter: calls the Telegram Bot API through `messaging/providers/telegram-bot/send.ts` |
2063
+ | `assistant/src/notifications/adapters/slack.ts` | Slack adapter: posts to the guardian's DM through `messaging/providers/slack/send.ts` |
2064
+ | `assistant/src/notifications/adapters/discord.ts` | Discord adapter: sends to the guardian's DM through `messaging/providers/discord/send.ts` |
2065
+ | `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints from the guardian delivery list (Telegram and Slack chat ID, Discord user ID) |
2052
2066
  | `assistant/src/notifications/copy-composer.ts` | Template-based fallback copy when LLM copy is unavailable |
2053
2067
  | `assistant/src/notifications/preference-extractor.ts` | Detects preference statements in conversation messages |
2054
2068
  | `assistant/src/notifications/preferences-store.ts` | CRUD for user notification preferences |
package/Dockerfile CHANGED
@@ -101,6 +101,69 @@ RUN apt-get update && apt-get install -y \
101
101
  xdg-utils \
102
102
  && rm -rf /var/lib/apt/lists/*
103
103
 
104
+ # Desktop system packages persist through container replacement as image layers.
105
+ RUN set -eu; \
106
+ wezterm_version=20240203-110809-5046fc22; \
107
+ case "$(dpkg --print-architecture)" in \
108
+ amd64) wezterm_suffix=Debian12.deb; wezterm_sha256=d3a5c97093fbc0a87e8f9616e44efc4c9503cfc495fd1cfe4ffeff88578d15f8 ;; \
109
+ arm64) wezterm_suffix=Debian12.arm64.deb; wezterm_sha256=351f8791c6e9561d687afa63834a2132de84800dad6e7c3d035cc6518d6c3744 ;; \
110
+ *) echo "Unsupported desktop architecture" >&2; exit 1 ;; \
111
+ esac; \
112
+ curl --fail --location --proto '=https' --proto-redir '=https' \
113
+ --retry 2 --max-time 300 --output /tmp/wezterm.deb \
114
+ "https://github.com/wezterm/wezterm/releases/download/${wezterm_version}/wezterm-${wezterm_version}.${wezterm_suffix}"; \
115
+ printf '%s /tmp/wezterm.deb\n' "$wezterm_sha256" | sha256sum --check -; \
116
+ apt-get update; \
117
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
118
+ adwaita-icon-theme \
119
+ at-spi2-core \
120
+ bamfdaemon \
121
+ dbus-daemon \
122
+ dbus-x11 \
123
+ feh \
124
+ fonts-liberation \
125
+ gnome-mines \
126
+ gvfs \
127
+ libcurl4 \
128
+ libegl1 \
129
+ libgl1-mesa-dri \
130
+ libgtk-3-0 \
131
+ libvulkan1 \
132
+ openbox \
133
+ plank \
134
+ python3 \
135
+ python3-dbus \
136
+ scrot \
137
+ thunar \
138
+ tigervnc-common \
139
+ tigervnc-standalone-server \
140
+ tumbler \
141
+ xauth \
142
+ xcompmgr \
143
+ xdotool \
144
+ xfonts-base \
145
+ xterm \
146
+ /tmp/wezterm.deb; \
147
+ wezterm --version; \
148
+ rm -rf /tmp/wezterm.deb /var/lib/apt/lists/* /var/cache/apt/archives/*.deb
149
+
150
+ # Extract Chrome without running package scripts or registering its repository.
151
+ RUN set -eu; \
152
+ chrome_version=153.0.8010.36-1; \
153
+ chrome_arch="$(dpkg --print-architecture)"; \
154
+ case "$chrome_arch" in \
155
+ amd64) chrome_sha256=9bb44e33031c2f2857cf36b4343051a12f93058e4b781e3c76313df87f6c8d32 ;; \
156
+ arm64) chrome_sha256=1fcf6ec51a9d52e26ff1ad807225f725be55069ad2b68c5d69361a2746665188 ;; \
157
+ *) echo "Unsupported Chrome architecture" >&2; exit 1 ;; \
158
+ esac; \
159
+ curl --fail --location --proto '=https' --proto-redir '=https' \
160
+ --retry 2 --max-time 300 --output /tmp/chrome.deb \
161
+ "https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${chrome_version}_${chrome_arch}.deb"; \
162
+ printf '%s /tmp/chrome.deb\n' "$chrome_sha256" | sha256sum --check -; \
163
+ dpkg-deb --extract /tmp/chrome.deb /; \
164
+ /opt/google/chrome/chrome --version; \
165
+ rm /tmp/chrome.deb
166
+
104
167
  # Copy bun binary from builder instead of re-installing
105
168
  COPY --from=builder /root/.bun/bin/bun /usr/local/bin/bun
106
169
  RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx
package/README.md CHANGED
@@ -70,16 +70,16 @@ bun run src/index.ts # interactive CLI session
70
70
 
71
71
  ### CLI commands
72
72
 
73
- | Command | Description |
74
- | -------------------------------------------------- | ------------------------------------------------ |
75
- | `vellum wake` | Start assistant + gateway from current checkout |
76
- | `vellum sleep` | Stop assistant + gateway processes |
77
- | `vellum ps` | List assistants and per-assistant process status |
78
- | `assistant` | Launch interactive CLI session |
73
+ | Command | Description |
74
+ | ---------------------------------------------------------- | ------------------------------------------------ |
75
+ | `vellum wake` | Start assistant + gateway from current checkout |
76
+ | `vellum sleep` | Stop assistant + gateway processes |
77
+ | `vellum ps` | List assistants and per-assistant process status |
78
+ | `assistant` | Launch interactive CLI session |
79
79
  | `assistant conversations list\|search\|new\|export\|clear` | Manage conversations |
80
- | `assistant config set\|get\|list` | Manage configuration |
81
- | `assistant keys set\|list\|delete` | Manage API keys in secure storage |
82
- | `assistant trust list\|add\|update\|remove` | Manage trust rules |
80
+ | `assistant config set\|get\|list` | Manage configuration |
81
+ | `assistant keys set\|list\|delete` | Manage API keys in secure storage |
82
+ | `assistant trust list\|add\|update\|remove` | Manage trust rules |
83
83
 
84
84
  ## Project Structure
85
85
 
@@ -183,7 +183,7 @@ Internal forwarding routes (`/v1/internal/twilio/*`) are unaffected — these ac
183
183
  The `/channels/inbound` endpoint requires a JWT with the `svc_gateway` principal type and `ingress.write` scope to prove the request originated from the gateway. This ensures channel messages can only arrive via the gateway (which performs webhook-level verification) and not via direct HTTP calls that bypass signature checks.
184
184
 
185
185
  - **JWT-based enforcement:** The route policy in `route-policy.ts` restricts `/channels/inbound` to the `svc_gateway` principal type with `ingress.write` scope. Actor and local principals are rejected with 403.
186
- - **Auth bypass:** When `DISABLE_HTTP_AUTH=true` is set (platform-managed deployments), JWT verification is skipped and a synthetic context is used.
186
+ - **Auth bypass:** When `DISABLE_HTTP_AUTH=true` is set (platform-managed deployments), a request that supplies no `Authorization` header gets a synthetic context. A request that supplies one is verified normally, and a token that fails verification is rejected.
187
187
 
188
188
  ## Twilio Setup Primitive
189
189
 
@@ -244,8 +244,8 @@ The channel guardian service generates verification challenge instructions with
244
244
  ### Operator Notes
245
245
 
246
246
  - **Verification input format:** Channel verification accepts a bare code reply only (6-digit numeric for identity-bound sessions; 64-char hex for unbound inbound/bootstrap compatibility).
247
- - **Rebind requirement:** Creating a new guardian challenge when a binding already exists requires `rebind: true` in the HTTP request. Without it, the assistant returns `already_bound`. This prevents accidental guardian replacement.
248
- - **Takeover prevention:** Verification is rejected when an active binding exists for a different external user. Same-user re-verification is allowed.
247
+ - **Rebind requirement:** Creating a new guardian challenge when a binding already exists requires `rebind: true` in the HTTP request. Without it, the assistant returns `already_bound`. On text channels the resulting code can only be redeemed by the account already bound, which is how the same guardian verifies again; to move the guardian to a different account, revoke the binding first and verify again. An outbound phone verification is the exception: its code replaces the bound number.
248
+ - **Takeover prevention:** On text channels, verification is rejected when an active binding exists for a different external user: the code is spent, the reply is the generic "invalid or expired", and the sender is made neither guardian nor contact. Same-user re-verification is allowed, including for a guardian who revoked their binding and is verifying the same account again. Phone differs: an outbound verification with `rebind: true` replaces the bound number once its code is entered, and an inbound call from a different number is not bound.
249
249
 
250
250
  ### Vellum Guardian Identity (Actor Tokens)
251
251
 
@@ -552,6 +552,13 @@ Message content (stored as JSON `ContentBlock[]` in the DB) is flattened for the
552
552
 
553
553
  Attachments are materialized into `conversations/<conversation>/attachments/` as soon as they are linked to a message. During disk-view sync, the JSONL record reuses those filenames directly and only falls back to materializing legacy rows that have not been projected yet. Filename collisions are still resolved by appending a numeric suffix (e.g., `photo-2.png`, `photo-3.png`).
554
554
 
555
+ Computer-use screenshot media is materialized while its tool-result row is
556
+ finalized, so earlier frames remain represented in tool history, JSONL, and
557
+ compaction inputs. The final screenshot-bearing invocation reuses that same
558
+ attachment ID for an additional reply link. A single attachment can therefore
559
+ appear on both a tool-result row and a reply row without creating a second
560
+ attachment-store object.
561
+
555
562
  ### Backfill Migration
556
563
 
557
564
  Existing conversations created before the disk view was introduced are backfilled by workspace migration `009-backfill-conversation-disk-view`, which replays all conversations and their messages through the disk-view sync functions.
@@ -87,8 +87,17 @@ graph LR
87
87
  nesting existed still parse, since an unindented body line that is not itself
88
88
  entry-shaped is read as a continuation.
89
89
  - **Consolidation** (`substrate/consolidation-job.ts`) is a background
90
- agent conversation that files buffer entries into concept pages, rewrites
91
- the aggregate views, and trims the buffer. Scheduling
90
+ agent conversation that files buffer entries into concept pages and
91
+ rewrites the aggregate views. The agent never writes the buffer: the job
92
+ snapshots `buffer.md`, hands the run its pass's entries verbatim in the
93
+ prompt, and after the run removes exactly those entries itself through
94
+ `buffer-file.ts` (the module that also owns the append path, so the two
95
+ writers of the buffer share one protocol). Removal happens only when the
96
+ run's persisted messages hold a page-writing tool call with a non-error
97
+ result, the same evidence bar the retrospective's cursor advance uses; a
98
+ run that wrote nothing, failed, or timed out leaves the buffer intact for
99
+ the next pass. Entries deferred past the per-run cap and entries appended
100
+ while the run was in flight are therefore never lost. Scheduling
92
101
  (`maybeEnqueueGraphMaintenanceJobs` in `jobs-worker.ts`):
93
102
  - interval-based (`memory.v2.consolidation_interval_hours`, default 8h),
94
103
  skipped below `MIN_BUFFER_LINES_FOR_CONSOLIDATION` (10) **unless** the
@@ -261,6 +270,12 @@ under `memory.v3.*`. The `memory.v2.enabled` flag gates only the v2 injection
261
270
  engine's turn-time selection; the substrate runs whenever
262
271
  `usesConceptPageMemory()` holds.
263
272
 
273
+ `memory.v3.poolLog.captureInput` (off by default) makes the v3 selector
274
+ persist its exact per-turn input beside the always-written pool audit
275
+ (`memory_v3_pool_inputs`, `memory_v3_pool_texts`), for offline selector
276
+ evaluation and training data; the memory plugin `AGENTS.md` documents the
277
+ tables.
278
+
264
279
  `src/plugins/defaults/memory/AGENTS.md` carries the details that matter when
265
280
  you touch this: the three substrate keys whose names differ from their v2 twin,
266
281
  the three disjoint places the dense/sparse sum-to-1 invariant is checked, and
@@ -176,6 +176,11 @@ sequenceDiagram
176
176
 
177
177
  Model->>Route: assistant credentials prompt --service --field --label
178
178
  Route->>Prompter: requestSecretStandalone(service, field, label, ...)
179
+ alt No surface can render the card (no conversation, or a channel without dynamic UI)
180
+ Prompter->>Route: {value: null, error: "unsupported_channel", collectionUrl?}
181
+ Route->>Model: "Share this one-time link ..." (pending, nothing stored yet)
182
+ Note over Route: The recipient submits the value on the gateway's<br/>credential entry page; the gateway stores it at redemption
183
+ end
179
184
  Prompter->>HTTP: secret_request {requestId, service, field, label, allowOneTimeSend}
180
185
  HTTP->>UI: Show secret prompt
181
186
  UI->>UI: User enters value in a masked field
@@ -226,11 +231,11 @@ User messages are scanned at ingress (`secret-ingress.ts`) against known credent
226
231
 
227
232
  ### Storage Layout
228
233
 
229
- | Component | Location | What it stores |
230
- | ------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
231
- | Secret values | CES credential store or encrypted file store | Encrypted credential values keyed as `credential/{service}/{field}`. Stored via CES RPC (primary), CES HTTP (containerized), or encrypted file store (fallback). |
232
- | Credential records | CES `<cesDataRoot>/metadata.json` | Service, field, alias, policy (`allowedTools`, `allowedDomains`, `injectionTemplates`), timestamps. Served over CES RPC/HTTP. |
233
- | Config | `$VELLUM_WORKSPACE_DIR/config.*` | `secretDetection` settings: enabled, blockIngress, allowOneTimeSend, blockTokenShapedMessages (default `true` — whole-message token-shape heuristic) |
234
+ | Component | Location | What it stores |
235
+ | ------------------ | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
236
+ | Secret values | CES credential store or encrypted file store | Encrypted credential values keyed as `credential/{service}/{field}`. Stored via CES RPC (primary), CES HTTP (containerized), or encrypted file store (fallback). |
237
+ | Credential records | CES `<cesDataRoot>/metadata.json` | Service, field, alias, policy (`allowedTools`, `allowedDomains`, `injectionTemplates`), timestamps. Served over CES RPC/HTTP. |
238
+ | Config | `$VELLUM_WORKSPACE_DIR/config.*` | `secretDetection` settings: enabled, blockIngress, allowOneTimeSend, blockTokenShapedMessages (default `true` — whole-message token-shape heuristic) |
234
239
 
235
240
  ### Key Files
236
241
 
@@ -29,6 +29,8 @@ Do not read `trustContext` or `currentTurnTrustContext` directly. Call sites han
29
29
 
30
30
  **Use `getTurnOrRestingTrust()`** for provenance stamped onto persisted rows (see `provenanceFromTrustContext`). Provenance is read back by the memory indexer, which runs extraction only for guardian rows, and by the transcript assembly, which wraps non-guardian user content before it reaches the model. The turn's actor is correct when a turn is running; rows persisted with no turn in flight (wake notices) must keep the owner's class, because stamping `"unknown"` there silently stops memory extraction for the owner's own flows.
31
31
 
32
+ That provenance describes the turn, so it is stamped on every row the turn writes, the assistant's replies and tool results included. Who wrote a row is a separate fact: `provenanceContactId` names the author's contact and needs positive evidence. It is added only where a person's own inbound words or actions are persisted (`actorAuthorProvenance`): a message channel ingress or its retry replay relays with an explicit `author`, unless that row is scripted or hidden, and the actor's reaction row. The shared user-message writer never infers an author from the conversation's trust, because machine-authored rows (ACP and subagent notifications, pointer turns) persist through it too. Rows the assistant writes during someone's turn never carry it. Slack backfill imports other people's messages, so the turn's actor says nothing about them; each backfilled sender is classified by the same gateway verdict live ingress uses (`resolve_inbound_trust`, see `inbound-stages/backfill-sender-provenance.ts`), which supplies both its trust class and its contact id. When that lookup returns no usable verdict, the row falls back to the guardian-address comparison and is marked `provenanceLookupFailed`, so a failed lookup is never stored as the same fact as a sender the gateway resolved as a stranger. Live ingress needs no such marker: it denies a turn whose verdict failed.
33
+
32
34
  **Use `getTrustContext()`** when there is no turn: HTTP routes reporting conversation state, hydration, and persistence of conversation-level options. Also when a caller deliberately wants the conversation's owner rather than whoever is currently acting; that intent should be obvious from the call site, and if it is not, it is probably the wrong accessor.
33
35
 
34
36
  ## When the acting actor is unknown
@@ -221,7 +221,7 @@ These invariants are enforced by guard tests and code review:
221
221
  4. **Grants and audit logs are CES-internal**: The assistant cannot read CES grant tables or audit logs directly. CES exposes grant status and audit summaries via RPC responses.
222
222
  5. **No generic authenticated HTTP clients in secure commands**: `curl`, `wget`, `httpie`, interpreters, and shell trampolines are structurally denied as secure command entrypoints. This is checked at manifest validation and re-checked at execution time.
223
223
  6. **Managed CES container runs as non-root**: The CES Docker image runs as `uid 1001` (user `ces`). The CES data volume is owned by this user.
224
- 7. **Single active bootstrap connection**: In managed mode, CES accepts one connection on the bootstrap socket and unlinks the socket path while that connection is live, so no second process can connect concurrently. CES is a long-lived sidecar: when the active session ends (the assistant disconnects or its container restarts), CES re-binds the socket and awaits the assistant's reconnection rather than shutting down. At most one connection is ever active; the sidecar only exits on SIGTERM/SIGINT.
224
+ 7. **Multi-connection bootstrap socket**: In managed mode, CES listens on the bootstrap socket as a concurrent multi-connection server and keeps the path bound. The assistant and its child processes each open their own RPC connection. CES is a long-lived sidecar: it stays up across assistant restarts and only exits on SIGTERM/SIGINT.
225
225
 
226
226
  ## Guarantees by deployment mode
227
227
 
@@ -1,6 +1,8 @@
1
1
  # Virtual desktop browser CLI
2
2
 
3
- `assistant browser --virtual-desktop` uses the browser CLI's shared operation handlers against the Chrome process owned by `DesktopSessionManager`. It requires a platform-hosted container, the `assistant-desktop` flag, completed automatic desktop installation and an identified guardian conversation. Availability is checked before starting or reusing control and after asynchronous startup; loss of the flag or installation readiness cancels active control. The first eligible browser command waits for the shared installation job, starts Chrome, and executes the original action exactly once. Cancellation and feature revocation stop the pending action while shared installation can finish for other viewers. Browser CLI requests allow ten minutes, with an eight-minute setup wait limit. Eligible web conversations receive browser guidance in the bash tool description, including the configured shell timeout; native clients retain their existing tool description. Opening the picture-in-picture panel also starts setup and shows progress automatically; failed installs retain a retry action. The persistent profile remains `data/desktop-profile`; no data migration or extension installation is required.
3
+ `assistant browser --virtual-desktop` uses the browser CLI's shared operation handlers against the Chrome process owned by `DesktopSessionManager`. It requires a platform-hosted container, the `assistant-desktop` flag, image-provided desktop components and an identified guardian conversation. Availability is checked before starting or reusing control and after asynchronous startup; losing readiness or the feature flag cancels active control. The first eligible browser command starts Chrome and executes its action without downloading or installing dependencies. Opening the picture-in-picture panel checks readiness and starts the viewer directly. The persistent profile remains `data/desktop-profile`.
4
+
5
+ The assistant Dockerfile installs desktop system packages, pinned WezTerm and pinned Google Chrome before Bun and application source. Architecture-specific SHA-256 checksums verify both downloads. Chrome is extracted to `/opt/google/chrome` without running package scripts or registering its repository. Missing components require replacing the assistant image. Runtime code only checks readiness. `POST /v1/desktop/setup` remains a read-only compatibility endpoint for released clients; current clients only use GET.
4
6
 
5
7
  Automatic browser selection in platform-hosted web conversations uses the streamed Chrome when the desktop flag is enabled and the actor is an identified guardian. The macOS and Windows apps keep their existing browser selection and fallback behavior; they use the streamed desktop only with explicit `--virtual-desktop`. Their shared renderer reports a `web` transport, so selection also reads the active turn's frozen `clientOs`; it does not change transport identity or host capability checks. Explicit `--virtual-desktop`, `--browser-mode`, `--target-client-id` and active-tab requests override the default. Existing personal-browser sessions and tab pins remain on their selected browser. Tab commands use the same streamed-browser default as page commands. `--browser-mode local` selects assistant-side Playwright, not the user's Chrome.
6
8
 
@@ -16,18 +18,61 @@ flowchart LR
16
18
  Chrome --> Stream[Existing desktop stream]
17
19
  ```
18
20
 
21
+ The Terminal dock launcher opens [WezTerm](https://wezterm.org/), with a plain dark native title bar, minimize/maximize/close controls, a new-tab button and split panes. Use Ctrl+Shift+T for a tab, Ctrl+Shift+D to split side by side, and Ctrl+Shift+E to split top and bottom. The desktop seeds an editable `data/desktop-panel/wezterm/wezterm.lua` configuration with software rendering and a dark theme. The managed launcher keeps its stable `data/desktop-panel/applications/xterm.desktop` path so existing dock pins remain valid. The image includes an exact-version, SHA-256-verified WezTerm package for Linux x64 or ARM64, plus its rendering libraries.
22
+
23
+ Chrome and WezTerm use explicit desktop window classes shared with their launcher entries. The desktop session bus and Plank share `XDG_DATA_HOME` so the D-Bus-activated window matcher can resolve the generated launchers and group running windows under their pinned icons.
24
+
19
25
  Chrome and its dock launcher share the managed profile and loopback debug port. For Chrome reopened from the dock, the profile singleton lock identifies a candidate PID, validated against the installed executable, profile and loopback debug arguments. Discovery checks `/proc` socket ownership against that browser PID, refuses redirects and validates the returned browser WebSocket endpoint. The connection stays within the container. No CDP endpoint or token is exposed to the renderer.
20
26
 
21
- The desktop client bypasses personal-browser discovery, extension reconnect waits and backend fallback. It reuses the existing AX snapshot, DOM element resolution, mouse, keyboard, extraction and credential-fill implementations. Operation-scoped clients borrow the lease's connection; disposing one does not release the lease. `detach`, `close`, cancellation, errors and idle expiry release control. Only `tabs close` closes a Chrome tab.
27
+ The desktop client bypasses personal-browser discovery, extension reconnect waits and backend fallback. It reuses the existing AX snapshot, DOM element resolution, mouse, keyboard, extraction and credential-fill implementations. Operation-scoped clients borrow the lease's connection; disposing one does not release the lease. `detach`, `close`, turn completion, cancellation, errors and idle expiry release control. Turn completion clears the activity indicator immediately and queues browser cleanup before the next automation session; it leaves Chrome and the current page open for the user. Only `tabs close` closes a Chrome tab.
22
28
 
23
29
  `assistant browser --virtual-desktop screenshot --output /tmp/desktop-page.jpg` captures a color page image through CDP `Page.captureScreenshot`. It excludes the browser toolbar and desktop dock. `snapshot` returns semantic page structure. Agents should use these interfaces and let the manager start the desktop, including when older memory notes describe manual Xvnc, `xdotool` or scratch XWD conversion scripts.
24
30
 
25
31
  Tab IDs are ephemeral numeric aliases for this managed browser's CDP target IDs. They are never personal extension tab IDs. Initial attachment selects an existing HTTP(S) page or opens a blank tab. Use `tabs list` and `tabs select --tab-id <id>` to choose explicitly. Navigation, tab selection, document replacement and release clear the desktop snapshot map. Personal-browser snapshots use a separate namespace.
26
32
 
27
- CDP mouse events use page viewport CSS coordinates. Before dispatching them, the client animates a purple arrow overlay to the same point. The overlay is excluded from accessibility and hit testing. It appears in the existing desktop stream and is removed on release. It does not move the OS pointer, appear in browser toolbar UI or visualize every programmatic DOM operation. Native dialogs and other applications are outside the browser CLI; users can interact with them directly in the expanded desktop. The picture-in-picture preview is view-only. Direct user interaction does not pause automation.
33
+ CDP mouse events use page viewport CSS coordinates. Before dispatching them, the client animates a purple arrow overlay to the same point. The overlay is excluded from accessibility and hit testing. It appears in the existing desktop stream and is removed on release. It does not move the OS pointer, appear in browser toolbar UI or visualize every programmatic DOM operation. Native dialogs and other applications use the computer-use skill or direct interaction in the expanded desktop. The picture-in-picture preview is view-only. Direct user interaction does not pause automation. For logins, the assistant uses saved credentials first and securely collects missing credentials with `assistant credentials prompt`, then fills the login form itself. Every CAPTCHA and bot-detection challenge, including sliders and press-and-hold checks, is handed to the user before the assistant attempts it. When human interaction is needed, the assistant calls `ask_question` with `desktopHelp: { message, doneLabel, skipLabel }` in the user's language. The tool releases held browser input and reserves the desktop before publishing a question with `presentation: "virtual_desktop"`. The live viewer mounts only in the attended Electron window, with browser focus as a fallback on older shells and the web, so conversations release it when focus changes. A busy viewer offers Reconnect if the previous connection has not finished closing. The compact card lives in the scrolling message transcript, with expandable instructions and a preview capped at 384 pixels wide. It hosts the shared live viewer, with Step In opening its full desktop modal and Done or Skip resolving the existing question response. The assistant retains an exclusive human-help reservation while waiting. Done resumes the same conversation's automation lease for its fresh snapshot; Skip, closure, timeout and cancellation release it. The browser idle timer does not expire a pending human-help reservation. The live preview connects after Show live preview or Step In, and reuses an already-open picture-in-picture viewer. Other devices receiving the card do not automatically open a stream. When the request resolves, its interactive viewer closes or returns to the read-only PiP session that was open before the request. Skip does not imply the obstacle was resolved. Older clients show the same request as a normal Done/Skip question, with model-localized labels retained in history. Channels without dynamic UI return guidance to continue in the app rather than waiting on an unusable card.
28
34
 
29
- The client records key and mouse presses before dispatch. On release it opens a fresh bounded cleanup connection, attaches to the same live targets, releases uncertain held input and removes overlays. A failed cleanup preserves state and the automation slot for retry. Dispatched actions are never automatically retried. Closed targets need no input cleanup. Browser-process loss disposes the client, and later requests discover the replacement process.
35
+ The client records key and mouse presses before dispatch. On release it opens a fresh bounded cleanup connection, attaches to the same live targets, releases uncertain held input and removes overlays. A failed cleanup preserves state and the automation slot for retry. Turn-triggered cancellation retries cleanup automatically until it succeeds or ownership changes. Dispatched actions are never automatically retried. Closed targets need no input cleanup. Browser-process loss disposes the client, and later requests discover the replacement process.
30
36
 
31
37
  `--use-active-tab` and personal browser targeting are rejected with `--virtual-desktop`. Download waiting is unsupported. Browser operations are bounded to two minutes and share the desktop lease's action budget and idle expiry.
32
38
 
33
- Validation: focused client tests exercise shared snapshot/click behavior, namespace isolation, stale references, target changes, cancellation and uncertain-input cleanup. Lease tests cover browser ownership, cancellation and cleanup independently of native input. The Linux smoke script exercises real Chrome, the CLI and visible pointer feedback.
39
+ Validation: focused client tests exercise shared snapshot/click behavior, namespace isolation, stale references, target changes, cancellation and uncertain-input cleanup. Lease tests cover browser ownership, cancellation and cleanup independently of native input. The Linux smoke script exercises real Chrome, the CLI and visible pointer feedback. For image replacement coverage, run `scripts/smoke-desktop-browser-cli.ts` in two disposable containers with the same workspace volume and networking disabled from first use. Both runs require baked components to be ready before navigation and assert that no installation progress is emitted. Each run needs a temporary `ASSISTANT_IPC_SOCKET_DIR`.
40
+
41
+ The desktop header icon pulses in the assistant's avatar accent color while a browser automation lease is active, including between browser commands. It shares the progress indicator's accent and neutral fallback. Reduced-motion clients show a solid accent. Setup status exposes the optional `automationActive` field; `desktop_activity_changed` events refresh it on acquisition and cancellation or release. The indicator reads status, and reconnects refetch the current lease state.
42
+
43
+ Desktop streaming checks the current in-memory gateway feature flags during connection startup. Once connected, frame and drain callbacks do not check feature flags or load workspace configuration. Turning the flag off prevents new connections; an existing stream continues until it closes or the desktop stops.
44
+
45
+ ## Computer use on the same desktop
46
+
47
+ The existing `computer-use` skill defaults to this desktop in platform-hosted
48
+ web conversations. Native desktop clients, including the Mac app connected to a
49
+ platform-hosted assistant, keep the connected-computer default and require
50
+ `target: "assistant-desktop"` to select the virtual desktop explicitly.
51
+ Non-platform assistants keep their connected-computer behavior.
52
+
53
+ Explicit `target: "connected-computer"` or `target_client_id` selects a connected
54
+ computer on every client. The selected target never falls back to another
55
+ computer when unavailable. The virtual desktop uses a fixed 1440x810 display.
56
+ Observations return full-screen screenshots and mouse actions use the same
57
+ screen coordinates.
58
+ Viewer resizing scales the canvas locally without changing the desktop layout.
59
+
60
+ Observe first and pass the returned `observation_id` with each native action.
61
+ Browser commands, user handoff, errors, and interruption require a fresh
62
+ observation before returning to native input. Browser commands and computer use
63
+ share session ownership, cancellation, and the user-help reservation. Use
64
+ browser commands for page-level operations and computer use for desktop UI.
65
+
66
+ ## File explorer
67
+
68
+ Open **Files**, between Chrome and Terminal in the virtual desktop dock, to browse the assistant workspace in
69
+ Thunar, with a Workspace sidebar shortcut and a dark theme. It supports tabs,
70
+ split views, search, hidden files, drag and drop,
71
+ copy/paste, bulk renaming, and file properties. GVfs provides Trash support and
72
+ Tumbler provides thumbnails. Use Ctrl+L to enter a path, Ctrl+T for a new tab,
73
+ Ctrl+H to toggle hidden files, and F3 for split view.
74
+
75
+ Files manages the assistant's files. Files on your personal computer must first
76
+ be uploaded or otherwise copied into the assistant workspace. Existing desktops
77
+ receive the Files dock shortcut once during upgrade; removing or rearranging it
78
+ is preserved across restarts.