@vellumai/assistant 0.12.2 → 0.12.3-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. package/.env.example +2 -0
  2. package/AGENTS.md +1 -1
  3. package/ARCHITECTURE.md +43 -29
  4. package/Dockerfile +63 -0
  5. package/docs/architecture/integrations.md +7 -0
  6. package/docs/architecture/memory.md +17 -2
  7. package/docs/architecture/security.md +10 -5
  8. package/docs/architecture/turn-actor.md +2 -0
  9. package/docs/credential-execution-service.md +1 -1
  10. package/docs/desktop-browser-cli.md +50 -5
  11. package/docs/live-voice-task-outcomes.md +100 -0
  12. package/docs/mode-sessions.md +183 -0
  13. package/docs/voice-input-diagnostics.md +58 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  19. package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
  20. package/node_modules/@vellumai/environments/src/shell.ts +24 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  25. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  26. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
  28. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  29. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  30. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  31. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  32. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  33. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  34. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  35. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  36. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  37. package/openapi.yaml +716 -16
  38. package/package.json +1 -1
  39. package/scripts/smoke-desktop-browser-cli.ts +11 -26
  40. package/scripts/smoke-desktop-window-theme.ts +2 -3
  41. package/scripts/sync-llm-catalog.ts +3 -0
  42. package/scripts/voice-ttft-spike.ts +2 -2
  43. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  44. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  45. package/src/__tests__/agent-loop.test.ts +259 -0
  46. package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
  47. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  48. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  49. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  50. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  51. package/src/__tests__/anthropic-provider.test.ts +55 -0
  52. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  53. package/src/__tests__/approval-message-composer.test.ts +1 -118
  54. package/src/__tests__/approval-routes-http.test.ts +3 -0
  55. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  56. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  57. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  58. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  59. package/src/__tests__/attachments-store.test.ts +22 -3
  60. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  61. package/src/__tests__/btw-routes.test.ts +4 -1
  62. package/src/__tests__/build-persisted-content.test.ts +1 -1
  63. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  64. package/src/__tests__/call-recovery.test.ts +7 -2
  65. package/src/__tests__/call-routes-http.test.ts +12 -0
  66. package/src/__tests__/call-store.test.ts +7 -2
  67. package/src/__tests__/channel-approval.test.ts +9 -14
  68. package/src/__tests__/channel-reply-delivery.test.ts +56 -0
  69. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  70. package/src/__tests__/chat-credential-redaction.test.ts +23 -0
  71. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  72. package/src/__tests__/checker.test.ts +11 -3
  73. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  74. package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
  75. package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
  76. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  77. package/src/__tests__/computer-use-tools.test.ts +1 -233
  78. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  79. package/src/__tests__/config-schema.test.ts +16 -0
  80. package/src/__tests__/config-watcher.test.ts +24 -0
  81. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  82. package/src/__tests__/context-search-fanout.test.ts +1 -1
  83. package/src/__tests__/context-search-types.test.ts +7 -7
  84. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  85. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  86. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  87. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  88. package/src/__tests__/conversation-agent-loop.test.ts +797 -16
  89. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  90. package/src/__tests__/conversation-attachments.test.ts +106 -0
  91. package/src/__tests__/conversation-evictor.test.ts +62 -37
  92. package/src/__tests__/conversation-fork-crud.test.ts +191 -0
  93. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  94. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  96. package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
  97. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  99. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  100. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  101. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  102. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  103. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  104. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  105. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  106. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  107. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  108. package/src/__tests__/conversation-undo.test.ts +61 -0
  109. package/src/__tests__/credential-execution-client.test.ts +72 -55
  110. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  111. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  112. package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
  113. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  114. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  115. package/src/__tests__/dm-backfill.test.ts +91 -1
  116. package/src/__tests__/document-create-route.test.ts +88 -0
  117. package/src/__tests__/document-sync-tags.test.ts +27 -0
  118. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  119. package/src/__tests__/events-tail-route.test.ts +58 -0
  120. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  121. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  122. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  123. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  124. package/src/__tests__/heartbeat-service.test.ts +2 -59
  125. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  126. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  127. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  128. package/src/__tests__/history-repair.test.ts +53 -0
  129. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  130. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  131. package/src/__tests__/image-credentials.test.ts +49 -0
  132. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  133. package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
  134. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  135. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  136. package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
  137. package/src/__tests__/llm-catalog-parity.test.ts +27 -4
  138. package/src/__tests__/media-generate-image.test.ts +49 -1
  139. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  140. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  141. package/src/__tests__/mode-session-history.test.ts +245 -0
  142. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  143. package/src/__tests__/mode-session-wire.test.ts +141 -0
  144. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  145. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  146. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  147. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  148. package/src/__tests__/oauth-commands-routes.test.ts +114 -101
  149. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  150. package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
  151. package/src/__tests__/oauth-providers-routes.test.ts +3 -0
  152. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  153. package/src/__tests__/persist-media-references.test.ts +50 -0
  154. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  155. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  156. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  157. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
  158. package/src/__tests__/process-message-display-content.test.ts +56 -0
  159. package/src/__tests__/reaction-persistence.test.ts +5 -0
  160. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  161. package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
  162. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  163. package/src/__tests__/schedule-routes.test.ts +20 -0
  164. package/src/__tests__/scheduler-result-notification.test.ts +23 -4
  165. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  166. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  167. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  168. package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
  169. package/src/__tests__/secret-routes-scrub.test.ts +22 -27
  170. package/src/__tests__/secret-scanner.test.ts +20 -0
  171. package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
  172. package/src/__tests__/secure-keys.test.ts +50 -4
  173. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  174. package/src/__tests__/server-history-render.test.ts +91 -1
  175. package/src/__tests__/server-tool-pairing.test.ts +107 -0
  176. package/src/__tests__/settings-routes.test.ts +50 -1
  177. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  178. package/src/__tests__/skills.test.ts +5 -4
  179. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  180. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  181. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  182. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
  184. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  185. package/src/__tests__/terminal-tools.test.ts +8 -0
  186. package/src/__tests__/thread-backfill.test.ts +53 -0
  187. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  188. package/src/__tests__/tool-result-follow-up.test.ts +99 -0
  189. package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
  190. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  191. package/src/__tests__/twilio-routes.test.ts +1 -0
  192. package/src/__tests__/unicode.test.ts +36 -0
  193. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  194. package/src/activation/progress-store.test.ts +12 -7
  195. package/src/agent/loop.ts +136 -53
  196. package/src/agent/tool-result-follow-up.ts +70 -0
  197. package/src/api/attachment-provenance.test.ts +68 -0
  198. package/src/api/computer-use-tool.test.ts +55 -0
  199. package/src/api/computer-use-tool.ts +27 -0
  200. package/src/api/events/assistant-outbound-attachment.ts +3 -0
  201. package/src/api/events/assistant-turn-start.ts +3 -0
  202. package/src/api/events/desktop-activity-changed.ts +10 -0
  203. package/src/api/events/generation-handoff.ts +2 -0
  204. package/src/api/events/message-complete.ts +2 -0
  205. package/src/api/events/notification-conversation-created.ts +14 -16
  206. package/src/api/events/notification-intent.ts +4 -2
  207. package/src/api/events/question-request.ts +1 -0
  208. package/src/api/events/tool-result.ts +85 -0
  209. package/src/api/events/tool-use-start.ts +3 -0
  210. package/src/api/events/user-message-echo.ts +3 -0
  211. package/src/api/index.ts +42 -6
  212. package/src/api/mode-session.test.ts +131 -0
  213. package/src/api/mode-session.ts +148 -0
  214. package/src/api/remember-tool.ts +15 -0
  215. package/src/api/responses/conversation-message.ts +9 -0
  216. package/src/approvals/AGENTS.md +4 -2
  217. package/src/approvals/approval-primitive.ts +5 -2
  218. package/src/approvals/scoped-approval-grants.ts +6 -2
  219. package/src/browser/__tests__/operations.test.ts +29 -0
  220. package/src/browser/operation-meta.ts +2 -1
  221. package/src/browser/operations.ts +29 -0
  222. package/src/browser/virtual-desktop-target.ts +2 -9
  223. package/src/bundler/bundle-signer.ts +1 -3
  224. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  225. package/src/calls/__tests__/call-controller.test.ts +94 -0
  226. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  227. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  228. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  229. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  230. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  231. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  232. package/src/calls/barge-in-guard.ts +5 -0
  233. package/src/calls/call-controller.ts +196 -1
  234. package/src/calls/call-domain.ts +4 -0
  235. package/src/calls/call-store.ts +87 -2
  236. package/src/calls/guardian-action-sweep.ts +22 -8
  237. package/src/calls/media-stream-audio-transcode.ts +1 -3
  238. package/src/calls/typesafe-noul.ts +156 -0
  239. package/src/calls/voice-control-protocol.ts +6 -0
  240. package/src/calls/voice-escalation-judge.ts +145 -0
  241. package/src/calls/voice-escalation-target.ts +10 -0
  242. package/src/calls/voice-leg-coordinator.ts +121 -3
  243. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  244. package/src/calls/voice-session-bridge.ts +256 -112
  245. package/src/calls/voice-triage-escalate.ts +7 -0
  246. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  247. package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
  248. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  249. package/src/cli/commands/__tests__/plugins.test.ts +20 -1
  250. package/src/cli/commands/__tests__/schedules.test.ts +14 -0
  251. package/src/cli/commands/bash.help.ts +4 -3
  252. package/src/cli/commands/browser.help.ts +9 -6
  253. package/src/cli/commands/browser.ts +0 -1
  254. package/src/cli/commands/clients.help.ts +46 -0
  255. package/src/cli/commands/clients.ts +116 -0
  256. package/src/cli/commands/credentials.help.ts +9 -4
  257. package/src/cli/commands/notifications.help.ts +16 -2
  258. package/src/cli/commands/notifications.ts +30 -8
  259. package/src/cli/commands/oauth/index.help.ts +10 -0
  260. package/src/cli/commands/oauth/providers.ts +12 -0
  261. package/src/cli/commands/oauth/request.test.ts +179 -2
  262. package/src/cli/commands/oauth/request.ts +41 -10
  263. package/src/cli/commands/plugins.ts +12 -5
  264. package/src/cli/commands/roadmap.help.ts +18 -21
  265. package/src/cli/commands/roadmap.ts +4 -21
  266. package/src/cli/commands/schedules.ts +2 -0
  267. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  268. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
  269. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  270. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
  271. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
  272. package/src/cli/lib/bundled-marketplace.json +906 -1
  273. package/src/cli/lib/bundled-plugin-packages.json +783 -1
  274. package/src/cli/lib/inspect-plugin.ts +11 -4
  275. package/src/cli/lib/plugin-marketplace.ts +8 -0
  276. package/src/cli/lib/publish-plugin.ts +1 -2
  277. package/src/cli/lib/upgrade-plugin.ts +19 -11
  278. package/src/cli/output.ts +18 -4
  279. package/src/config/__tests__/default-provider.test.ts +6 -0
  280. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  281. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  282. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  283. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  284. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  285. package/src/config/bundled-skills/schedule/SKILL.md +6 -6
  286. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  287. package/src/config/call-site-defaults.ts +9 -0
  288. package/src/config/feature-flag-registry.json +16 -0
  289. package/src/config/loader.ts +9 -17
  290. package/src/config/platform-identity.ts +8 -8
  291. package/src/config/profile-text-generation.test.ts +51 -0
  292. package/src/config/profile-text-generation.ts +51 -0
  293. package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
  294. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  295. package/src/config/schemas/call-site-catalog.ts +14 -0
  296. package/src/config/schemas/channels.ts +0 -18
  297. package/src/config/schemas/llm.ts +9 -2
  298. package/src/config/schemas/mcp.ts +6 -1
  299. package/src/config/schemas/memory-retrospective.ts +11 -2
  300. package/src/config/schemas/memory-v3.ts +12 -0
  301. package/src/config/schemas/services.ts +15 -6
  302. package/src/config/schemas/tools.ts +10 -0
  303. package/src/config/session-groups-gate.ts +21 -0
  304. package/src/config/skills.ts +2 -6
  305. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  306. package/src/conversations/message-consolidation.ts +102 -5
  307. package/src/credential-execution/ces-connect.test.ts +69 -0
  308. package/src/credential-execution/ces-connect.ts +115 -0
  309. package/src/credential-execution/ces-runtime.ts +55 -93
  310. package/src/credential-execution/executable-discovery.ts +34 -142
  311. package/src/credential-execution/process-manager.test.ts +20 -24
  312. package/src/credential-execution/process-manager.ts +24 -19
  313. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  314. package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
  315. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  316. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
  317. package/src/daemon/assistant-attachments.ts +20 -12
  318. package/src/daemon/browser-mode-session.test.ts +402 -0
  319. package/src/daemon/browser-mode-session.ts +186 -0
  320. package/src/daemon/chat-credential-redaction.ts +16 -1
  321. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  322. package/src/daemon/computer-use-mode-session.ts +105 -0
  323. package/src/daemon/config-watcher.ts +10 -0
  324. package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
  325. package/src/daemon/conversation-agent-loop.ts +231 -25
  326. package/src/daemon/conversation-attachments.ts +93 -12
  327. package/src/daemon/conversation-evictor.ts +5 -24
  328. package/src/daemon/conversation-history.ts +10 -0
  329. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  330. package/src/daemon/conversation-interrupt.ts +7 -11
  331. package/src/daemon/conversation-messaging.ts +58 -5
  332. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  333. package/src/daemon/conversation-mode-session.ts +1008 -0
  334. package/src/daemon/conversation-process.ts +5 -0
  335. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  336. package/src/daemon/conversation-skill-tools.ts +1 -0
  337. package/src/daemon/conversation-store.ts +4 -4
  338. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  339. package/src/daemon/conversation-surfaces.ts +113 -5
  340. package/src/daemon/conversation-tool-setup.ts +79 -6
  341. package/src/daemon/conversation-turn-finalize.ts +26 -13
  342. package/src/daemon/conversation.ts +215 -58
  343. package/src/daemon/daemon-control.ts +3 -7
  344. package/src/daemon/handlers/config-model.ts +7 -5
  345. package/src/daemon/handlers/shared.ts +55 -16
  346. package/src/daemon/host-cu-proxy.ts +51 -22
  347. package/src/daemon/lifecycle.ts +30 -13
  348. package/src/daemon/mcp-reload-service.ts +1 -1
  349. package/src/daemon/message-protocol.ts +0 -1
  350. package/src/daemon/message-provenance.ts +28 -4
  351. package/src/daemon/message-types/shared.ts +1 -0
  352. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  353. package/src/daemon/mode-session-tracking.ts +54 -0
  354. package/src/daemon/orphan-reaper.ts +4 -3
  355. package/src/daemon/persist-media-references.ts +20 -3
  356. package/src/daemon/process-message.ts +13 -4
  357. package/src/daemon/tool-setup-types.ts +6 -0
  358. package/src/daemon/virtual-desktop-context.ts +21 -0
  359. package/src/daemon/wake-conversation-ops.ts +50 -15
  360. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  361. package/src/desktop/desktop-accessibility-script.ts +88 -0
  362. package/src/desktop/desktop-accessibility.test.ts +160 -0
  363. package/src/desktop/desktop-accessibility.ts +169 -0
  364. package/src/desktop/desktop-automation-lease.test.ts +302 -64
  365. package/src/desktop/desktop-automation-lease.ts +129 -54
  366. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  367. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  368. package/src/desktop/desktop-computer-use.test.ts +449 -0
  369. package/src/desktop/desktop-computer-use.ts +502 -0
  370. package/src/desktop/desktop-dependencies.ts +47 -293
  371. package/src/desktop/desktop-display.ts +2 -2
  372. package/src/desktop/desktop-help.ts +15 -0
  373. package/src/desktop/desktop-panel-config.test.ts +13 -3
  374. package/src/desktop/desktop-panel-config.ts +109 -15
  375. package/src/desktop/desktop-session-manager.test.ts +69 -21
  376. package/src/desktop/desktop-session-manager.ts +76 -22
  377. package/src/desktop/desktop-stream-bridge.test.ts +76 -132
  378. package/src/desktop/desktop-stream-bridge.ts +9 -11
  379. package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
  380. package/src/desktop/desktop-wallpaper-worker.ts +17 -0
  381. package/src/desktop/desktop-wallpaper.test.ts +48 -7
  382. package/src/desktop/desktop-wallpaper.ts +34 -102
  383. package/src/desktop/desktop-window-theme.ts +5 -25
  384. package/src/desktop/virtual-desktop-feature.ts +53 -3
  385. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  386. package/src/documents/document-store.ts +23 -0
  387. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  388. package/src/heartbeat/heartbeat-service.ts +5 -33
  389. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  390. package/src/ipc/assistant-server.ts +2 -0
  391. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  392. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  393. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  394. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  395. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  396. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  397. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  398. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  399. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  400. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  401. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  402. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  403. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  404. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  405. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  406. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  407. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  408. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  409. package/src/live-voice/camera-mode-session.test.ts +265 -0
  410. package/src/live-voice/camera-mode-session.ts +277 -0
  411. package/src/live-voice/continuation-judge.ts +123 -0
  412. package/src/live-voice/live-activity-reporter.ts +115 -6
  413. package/src/live-voice/live-voice-manager.ts +36 -1
  414. package/src/live-voice/live-voice-photo.ts +88 -7
  415. package/src/live-voice/live-voice-session-manager.ts +15 -0
  416. package/src/live-voice/live-voice-session.ts +1443 -747
  417. package/src/live-voice/live-voice-tts.ts +22 -4
  418. package/src/live-voice/microphone-idle-gate.ts +56 -0
  419. package/src/live-voice/protocol.ts +171 -4
  420. package/src/live-voice/session-controls.ts +11 -3
  421. package/src/live-voice/task-outcomes.ts +131 -0
  422. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  423. package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
  424. package/src/mcp/__tests__/startup.test.ts +30 -7
  425. package/src/mcp/__tests__/tool-caps.test.ts +134 -0
  426. package/src/mcp/manager.ts +171 -101
  427. package/src/mcp/startup.ts +33 -13
  428. package/src/mcp/tool-caps.ts +184 -0
  429. package/src/media/__tests__/image-models.test.ts +58 -0
  430. package/src/media/image-credentials.ts +5 -0
  431. package/src/media/image-models.ts +52 -0
  432. package/src/media/image-service.ts +8 -0
  433. package/src/media/openrouter-image-service.test.ts +133 -0
  434. package/src/media/openrouter-image-service.ts +153 -0
  435. package/src/media/types.ts +1 -1
  436. package/src/messaging/provider-message-metadata.ts +3 -3
  437. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  438. package/src/messaging/providers/discord/send.ts +4 -17
  439. package/src/messaging/providers/discord/transport.ts +2 -2
  440. package/src/messaging/providers/outlook/client.ts +16 -22
  441. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  442. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  443. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  444. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  445. package/src/monitoring/__tests__/control.test.ts +17 -5
  446. package/src/monitoring/control.ts +15 -5
  447. package/src/notifications/AGENTS.md +1 -1
  448. package/src/notifications/README.md +83 -99
  449. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  450. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  451. package/src/notifications/__tests__/copy-composer.test.ts +71 -1
  452. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  453. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  454. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  455. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  456. package/src/notifications/adapters/macos.ts +37 -46
  457. package/src/notifications/broadcaster.ts +5 -6
  458. package/src/notifications/channel-allowlist.ts +44 -0
  459. package/src/notifications/copy-composer.ts +11 -26
  460. package/src/notifications/decision-engine.ts +24 -14
  461. package/src/notifications/deterministic-checks.ts +1 -1
  462. package/src/notifications/emit-signal.ts +123 -37
  463. package/src/notifications/home-feed-side-effect.ts +9 -7
  464. package/src/notifications/notification-utils.ts +19 -0
  465. package/src/notifications/schedule-result-producer.ts +4 -6
  466. package/src/notifications/signal.ts +4 -19
  467. package/src/notifications/types.ts +15 -0
  468. package/src/oauth/AGENTS.md +2 -0
  469. package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
  470. package/src/oauth/connection-resolver.ts +1 -2
  471. package/src/oauth/identity-verifier.ts +24 -0
  472. package/src/oauth/oauth-store.ts +12 -4
  473. package/src/oauth/provider-serializer.ts +8 -0
  474. package/src/oauth/seed-providers.ts +42 -0
  475. package/src/onboarding/onboarding-events-store.ts +99 -12
  476. package/src/permissions/confirmation-guardian-request.test.ts +16 -0
  477. package/src/permissions/confirmation-guardian-request.ts +2 -3
  478. package/src/permissions/question-prompter.test.ts +31 -0
  479. package/src/permissions/question-prompter.ts +2 -0
  480. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  481. package/src/persistence/attachments-store.ts +84 -44
  482. package/src/persistence/client-connection-events-store.ts +377 -0
  483. package/src/persistence/conversation-crud.ts +166 -26
  484. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  485. package/src/persistence/conversation-mode-sessions.ts +460 -0
  486. package/src/persistence/conversation-plugin-facade.ts +30 -0
  487. package/src/persistence/conversation-queries.ts +6 -19
  488. package/src/persistence/conversation-tool-surface.ts +135 -0
  489. package/src/persistence/conversation-types.test.ts +32 -0
  490. package/src/persistence/conversation-types.ts +26 -4
  491. package/src/persistence/llm-usage-store.ts +3 -9
  492. package/src/persistence/message-metadata.ts +25 -0
  493. package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
  494. package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
  495. package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
  496. package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
  497. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
  498. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
  499. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  500. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  501. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  502. package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
  503. package/src/persistence/schema/conversations.ts +67 -0
  504. package/src/persistence/schema/index.ts +1 -0
  505. package/src/persistence/schema/infrastructure.ts +29 -0
  506. package/src/persistence/schema/oauth.ts +1 -0
  507. package/src/persistence/steps.ts +41 -3
  508. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  509. package/src/plugin-api/conversation-turn.ts +31 -7
  510. package/src/plugin-api/effective-context-window.ts +33 -0
  511. package/src/plugin-api/index.ts +35 -6
  512. package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
  513. package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
  514. package/src/plugin-api/plugin-name-env.ts +125 -0
  515. package/src/plugin-api/resolve-credential.ts +79 -20
  516. package/src/plugin-api/vision-support.test.ts +22 -0
  517. package/src/plugin-api/vision-support.ts +17 -5
  518. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  519. package/src/plugins/active-plugin-env.ts +51 -0
  520. package/src/plugins/defaults/index.ts +24 -0
  521. package/src/plugins/defaults/memory/AGENTS.md +39 -5
  522. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  523. package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
  524. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
  525. package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
  526. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
  527. package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
  528. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
  530. package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
  531. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  532. package/src/plugins/defaults/memory/buffer-file.ts +354 -0
  533. package/src/plugins/defaults/memory/buffer-format.ts +40 -0
  534. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  535. package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
  536. package/src/plugins/defaults/memory/context-search/format.ts +53 -8
  537. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  538. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  539. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  540. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  541. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
  542. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
  543. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  544. package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
  545. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  546. package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
  547. package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
  548. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  549. package/src/plugins/defaults/memory/host-utils.ts +0 -10
  550. package/src/plugins/defaults/memory/injectors.ts +4 -3
  551. package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
  552. package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
  553. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  554. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
  555. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  556. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
  557. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
  558. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
  559. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
  560. package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
  561. package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
  562. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
  563. package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
  564. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  565. package/src/plugins/defaults/memory/tools.ts +38 -11
  566. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
  567. package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
  568. package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
  570. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
  571. package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
  572. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
  574. package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
  575. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
  576. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
  578. package/src/plugins/defaults/memory/v3/card.ts +2 -1
  579. package/src/plugins/defaults/memory/v3/injector.ts +212 -178
  580. package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
  581. package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
  582. package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
  583. package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
  584. package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
  585. package/src/plugins/defaults/memory/v3/sections.ts +2 -1
  586. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
  587. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  588. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  589. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  590. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  591. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  592. package/src/plugins/defaults/task-progress/package.json +14 -0
  593. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  594. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  595. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
  596. package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
  597. package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
  598. package/src/prompts/delegation-gate.ts +57 -0
  599. package/src/prompts/system-prompt.ts +14 -32
  600. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  601. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  602. package/src/providers/anthropic/client.ts +10 -1
  603. package/src/providers/anthropic-gateway-shared.ts +6 -0
  604. package/src/providers/fetch-provider-catalog.ts +11 -0
  605. package/src/providers/gemini/client.ts +25 -8
  606. package/src/providers/inference/adapter-factory.ts +6 -0
  607. package/src/providers/jev/client.test.ts +270 -0
  608. package/src/providers/jev/client.ts +534 -0
  609. package/src/providers/model-catalog.ts +59 -3
  610. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  611. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  612. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  613. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  614. package/src/providers/openai/chat-completions-provider.ts +100 -29
  615. package/src/providers/openai/google-thought-signature.ts +0 -6
  616. package/src/providers/openai/responses-provider.ts +23 -1
  617. package/src/providers/ratelimit.ts +1 -3
  618. package/src/providers/search-provider-catalog.ts +24 -0
  619. package/src/providers/server-tool-pairing.ts +16 -7
  620. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  621. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  622. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  623. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  624. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  625. package/src/providers/types.ts +5 -0
  626. package/src/routes/control.ts +7 -5
  627. package/src/runtime/AGENTS.md +6 -4
  628. package/src/runtime/__tests__/agent-wake.test.ts +94 -1
  629. package/src/runtime/actor-trust-resolver.ts +3 -3
  630. package/src/runtime/agent-wake.ts +32 -5
  631. package/src/runtime/approval-message-composer.ts +3 -69
  632. package/src/runtime/assistant-event-hub.ts +73 -75
  633. package/src/runtime/assistant-event-publish-options.ts +7 -0
  634. package/src/runtime/assistant-event-targeting.ts +79 -0
  635. package/src/runtime/assistant-stream-state.ts +13 -100
  636. package/src/runtime/background-job-runner.ts +5 -5
  637. package/src/runtime/channel-retry-sweep.ts +1 -0
  638. package/src/runtime/guardian-action-message-composer.ts +8 -161
  639. package/src/runtime/guardian-action-service.ts +2 -17
  640. package/src/runtime/guardian-reply-router.ts +29 -40
  641. package/src/runtime/http-server.ts +2 -2
  642. package/src/runtime/http-types.ts +6 -0
  643. package/src/runtime/message-composer-types.ts +3 -61
  644. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  645. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
  646. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  647. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  648. package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
  649. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  650. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  651. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  652. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  653. package/src/runtime/pending-interactions.ts +29 -0
  654. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  655. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  656. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
  657. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  658. package/src/runtime/routes/browser-context.ts +31 -11
  659. package/src/runtime/routes/browser-routes.ts +43 -4
  660. package/src/runtime/routes/btw-routes.ts +9 -4
  661. package/src/runtime/routes/channel-route-shared.ts +1 -9
  662. package/src/runtime/routes/client-routes.ts +108 -0
  663. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  664. package/src/runtime/routes/conversation-routes.ts +125 -14
  665. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  666. package/src/runtime/routes/credential-routes.ts +1 -2
  667. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  668. package/src/runtime/routes/desktop-setup-routes.ts +8 -7
  669. package/src/runtime/routes/documents-routes.ts +51 -0
  670. package/src/runtime/routes/email-routes.ts +3 -7
  671. package/src/runtime/routes/events-routes.ts +75 -54
  672. package/src/runtime/routes/guardian-approval-interception.ts +24 -0
  673. package/src/runtime/routes/identity-routes.ts +1 -5
  674. package/src/runtime/routes/image-generation-routes.ts +8 -14
  675. package/src/runtime/routes/inbound-message-handler.ts +37 -41
  676. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  677. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  678. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
  679. package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
  680. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  681. package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
  682. package/src/runtime/routes/inference-profiles-routes.ts +9 -0
  683. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  684. package/src/runtime/routes/migration-routes.ts +73 -2
  685. package/src/runtime/routes/notification-routes.ts +10 -0
  686. package/src/runtime/routes/oauth-commands-routes.ts +57 -54
  687. package/src/runtime/routes/oauth-providers.ts +11 -0
  688. package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
  689. package/src/runtime/routes/oauth-request-hints.ts +149 -0
  690. package/src/runtime/routes/plugins-routes.ts +6 -0
  691. package/src/runtime/routes/roadmap-routes.ts +47 -8
  692. package/src/runtime/routes/schedule-routes.ts +2 -0
  693. package/src/runtime/routes/secret-routes.ts +99 -119
  694. package/src/runtime/routes/settings-routes.ts +10 -4
  695. package/src/runtime/routes/watcher-routes.ts +1 -3
  696. package/src/runtime/trust-class.test.ts +7 -6
  697. package/src/runtime/trust-class.ts +9 -17
  698. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  699. package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
  700. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
  701. package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
  702. package/src/schedule/run-script.ts +2 -2
  703. package/src/schedule/scheduler.ts +47 -11
  704. package/src/schedule/tool-surface-readiness.ts +65 -0
  705. package/src/schedule/worker-control.ts +15 -5
  706. package/src/schedule/worker-mcp.ts +85 -0
  707. package/src/schedule/worker.ts +9 -31
  708. package/src/security/secure-keys.ts +74 -112
  709. package/src/skills/clawhub.ts +3 -8
  710. package/src/skills/managed-store.ts +1 -5
  711. package/src/stt/types.ts +4 -0
  712. package/src/subagent/notify.ts +54 -34
  713. package/src/subagent/parent-notification.ts +6 -0
  714. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  715. package/src/telemetry/phone-call-funnel.ts +144 -0
  716. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  717. package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
  718. package/src/tools/ask-question/ask-question-tool.ts +120 -22
  719. package/src/tools/browser/browser-execution.ts +29 -60
  720. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  721. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  722. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  723. package/src/tools/client-os.ts +15 -0
  724. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  725. package/src/tools/computer-use/target.ts +42 -0
  726. package/src/tools/document/document-tool.ts +13 -18
  727. package/src/tools/execution-target.ts +14 -16
  728. package/src/tools/host-terminal/host-shell.ts +16 -7
  729. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  730. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  731. package/src/tools/network/web-fetch.ts +274 -7
  732. package/src/tools/network/web-search.ts +468 -6
  733. package/src/tools/permission-checker.ts +3 -3
  734. package/src/tools/policy-context.ts +3 -1
  735. package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
  736. package/src/tools/shared/shell-output.test.ts +10 -0
  737. package/src/tools/shared/shell-output.ts +14 -2
  738. package/src/tools/skills/load.ts +2 -1
  739. package/src/tools/skills/sandbox-runner.ts +24 -4
  740. package/src/tools/skills/scaffold-managed.ts +2 -1
  741. package/src/tools/skills/skill-script-runner.ts +7 -0
  742. package/src/tools/skills/skill-tool-factory.ts +15 -1
  743. package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
  744. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
  745. package/src/tools/terminal/safe-env.ts +39 -24
  746. package/src/tools/terminal/sanitized-bash.ts +15 -2
  747. package/src/tools/terminal/shell-launch.test.ts +162 -0
  748. package/src/tools/terminal/shell.test.ts +29 -0
  749. package/src/tools/terminal/shell.ts +15 -7
  750. package/src/tools/tool-approval-handler.ts +5 -1
  751. package/src/tools/tool-types.ts +3 -3
  752. package/src/tools/types.ts +8 -2
  753. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  754. package/src/util/abort-reasons.ts +18 -26
  755. package/src/util/browser-human-verification.ts +14 -0
  756. package/src/util/canonicalize-identity.test.ts +21 -0
  757. package/src/util/canonicalize-identity.ts +16 -0
  758. package/src/util/errors.ts +13 -3
  759. package/src/util/host-process.test.ts +17 -1
  760. package/src/util/host-process.ts +24 -0
  761. package/src/util/provider-error-patterns.ts +3 -0
  762. package/src/util/unicode.ts +29 -0
  763. package/src/util/worker-process.ts +77 -35
  764. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  765. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  766. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  767. package/src/workspace/migrations/registry.ts +2 -0
  768. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  769. package/src/api/events/heartbeat-alert.ts +0 -20
  770. package/src/daemon/message-types/web-activity.ts +0 -65
  771. package/src/desktop/desktop-dependencies.test.ts +0 -131
  772. package/src/tools/computer-use/definitions.ts +0 -607
@@ -63,6 +63,8 @@ interface TurnTailContext {
63
63
  /** Minimal per-run handler state {@link settleTurnContent} consumes. */
64
64
  interface TurnContentState {
65
65
  readonly lastAssistantMessageId: string | undefined;
66
+ /** Earlier reply rows that must join the final disk-view export. */
67
+ readonly assistantMessageIdsToSync: ReadonlySet<string>;
66
68
  /** In-flight content writers the turn left behind (see EventHandlerState). */
67
69
  readonly inflightWriters: Map<string, InflightContentWriter>;
68
70
  }
@@ -224,20 +226,31 @@ export async function settleTurnContent(params: {
224
226
  );
225
227
  }
226
228
 
227
- // Mirror the final assistant row into the JSONL disk view. Guarded like the
228
- // steps above: this runs AFTER the terminal SSE, so a throw here must not
229
- // escape into the loop's outer catch and emit a second, contradictory
230
- // terminal event for a turn the client already saw complete.
231
- try {
232
- if (state.lastAssistantMessageId && liveConversation) {
233
- syncMessageToDisk(
234
- ctx.conversationId,
235
- state.lastAssistantMessageId,
236
- liveConversation.createdAt,
237
- );
229
+ // Mirror every assistant row finalized by this turn into the JSONL disk
230
+ // view. Most turns contribute only their last row. A turn that delivered its
231
+ // reply through `send_user_message` can also contribute an earlier row that
232
+ // received the reply attachment. Set insertion order preserves the reply's
233
+ // position, while adding the last row deduplicates the ordinary case where
234
+ // both ids are the same.
235
+ if (liveConversation) {
236
+ const messageIds = new Set(state.assistantMessageIdsToSync);
237
+ if (state.lastAssistantMessageId) {
238
+ messageIds.add(state.lastAssistantMessageId);
239
+ }
240
+ for (const messageId of messageIds) {
241
+ try {
242
+ syncMessageToDisk(
243
+ ctx.conversationId,
244
+ messageId,
245
+ liveConversation.createdAt,
246
+ );
247
+ } catch (err) {
248
+ rlog.warn(
249
+ { err, messageId },
250
+ "Failed to sync assistant message to disk (non-fatal)",
251
+ );
252
+ }
238
253
  }
239
- } catch (err) {
240
- rlog.warn({ err }, "Failed to sync assistant message to disk (non-fatal)");
241
254
  }
242
255
  }
243
256
 
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import { repairHistory } from "../agent/history-repair/history-repair.js";
19
- import type { AgentLoopConfig } from "../agent/loop.js";
19
+ import type { AgentLoopConfig, PreparedModelCall } from "../agent/loop.js";
20
20
  import { AgentLoop } from "../agent/loop.js";
21
21
  import type { AssistantActivityStateEvent } from "../api/events/assistant-activity-state.js";
22
22
  import type { ConfirmationStateChangedEvent } from "../api/events/confirmation-state-changed.js";
@@ -39,6 +39,7 @@ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
39
39
  import { getConfig } from "../config/loader.js";
40
40
  import type { LLMCallSite, Speed } from "../config/schemas/llm.js";
41
41
  import { resolveSendUserMessageActive } from "../config/send-user-message-gate.js";
42
+ import { isSessionGroupsEnabled } from "../config/session-groups-gate.js";
42
43
  import {
43
44
  derefToolResultReReads,
44
45
  postTurnTruncateToolResults,
@@ -92,6 +93,7 @@ import {
92
93
  markV3LiveBlock,
93
94
  MEMORY_V3_POINTER_BLOCK_METADATA_KEY,
94
95
  } from "../plugins/defaults/memory/v3/types.js";
96
+ import { resolveDelegateIndependentTasks } from "../prompts/delegation-gate.js";
95
97
  import {
96
98
  applyBootstrapTemplate,
97
99
  buildSystemPrompt,
@@ -117,6 +119,8 @@ import { withSqliteRetry } from "../util/sqlite-retry.js";
117
119
  import type { WorkspaceGitService } from "../workspace/git-service.js";
118
120
  import type { commitTurnChanges } from "../workspace/turn-commit.js";
119
121
  import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
122
+ import { BrowserModeSessionProducer } from "./browser-mode-session.js";
123
+ import { ComputerUseModeSessionProducer } from "./computer-use-mode-session.js";
120
124
  import type { AssistantSurface } from "./conversation-agent-loop.js";
121
125
  import {
122
126
  applyCompactionResult,
@@ -140,6 +144,7 @@ import {
140
144
  persistUserMessage as persistUserMessageImpl,
141
145
  redirectToSecurePrompt as redirectToSecurePromptImpl,
142
146
  } from "./conversation-messaging.js";
147
+ import { ConversationModeSessionCoordinator } from "./conversation-mode-session.js";
143
148
  // Extracted modules
144
149
  import { registerConversationNotifiers } from "./conversation-notifiers.js";
145
150
  import type { ProcessMessageOptions } from "./conversation-process.js";
@@ -181,6 +186,7 @@ import {
181
186
  canSpawnSubagentsForTurn,
182
187
  createResolveToolsCallback,
183
188
  createToolExecutor,
189
+ createWireToolSurfaceRecorder,
184
190
  } from "./conversation-tool-setup.js";
185
191
  import { canonicalizeTimeZone } from "./date-context.js";
186
192
  import { HostAppControlProxy } from "./host-app-control-proxy.js";
@@ -191,6 +197,7 @@ import { filterMessagesForUntrustedActor } from "./message-provenance.js";
191
197
  import type { ConversationTransportMetadata } from "./message-types/conversations.js";
192
198
  import { isHostProxyTransport } from "./message-types/conversations.js";
193
199
  import { conversationMetadataSyncTag } from "./message-types/sync.js";
200
+ import { bestEffortModeSessionTracking } from "./mode-session-tracking.js";
194
201
  import { renderReactionHistoryText } from "./reaction-history-render.js";
195
202
  import type { QueuedReactionRecord } from "./reaction-record.js";
196
203
  import {
@@ -199,6 +206,7 @@ import {
199
206
  } from "./summarize-boundary.js";
200
207
 
201
208
  const log = getLogger("conversation");
209
+ const PROMPT_CACHE_WARM_MAX_TOKENS = 16;
202
210
 
203
211
  /**
204
212
  * First text block of a persisted message row's content, mirroring
@@ -452,6 +460,41 @@ export class Conversation {
452
460
  * @internal
453
461
  */
454
462
  toolContextPin?: WakeToolContextPin;
463
+ /**
464
+ * Tool definitions sent verbatim in place of the resolved wire array, for
465
+ * a wake replaying its source conversation's recorded surface
466
+ * (`recordConversationToolSurface`). Set and restored alongside the
467
+ * allowlist by `scopeWakeAllowedTools`; read only where the resolver returns
468
+ * the wire array, so it never widens what may execute.
469
+ * @internal
470
+ */
471
+ wireToolReplay?: readonly ToolDefinition[];
472
+ /**
473
+ * The delegation section's rendered state a wake replaying its source's
474
+ * recorded surface carries into its system prompt, in place of the answer
475
+ * derived from the wake's own scope (`canSpawnSubagentsForTurn`). Set and
476
+ * restored alongside {@link wireToolReplay} by `scopeWakeAllowedTools`;
477
+ * read only by {@link buildCurrentSystemPrompt}, so it never widens what
478
+ * may execute.
479
+ * @internal
480
+ */
481
+ delegateIndependentTasksReplay?: boolean;
482
+ /**
483
+ * The delegation-section state the system prompt most recently built by
484
+ * {@link buildCurrentSystemPrompt} rendered: the value the loop's prompt
485
+ * carries until the next build. `null` when that prompt is a verbatim
486
+ * override, unset before the first build. Read by the wire-surface recorder
487
+ * so the recorded state is the one the provider received, not a
488
+ * re-derivation that a config change mid-turn could flip.
489
+ * @internal
490
+ */
491
+ renderedDelegateIndependentTasks?: boolean | null;
492
+ /**
493
+ * Hash of the wire surface last recorded for this conversation in this
494
+ * process, so an unchanged surface is not rewritten on every provider call.
495
+ * @internal
496
+ */
497
+ recordedToolSurfaceHash?: string;
455
498
  /** @internal */ readonly skillProjectionState = new Map<string, string>();
456
499
  /** @internal */ readonly skillProjectionCache: SkillProjectionCache = {};
457
500
  /** @internal */ usageStats: UsageStats = {
@@ -488,6 +531,13 @@ export class Conversation {
488
531
  */
489
532
  enabledPlugins: string[] | null = null;
490
533
  /** @internal */ currentRequestId?: string;
534
+ /** Canonical recorded-session ownership for this conversation. */
535
+ readonly modeSessions: ConversationModeSessionCoordinator;
536
+ /** Computer-use producer mapped onto the canonical session coordinator. */
537
+ readonly computerUseModeSessions: ComputerUseModeSessionProducer;
538
+ /** Browser producer mapped onto the canonical session coordinator. */
539
+ readonly browserModeSessions: BrowserModeSessionProducer;
540
+ private liveVoiceResidencyLeases = 0;
491
541
  /**
492
542
  * The `clientMessageId` the running turn was started by, recorded in the same
493
543
  * synchronous step that takes the processing lock.
@@ -746,17 +796,22 @@ export class Conversation {
746
796
  */
747
797
  pendingInterruptActivityBridge = false;
748
798
  /**
749
- * Set by `interruptRunningTurn` when the abort it ran landed with no tool
750
- * call in flight, and consumed exactly once by the persist of the
751
- * interrupting user message, which appends
799
+ * Set by `interruptRunningTurn` on every handover it completes, and consumed
800
+ * exactly once by the first user message persisted after it, which appends
752
801
  * {@link INTERRUPTED_TURN_NOTE_TEXT} to that message's LLM-facing content
753
802
  * and stamps `interruptedPriorTurn` on the row.
754
803
  *
755
- * An interrupt caught mid-tool needs nothing here: the synthetic
756
- * `tool_result` the loop or the repair writes already tells the model a
757
- * message preempted it. Caught mid-provider-call there is no `tool_use` to
758
- * answer, so the note is the only signal, and it rides on the message that
759
- * did the interrupting.
804
+ * The note is the only place the behavior after an interrupt is spelled out.
805
+ * A synthetic `tool_result` states what happened to the one call it answers
806
+ * and nothing more, so an interrupt caught mid-tool arms this too.
807
+ *
808
+ * It belongs to the history position, not to the send that armed it. That
809
+ * first row is the one sitting directly under the work the handover stopped,
810
+ * so it is the row whose note the model reads in the right place. Normally it
811
+ * is the interrupting message itself. When that send loses the lock race and
812
+ * queues, the message that persists first was also sent while the assistant
813
+ * was working, and the note is true of it; the queued one drains after a
814
+ * completed turn, where the same note would be stale.
760
815
  * @internal
761
816
  */
762
817
  pendingInterruptNote = false;
@@ -938,6 +993,16 @@ export class Conversation {
938
993
  const { maxTokens, speedOverride, cacheTtl, modelOverride } = options ?? {};
939
994
  const enableNativeWebSearch = options?.enableNativeWebSearch ?? false;
940
995
  this.conversationId = conversationId;
996
+ this.modeSessions = new ConversationModeSessionCoordinator(conversationId);
997
+ this.computerUseModeSessions = new ComputerUseModeSessionProducer(
998
+ this.modeSessions,
999
+ isSessionGroupsEnabled,
1000
+ );
1001
+ this.browserModeSessions = new BrowserModeSessionProducer(
1002
+ this.modeSessions,
1003
+ 1,
1004
+ isSessionGroupsEnabled,
1005
+ );
941
1006
  this.parentConversationId = options?.parentConversationId;
942
1007
  this.systemPrompt = systemPrompt;
943
1008
  this.provider = provider;
@@ -1038,6 +1103,7 @@ export class Conversation {
1038
1103
  tools: toolDefs.length > 0 ? toolDefs : undefined,
1039
1104
  toolExecutor: toolDefs.length > 0 ? toolExecutor : undefined,
1040
1105
  resolveTools,
1106
+ onToolsSent: createWireToolSurfaceRecorder(this),
1041
1107
  resolveConversationDir: () => {
1042
1108
  const conv = getConversation(this.conversationId);
1043
1109
  if (!conv) {
@@ -1132,23 +1198,40 @@ export class Conversation {
1132
1198
  * the provider's prefix cache).
1133
1199
  */
1134
1200
  buildCurrentSystemPrompt(): string {
1135
- return this.hasSystemPromptOverride
1136
- ? this.systemPrompt
1137
- : buildSystemPrompt({
1138
- hasNoClient: this.hasNoClient,
1139
- trustContext: this.currentTurnTrustContext,
1140
- channelCapabilities: this.currentTurnChannelCapabilities,
1141
- personaOverride: this.wakePersonaOverride,
1142
- onboardingContext: this.getOnboardingContext(),
1143
- conversationId: this.conversationId,
1144
- sendUserMessageTool: resolveSendUserMessageActive(this),
1145
- // Read off this turn's resolved tool surface: a workspace
1146
- // `tools.exclude` entry, a background run's `allowedTools` scope, a
1147
- // read-only subagent pass, or tools disabled all answer no, and the
1148
- // delegation section renders off rather than pointing at a tool the
1149
- // turn cannot call.
1150
- canSpawnSubagents: canSpawnSubagentsForTurn(this),
1151
- });
1201
+ if (this.hasSystemPromptOverride) {
1202
+ this.renderedDelegateIndependentTasks = null;
1203
+ return this.systemPrompt;
1204
+ }
1205
+ // Resolved once here, handed to the builder, and kept for the
1206
+ // wire-surface recorder, so the prompt the provider receives and the state
1207
+ // a fork replays are the same value by construction. A wake replaying its
1208
+ // source's recorded surface renders the section the source's live turn
1209
+ // rendered; otherwise the answer is read off this turn's resolved tool
1210
+ // surface: a workspace `tools.exclude` entry, a background run's
1211
+ // `allowedTools` scope, a read-only subagent pass, or tools disabled all
1212
+ // answer no, and the section renders off rather than pointing at a tool
1213
+ // the turn cannot call.
1214
+ const delegateIndependentTasks =
1215
+ this.delegateIndependentTasksReplay ??
1216
+ resolveDelegateIndependentTasks({
1217
+ canSpawnSubagents: canSpawnSubagentsForTurn(this),
1218
+ channelCapabilities: this.currentTurnChannelCapabilities,
1219
+ });
1220
+ const prompt = buildSystemPrompt({
1221
+ hasNoClient: this.hasNoClient,
1222
+ trustContext: this.currentTurnTrustContext,
1223
+ channelCapabilities: this.currentTurnChannelCapabilities,
1224
+ personaOverride: this.wakePersonaOverride,
1225
+ onboardingContext: this.getOnboardingContext(),
1226
+ conversationId: this.conversationId,
1227
+ sendUserMessageTool: resolveSendUserMessageActive(this),
1228
+ delegateIndependentTasks,
1229
+ });
1230
+ // Recorded only once the build succeeds: a wake's prompt sync swallows a
1231
+ // failed rebuild and runs on the previous prompt, whose state must stay
1232
+ // the recorded one.
1233
+ this.renderedDelegateIndependentTasks = delegateIndependentTasks;
1234
+ return prompt;
1152
1235
  }
1153
1236
 
1154
1237
  /**
@@ -1182,48 +1265,91 @@ export class Conversation {
1182
1265
  // ── Prompt Cache Warming ─────────────────────────────────────────
1183
1266
 
1184
1267
  /**
1185
- * Fire-and-forget LLM call with max_tokens=1 to populate the provider's
1186
- * prompt cache (system prompt + tools). Called after the canned first
1187
- * greeting so the user's next real message gets a cache hit.
1268
+ * Non-rejecting LLM call with a minimal output budget to populate the selected
1269
+ * provider's prompt cache (system prompt + tools).
1188
1270
  */
1189
- warmPromptCache(): void {
1271
+ async warmPromptCache(options?: {
1272
+ callSite?: LLMCallSite;
1273
+ overrideProfile?: string;
1274
+ forceOverrideProfile?: boolean;
1275
+ signal?: AbortSignal;
1276
+ systemPrompt?: string | null;
1277
+ tools?: ToolDefinition[];
1278
+ }): Promise<void> {
1190
1279
  this.cacheWarmAbort?.abort();
1191
1280
  const abort = new AbortController();
1192
1281
  this.cacheWarmAbort = abort;
1193
1282
 
1194
- const systemPrompt = this.buildCurrentSystemPrompt();
1195
- const tools = getAllToolDefinitions();
1196
- const provider = this.provider;
1283
+ const externalSignal = options?.signal;
1284
+ const relayAbort = (): void => abort.abort(externalSignal?.reason);
1285
+ if (externalSignal?.aborted) {
1286
+ relayAbort();
1287
+ } else {
1288
+ externalSignal?.addEventListener("abort", relayAbort, { once: true });
1289
+ }
1197
1290
 
1198
- const warmMessage: Message = {
1199
- role: "user",
1200
- content: [{ type: "text", text: "hi" }],
1201
- };
1291
+ const callSite = options?.callSite ?? "mainAgent";
1202
1292
 
1203
- provider
1204
- .sendMessage([warmMessage], {
1205
- tools,
1206
- systemPrompt,
1293
+ try {
1294
+ const hasSystemPrompt =
1295
+ options !== undefined &&
1296
+ Object.prototype.hasOwnProperty.call(options, "systemPrompt");
1297
+ const systemPrompt = hasSystemPrompt
1298
+ ? (options.systemPrompt ?? undefined)
1299
+ : this.buildCurrentSystemPrompt();
1300
+ const tools =
1301
+ options?.tools ?? this.agentLoop.getResolvedTools(this.messages);
1302
+ const providerConfig = {
1303
+ ...(options?.overrideProfile !== undefined
1304
+ ? { overrideProfile: options.overrideProfile }
1305
+ : {}),
1306
+ ...(options?.forceOverrideProfile !== undefined
1307
+ ? { forceOverrideProfile: options.forceOverrideProfile }
1308
+ : {}),
1309
+ selectionSeed: this.conversationId,
1310
+ };
1311
+ const warmMessage: Message = {
1312
+ role: "user",
1313
+ content: [{ type: "text", text: "hi" }],
1314
+ };
1315
+
1316
+ await this.provider.sendMessage([warmMessage], {
1317
+ tools: tools.length > 0 ? tools : undefined,
1318
+ ...(systemPrompt !== undefined ? { systemPrompt } : {}),
1207
1319
  config: {
1208
- max_tokens: 1,
1209
- callSite: "mainAgent",
1210
- usageTracking: "manual",
1320
+ max_tokens: PROMPT_CACHE_WARM_MAX_TOKENS,
1321
+ callSite,
1322
+ ...providerConfig,
1323
+ conversationId: this.conversationId,
1211
1324
  },
1212
1325
  signal: abort.signal,
1213
- })
1214
- .then(() => {
1215
- log.info("Prompt cache warmed successfully");
1216
- })
1217
- .catch((err) => {
1218
- if (!abort.signal.aborted) {
1219
- log.warn({ err }, "Prompt cache warming failed (non-fatal)");
1220
- }
1221
- })
1222
- .finally(() => {
1223
- if (this.cacheWarmAbort === abort) {
1224
- this.cacheWarmAbort = undefined;
1225
- }
1226
1326
  });
1327
+ if (!abort.signal.aborted) {
1328
+ log.info(
1329
+ {
1330
+ callSite,
1331
+ profile: options?.overrideProfile ?? null,
1332
+ },
1333
+ "Prompt cache warmed successfully",
1334
+ );
1335
+ }
1336
+ } catch (err) {
1337
+ if (!abort.signal.aborted) {
1338
+ log.warn(
1339
+ {
1340
+ err,
1341
+ callSite,
1342
+ profile: options?.overrideProfile ?? null,
1343
+ },
1344
+ "Prompt cache warming failed (non-fatal)",
1345
+ );
1346
+ }
1347
+ } finally {
1348
+ externalSignal?.removeEventListener("abort", relayAbort);
1349
+ if (this.cacheWarmAbort === abort) {
1350
+ this.cacheWarmAbort = undefined;
1351
+ }
1352
+ }
1227
1353
  }
1228
1354
 
1229
1355
  // ── Lifecycle ────────────────────────────────────────────────────
@@ -2454,14 +2580,31 @@ export class Conversation {
2454
2580
  return !this.queue.isEmpty;
2455
2581
  }
2456
2582
 
2583
+ acquireLiveVoiceResidency(): () => void {
2584
+ this.liveVoiceResidencyLeases += 1;
2585
+ let released = false;
2586
+ return () => {
2587
+ if (released) {
2588
+ return;
2589
+ }
2590
+ released = true;
2591
+ this.liveVoiceResidencyLeases = Math.max(
2592
+ 0,
2593
+ this.liveVoiceResidencyLeases - 1,
2594
+ );
2595
+ };
2596
+ }
2597
+
2457
2598
  /**
2458
2599
  * True when dropping this instance would lose work that is still in flight:
2459
- * a live turn, a queued successor, or a child subagent.
2600
+ * a live turn, queued successor, child subagent, or mode-session lifecycle.
2460
2601
  */
2461
2602
  hasInFlightWork(): boolean {
2462
2603
  return (
2463
2604
  this.isProcessing() ||
2464
2605
  this.hasQueuedMessages() ||
2606
+ this.liveVoiceResidencyLeases > 0 ||
2607
+ this.modeSessions.hasResidentWork() ||
2465
2608
  getSubagentManager().hasActiveChildren(this.conversationId)
2466
2609
  );
2467
2610
  }
@@ -2588,6 +2731,16 @@ export class Conversation {
2588
2731
 
2589
2732
  setHostCuProxy(proxy: HostCuProxy | undefined): void {
2590
2733
  if (this.hostCuProxy && this.hostCuProxy !== proxy) {
2734
+ const previousProxy = this.hostCuProxy;
2735
+ bestEffortModeSessionTracking("computer use proxy replacement", () => {
2736
+ this.computerUseModeSessions.endTask({
2737
+ turnId: this.currentRequestId,
2738
+ source: {
2739
+ sourceId: previousProxy.sourceId,
2740
+ generation: previousProxy.resetGeneration,
2741
+ },
2742
+ });
2743
+ });
2591
2744
  this.hostCuProxy.dispose();
2592
2745
  }
2593
2746
  this.hostCuProxy = proxy;
@@ -3362,6 +3515,8 @@ export class Conversation {
3362
3515
  */
3363
3516
  replyDeliveredInAppOnly?: boolean;
3364
3517
  callSite?: LLMCallSite;
3518
+ /** Provider configuration source when distinct from turn semantics. */
3519
+ inferenceCallSite?: LLMCallSite;
3365
3520
  /**
3366
3521
  * Optional ad-hoc inference-profile override applied to every LLM call
3367
3522
  * the loop issues for this turn. Forwarded into
@@ -3373,6 +3528,8 @@ export class Conversation {
3373
3528
  overrideProfile?: string;
3374
3529
  /** Float `overrideProfile` above call-site layers for this run. */
3375
3530
  forceOverrideProfile?: boolean;
3531
+ /** Observe the first finalized model request without delaying it. */
3532
+ onFirstModelCallPrepared?: (prepared: PreparedModelCall) => void;
3376
3533
  /**
3377
3534
  * Firing's `cron_runs.id` stamped onto this turn's usage rows. Per-turn:
3378
3535
  * forwarded into {@link runAgentLoopImpl} and threaded to `recordUsage`.
@@ -43,7 +43,7 @@ function isPositiveInteger(v: unknown): v is number {
43
43
 
44
44
  /**
45
45
  * Read daemon timeout values directly from the config JSON file, bypassing
46
- * loadConfig() and its ensureMigratedDataDir()/ensureDataDir() side effects.
46
+ * loadConfig() and its ensureDataDir() side effects.
47
47
  * Falls back to hardcoded defaults on any error (missing file, malformed JSON,
48
48
  * unexpected shape) so daemon stop/start never fails due to config issues.
49
49
  */
@@ -258,15 +258,11 @@ async function getDaemonStatus(): Promise<{
258
258
  return { running: true, pid };
259
259
  }
260
260
 
261
- function getStartupLockPath(): string {
262
- return getDaemonStartupLockPath();
263
- }
264
-
265
261
  /** Attempt to acquire a startup lock. Returns true on success. Stale locks
266
262
  * (older than STARTUP_LOCK_STALE_MS) are forcibly removed to prevent
267
263
  * permanent deadlocks from a crashed caller. */
268
264
  function acquireStartupLock(): boolean {
269
- const lockPath = getStartupLockPath();
265
+ const lockPath = getDaemonStartupLockPath();
270
266
  try {
271
267
  // Ensure the root directory exists before attempting the lock file write.
272
268
  // On a first-time run, getRootDir() may not exist yet, and writeFileSync
@@ -293,7 +289,7 @@ function acquireStartupLock(): boolean {
293
289
 
294
290
  function releaseStartupLock(): void {
295
291
  try {
296
- unlinkSync(getStartupLockPath());
292
+ unlinkSync(getDaemonStartupLockPath());
297
293
  } catch {
298
294
  /* already removed */
299
295
  }
@@ -98,14 +98,16 @@ export function setImageGenModel(modelId: string, ctx: ModelSetContext): void {
98
98
  // Keep the derived provider in sync with the selected model so downstream
99
99
  // routing never sends a Gemini request to an OpenAI model (or vice versa).
100
100
  // The prefix logic is shared with workspace migration 006-services-config
101
- // via providerForImageModelPrefix(). Provider "vellum" is exempt: it is
102
- // managed for every model (the backend derives from the model at request
103
- // time), and rewriting it here would silently move a managed user onto a
104
- // BYOK provider they may hold no key for.
101
+ // via providerForImageModelPrefix(). Providers "vellum" and "openrouter"
102
+ // are exempt: vellum is managed for every model, and openrouter owns every
103
+ // selected slug (including google/ and openai/ prefixes). Rewriting either
104
+ // would silently move the user onto a BYOK provider they may hold no key
105
+ // for.
105
106
  const services = raw.services as
106
107
  | Record<string, { provider?: string }>
107
108
  | undefined;
108
- if (services?.["image-generation"]?.provider !== "vellum") {
109
+ const currentProvider = services?.["image-generation"]?.provider;
110
+ if (currentProvider !== "vellum" && currentProvider !== "openrouter") {
109
111
  setServiceField(
110
112
  raw,
111
113
  "image-generation",
@@ -3,8 +3,13 @@ import {
3
3
  SENTINEL_REDACTION_VERSION,
4
4
  } from "@vellumai/service-contracts/redacted-credential";
5
5
  import { v4 as uuid } from "uuid";
6
+ import { z } from "zod";
6
7
 
7
8
  import { AnsweredQuestionSchema } from "../../api/events/question-answered.js";
9
+ import {
10
+ type ToolActivityMetadata,
11
+ ToolActivityMetadataSchema,
12
+ } from "../../api/events/tool-result.js";
8
13
  import type {
9
14
  ConversationContentBlock,
10
15
  ConversationMessageAttachment,
@@ -246,6 +251,33 @@ export interface ConversationCreateOptions {
246
251
  conversationType?: ConversationCreateType;
247
252
  }
248
253
 
254
+ /** One schema per activity entry, so each entry validates on its own. */
255
+ const ACTIVITY_ENTRY_SCHEMAS = Object.entries(
256
+ ToolActivityMetadataSchema.shape,
257
+ ).map(([key, schema]) => z.object({ [key]: schema }));
258
+
259
+ /**
260
+ * Validates a persisted `_activityMetadata` rider one tool's entry at a time.
261
+ * Cards render these fields directly, so an entry that no longer matches its
262
+ * schema is dropped (its card degrades to the result text) without taking a
263
+ * valid sibling entry with it.
264
+ */
265
+ function readPersistedActivityMetadata(
266
+ value: unknown,
267
+ ): ToolActivityMetadata | undefined {
268
+ if (!isRecord(value)) {
269
+ return undefined;
270
+ }
271
+ const activity: ToolActivityMetadata = {};
272
+ for (const schema of ACTIVITY_ENTRY_SCHEMAS) {
273
+ const parsed = schema.safeParse(value);
274
+ if (parsed.success) {
275
+ Object.assign(activity, parsed.data);
276
+ }
277
+ }
278
+ return Object.keys(activity).length > 0 ? activity : undefined;
279
+ }
280
+
249
281
  function isRecord(value: unknown): value is Record<string, unknown> {
250
282
  return typeof value === "object" && value != null;
251
283
  }
@@ -661,12 +693,12 @@ export function renderHistoryContent(
661
693
  entry.riskDirectoryScopeOptions =
662
694
  block._riskDirectoryScopeOptions as HistoryToolCall["riskDirectoryScopeOptions"];
663
695
  }
664
- // Read back tool activity (web_search / web_fetch) persisted by
665
- // `annotatePersistedAssistantMessage` so the activity card survives a
666
- // history reopen instead of degrading to the plain result text.
667
- if (isRecord(block._activityMetadata)) {
668
- entry.activityMetadata =
669
- block._activityMetadata as HistoryToolCall["activityMetadata"];
696
+ // Read back tool activity persisted by `annotatePersistedAssistantMessage`
697
+ // so the activity card survives a history reopen instead of degrading to
698
+ // the plain result text.
699
+ const activity = readPersistedActivityMetadata(block._activityMetadata);
700
+ if (activity) {
701
+ entry.activityMetadata = activity;
670
702
  }
671
703
  // Read back the answered `ask_question` record so the answered card
672
704
  // rehydrates from history. Validated (rather than trusted like the
@@ -708,9 +740,9 @@ export function renderHistoryContent(
708
740
  }
709
741
  // Native server tools (Anthropic web_search) persist their activity on
710
742
  // the server_tool_use block, so read it back here too.
711
- if (isRecord(block._activityMetadata)) {
712
- entry.activityMetadata =
713
- block._activityMetadata as HistoryToolCall["activityMetadata"];
743
+ const activity = readPersistedActivityMetadata(block._activityMetadata);
744
+ if (activity) {
745
+ entry.activityMetadata = activity;
714
746
  }
715
747
  toolCalls.push(entry);
716
748
  if (id) {
@@ -936,17 +968,24 @@ async function mintCollectionLinkFallback(
936
968
  *
937
969
  * Lifecycle state (resolver, timer) is registered in pendingInteractions — the
938
970
  * same tracker the in-conversation SecretPrompter uses — so `POST /v1/secret`
939
- * resolves the prompt generically. When a `conversationId` is supplied (the CLI
940
- * `credentials prompt` command forwards `__CONVERSATION_ID`), the broadcast is
941
- * scoped to that conversation so clients deliver it; otherwise it is
942
- * conversation-less. When that conversation's channel cannot render dynamic UI
943
- * (e.g. slack, telegram), resolves immediately with `unsupported_channel` —
944
- * carrying a one-time collection link when the gateway can mint one — instead
945
- * of broadcasting a request that can only time out.
971
+ * resolves the prompt generically. The broadcast is scoped to the supplied
972
+ * `conversationId` (the CLI `credentials prompt` command forwards
973
+ * `__CONVERSATION_ID`) so clients deliver it. Two cases have no surface that
974
+ * can render the card and resolve immediately with `unsupported_channel`,
975
+ * carrying a one-time collection link when the gateway can mint one, instead
976
+ * of broadcasting a request that can only time out:
977
+ * - the conversation's channel cannot render dynamic UI (slack, telegram);
978
+ * - there is no conversation at all (a headless exec such as Doctor's
979
+ * `run_assistant_cli`). Clients drop conversation-scoped events without a
980
+ * conversationId and `/v1/pending-interactions` is keyed by conversation,
981
+ * so a conversation-less `secret_request` is invisible everywhere.
946
982
  */
947
983
  export function requestSecretStandalone(
948
984
  params: StandaloneSecretParams,
949
985
  ): Promise<SecretPromptResult> {
986
+ if (!params.conversationId) {
987
+ return mintCollectionLinkFallback(params);
988
+ }
950
989
  const conversation = findConversation(params.conversationId);
951
990
  if (conversation && !conversationSupportsDynamicUi(conversation)) {
952
991
  return mintCollectionLinkFallback(params);