@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
@@ -41,18 +41,12 @@ const capturedMessages: string[] = [];
41
41
  /** Parent conversation ids that a notification was routed to (findConversation). */
42
42
  const capturedParentIds: string[] = [];
43
43
 
44
- /**
45
- * Cron attribution seen by each delivery path. The queued path hands it to
46
- * `enqueueMessage` (the drain applies it later); the immediate path hands it
47
- * straight to `runAgentLoop`.
48
- */
49
44
  const capturedEnqueueCronRunIds: (string | null | undefined)[] = [];
50
- const capturedLoopCronRunIds: (string | null | undefined)[] = [];
51
-
52
- /**
53
- * Whether the stub parent accepts an enqueue. `false` sends
54
- * `injectMessageIntoParent` down its immediate persist-and-run path.
55
- */
45
+ const capturedQueueOptions: {
46
+ queueWhenIdle: boolean;
47
+ metadata?: Record<string, unknown>;
48
+ }[] = [];
49
+ const drainedParents: string[] = [];
56
50
  let parentAcceptsEnqueue = true;
57
51
 
58
52
  // Live subagent conversations, keyed by conversationId. notifyParentFromChild
@@ -74,19 +68,17 @@ mock.module("../daemon/conversation-registry.js", () => ({
74
68
  hasInFlightWork: () => false,
75
69
  enqueueMessage: (options: {
76
70
  content: string;
71
+ queueWhenIdle: boolean;
72
+ metadata?: Record<string, unknown>;
77
73
  cronRunId?: string | null;
78
74
  }) => {
79
75
  capturedMessages.push(options.content);
76
+ capturedQueueOptions.push(options);
80
77
  capturedEnqueueCronRunIds.push(options.cronRunId);
81
78
  return { queued: parentAcceptsEnqueue };
82
79
  },
83
- persistUserMessage: async () => ({ id: "mock-msg", deduplicated: false }),
84
- runAgentLoop: async (
85
- _message: string,
86
- _messageId: string,
87
- options?: { cronRunId?: string | null },
88
- ) => {
89
- capturedLoopCronRunIds.push(options?.cronRunId);
80
+ kickDrainQueue: async () => {
81
+ drainedParents.push(id);
90
82
  },
91
83
  };
92
84
  },
@@ -111,11 +103,15 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
111
103
 
112
104
  import type { Conversation } from "../daemon/conversation.js";
113
105
  import { isToolActiveForContext } from "../daemon/conversation-tool-setup.js";
106
+ import { beginTurnFinalization } from "../daemon/turn-finalization.js";
107
+ import { setLiveVoiceSessionManagerForTesting } from "../live-voice/live-voice-manager.js";
108
+ import { LiveVoiceSessionManager } from "../live-voice/live-voice-session-manager.js";
114
109
  import type { SubagentRecord } from "../persistence/subagent-store.js";
115
110
  import {
116
111
  injectMessageIntoParent,
117
112
  notifyParentFromChild,
118
113
  } from "../subagent/notify.js";
114
+ import type { SubagentParentNotification } from "../subagent/parent-notification.js";
119
115
  import {
120
116
  executeSubagentNotifyParent,
121
117
  notifyParentTool,
@@ -183,12 +179,108 @@ function lastCapturedMessage(): string {
183
179
  function clearCaptured(): void {
184
180
  capturedMessages.length = 0;
185
181
  capturedEnqueueCronRunIds.length = 0;
186
- capturedLoopCronRunIds.length = 0;
182
+ capturedQueueOptions.length = 0;
183
+ drainedParents.length = 0;
187
184
  parentAcceptsEnqueue = true;
188
185
  }
189
186
 
190
187
  // ── Tool definition ────────────────────────────────────────────────
191
188
 
189
+ describe("voice parent notification routing", () => {
190
+ test("only the matching active call claims task updates, without starting a generic parent turn", async () => {
191
+ clearCaptured();
192
+ const received: SubagentParentNotification[] = [];
193
+ let finishClose: (() => void) | undefined;
194
+ const manager = new LiveVoiceSessionManager({
195
+ createSession: (context) => ({
196
+ start: async () => {
197
+ await context.sendFrame({
198
+ type: "ready",
199
+ sessionId: context.sessionId,
200
+ conversationId: "parent-voice",
201
+ });
202
+ },
203
+ handleClientFrame: () => {},
204
+ handleBinaryAudio: () => {},
205
+ close: () =>
206
+ new Promise<void>((resolve) => {
207
+ finishClose = resolve;
208
+ }),
209
+ receiveSubagentNotification: (notification) => {
210
+ received.push(notification);
211
+ return true;
212
+ },
213
+ }),
214
+ });
215
+ setLiveVoiceSessionManagerForTesting(manager);
216
+ const metadata = {
217
+ subagentNotification: {
218
+ subagentId: "task-1",
219
+ status: "completed",
220
+ conversationId: "child-1",
221
+ },
222
+ };
223
+ try {
224
+ await manager.startSession(
225
+ {
226
+ type: "start",
227
+ audio: { mimeType: "audio/pcm", sampleRate: 24_000, channels: 1 },
228
+ },
229
+ { sendFrame: () => {} },
230
+ );
231
+ injectMessageIntoParent("parent-voice", "Task completed", metadata, {
232
+ cronRunId: "run-123",
233
+ });
234
+ expect(received).toEqual([
235
+ {
236
+ taskId: "child-1",
237
+ message: "Task completed",
238
+ metadata,
239
+ cronRunId: "run-123",
240
+ },
241
+ ]);
242
+ expect(capturedMessages).toEqual([]);
243
+ expect(drainedParents).toEqual([]);
244
+
245
+ injectMessageIntoParent("parent-other", "Other task completed", metadata);
246
+ injectMessageIntoParent("parent-voice", "Generic event");
247
+ injectMessageIntoParent("parent-voice", "Hang-up fallback", metadata, {
248
+ bypassLiveVoice: true,
249
+ cronRunId: "run-123",
250
+ });
251
+ expect(received).toHaveLength(1);
252
+ expect(capturedMessages).toEqual([
253
+ "Other task completed",
254
+ "Generic event",
255
+ "Hang-up fallback",
256
+ ]);
257
+ expect(capturedEnqueueCronRunIds.at(-1)).toBe("run-123");
258
+
259
+ const closing = manager.endActiveSession("manager_shutdown");
260
+ injectMessageIntoParent(
261
+ "parent-voice",
262
+ "Finished during hang-up",
263
+ metadata,
264
+ );
265
+ expect(received.at(-1)?.message).toBe("Finished during hang-up");
266
+ expect(capturedMessages).not.toContain("Finished during hang-up");
267
+ finishClose?.();
268
+ await closing;
269
+ injectMessageIntoParent(
270
+ "parent-voice",
271
+ "Finished after hang-up",
272
+ metadata,
273
+ );
274
+ expect(capturedMessages.at(-1)).toBe("Finished after hang-up");
275
+ } finally {
276
+ finishClose?.();
277
+ await manager.endActiveSession("manager_shutdown");
278
+ setLiveVoiceSessionManagerForTesting(null);
279
+ clearCaptured();
280
+ }
281
+ });
282
+ });
283
+
192
284
  describe("notify_parent tool definition", () => {
193
285
  test("has correct core tool definition", () => {
194
286
  const def = notifyParentTool;
@@ -443,31 +535,46 @@ describe("injectMessageIntoParent cron attribution", () => {
443
535
  expect(capturedEnqueueCronRunIds).toEqual(["cron-run-7"]);
444
536
  });
445
537
 
446
- test("the immediate delivery path carries the firing's run id", async () => {
538
+ test("queues simultaneous idle-parent deliveries until turn finalization", async () => {
447
539
  clearCaptured();
448
- // A parent that is not processing rejects the enqueue, so the injection
449
- // persists and runs the turn itself.
450
- parentAcceptsEnqueue = false;
451
-
452
- injectMessageIntoParent("parent-cron", "notification", undefined, {
453
- cronRunId: "cron-run-7",
454
- });
455
- await new Promise((resolve) => setTimeout(resolve, 0));
456
-
457
- expect(capturedLoopCronRunIds).toEqual(["cron-run-7"]);
540
+ const finalize = beginTurnFinalization("parent-handoff");
541
+ try {
542
+ injectMessageIntoParent("parent-handoff", "first result", undefined, {
543
+ bypassLiveVoice: true,
544
+ });
545
+ injectMessageIntoParent("parent-handoff", "second result", undefined, {
546
+ bypassLiveVoice: true,
547
+ });
548
+ expect(capturedMessages).toEqual(["first result", "second result"]);
549
+ expect(capturedQueueOptions).toEqual([
550
+ expect.objectContaining({
551
+ queueWhenIdle: true,
552
+ metadata: { scripted: true },
553
+ }),
554
+ expect.objectContaining({
555
+ queueWhenIdle: true,
556
+ metadata: { scripted: true },
557
+ }),
558
+ ]);
559
+ expect(drainedParents).toEqual([]);
560
+ } finally {
561
+ finalize();
562
+ }
563
+ await Promise.resolve();
564
+ expect(drainedParents).toEqual(["parent-handoff", "parent-handoff"]);
458
565
  });
459
566
 
460
- test("an unscheduled notification carries no run id on either path", async () => {
567
+ test("does not start an unqueued turn when the parent queue rejects delivery", () => {
461
568
  clearCaptured();
462
-
463
- injectMessageIntoParent("parent-plain", "notification");
464
569
  parentAcceptsEnqueue = false;
465
- injectMessageIntoParent("parent-plain", "notification");
466
- await new Promise((resolve) => setTimeout(resolve, 0));
570
+ injectMessageIntoParent("parent-full", "notification");
571
+ expect(drainedParents).toEqual([]);
572
+ });
467
573
 
468
- // Not merely falsy: the option is absent, so nothing downstream reads an
469
- // attribution no firing produced.
470
- expect(capturedEnqueueCronRunIds).toEqual([undefined, undefined]);
471
- expect(capturedLoopCronRunIds).toEqual([undefined]);
574
+ test("an unscheduled notification carries no run id", () => {
575
+ clearCaptured();
576
+ injectMessageIntoParent("parent-plain", "notification");
577
+ expect(capturedEnqueueCronRunIds).toEqual([undefined]);
578
+ expect(drainedParents).toEqual(["parent-plain"]);
472
579
  });
473
580
  });
@@ -22,8 +22,7 @@ mock.module("../daemon/conversation-registry.js", () => ({
22
22
  delivered.push(options.content);
23
23
  return { queued: true };
24
24
  },
25
- persistUserMessage: async () => ({ id: "mock-msg" }),
26
- runAgentLoop: async () => {},
25
+ kickDrainQueue: async () => {},
27
26
  };
28
27
  },
29
28
  }));
@@ -36,8 +35,7 @@ mock.module("../daemon/conversation-store.js", () => ({
36
35
  delivered.push(`rebuilt:${options.content}`);
37
36
  return { queued: true };
38
37
  },
39
- persistUserMessage: async () => ({ id: "rebuilt-msg" }),
40
- runAgentLoop: async () => {},
38
+ kickDrainQueue: async () => {},
41
39
  };
42
40
  },
43
41
  }));
@@ -66,6 +66,40 @@ mock.module("../daemon/conversation-skill-tools.js", () => ({
66
66
  })),
67
67
  }));
68
68
 
69
+ // Records every wire tool surface the resolver persists (conversation id +
70
+ // tool names + the hash it already knew), and lets a test make the write fail.
71
+ type RecordedSurface = {
72
+ tools: ToolDefinition[];
73
+ delegateIndependentTasks: boolean | null;
74
+ };
75
+ let recordedSurfaces: Array<{
76
+ conversationId: string;
77
+ toolNames: string[];
78
+ delegateIndependentTasks: boolean | null;
79
+ knownHash: string | undefined;
80
+ }> = [];
81
+ let recordSurfaceThrows: Error | null = null;
82
+ mock.module("../persistence/conversation-tool-surface.js", () => ({
83
+ recordConversationToolSurface: (
84
+ conversationId: string,
85
+ surface: RecordedSurface,
86
+ knownHash?: string,
87
+ ) => {
88
+ recordedSurfaces.push({
89
+ conversationId,
90
+ toolNames: surface.tools.map((t) => t.name),
91
+ delegateIndependentTasks: surface.delegateIndependentTasks,
92
+ knownHash,
93
+ });
94
+ if (recordSurfaceThrows) {
95
+ throw recordSurfaceThrows;
96
+ }
97
+ return `hash:${surface.tools.map((t) => t.name).join(",")}`;
98
+ },
99
+ hashConversationToolSurface: (surface: RecordedSurface) =>
100
+ `hash:${surface.tools.map((t) => t.name).join(",")}`,
101
+ }));
102
+
69
103
  // ---------------------------------------------------------------------------
70
104
  // Imports after mocks are in place
71
105
  // ---------------------------------------------------------------------------
@@ -75,6 +109,7 @@ import { createSurfaceMutex } from "../daemon/conversation-surfaces.js";
75
109
  import {
76
110
  createResolveToolsCallback,
77
111
  createToolExecutor,
112
+ createWireToolSurfaceRecorder,
78
113
  isRefusedInReadOnlyPass,
79
114
  type SubagentToolStats,
80
115
  } from "../daemon/conversation-tool-setup.js";
@@ -1117,3 +1152,194 @@ describe("createResolveToolsCallback — read-only hides dynamic MCP tools", ()
1117
1152
  expect(resolve(EMPTY_HISTORY).map((t) => t.name)).toContain("srv_send");
1118
1153
  });
1119
1154
  });
1155
+
1156
+ // ---------------------------------------------------------------------------
1157
+ // Resolver: wire tool surface record + replay (fork cache parity)
1158
+ // ---------------------------------------------------------------------------
1159
+
1160
+ describe("createResolveToolsCallback: wire tool surface record and replay", () => {
1161
+ beforeEach(() => {
1162
+ recordedSurfaces = [];
1163
+ recordSurfaceThrows = null;
1164
+ projectedSkillToolNames = [];
1165
+ });
1166
+
1167
+ test("the resolver itself never records: out-of-band callers read it too", () => {
1168
+ const toolDefs = [makeToolDef("remember"), makeToolDef("tool_b")];
1169
+ const ctx = makeProjectionCtx({ conversationId: "conv-live" });
1170
+ const resolve = createResolveToolsCallback(toolDefs, ctx)!;
1171
+
1172
+ // The `/compact` token count resolves outside any turn, where presence
1173
+ // reads clientless; recording here would overwrite the sent surface.
1174
+ resolve(EMPTY_HISTORY);
1175
+
1176
+ expect(recordedSurfaces).toEqual([]);
1177
+ expect(ctx.recordedToolSurfaceHash).toBeUndefined();
1178
+ });
1179
+
1180
+ test("the send-boundary recorder records the sent array, keyed by conversation, and remembers its hash", () => {
1181
+ const ctx = makeProjectionCtx({
1182
+ conversationId: "conv-live",
1183
+ renderedDelegateIndependentTasks: true,
1184
+ });
1185
+ const record = createWireToolSurfaceRecorder(ctx);
1186
+ const sent = [makeToolDef("remember"), makeToolDef("web_search")];
1187
+
1188
+ record(sent);
1189
+ record(sent);
1190
+
1191
+ // Every provider call records; the persistence layer dedupes on the hash
1192
+ // handed back from the previous call.
1193
+ expect(recordedSurfaces).toEqual([
1194
+ {
1195
+ conversationId: "conv-live",
1196
+ toolNames: ["remember", "web_search"],
1197
+ delegateIndependentTasks: true,
1198
+ knownHash: undefined,
1199
+ },
1200
+ {
1201
+ conversationId: "conv-live",
1202
+ toolNames: ["remember", "web_search"],
1203
+ delegateIndependentTasks: true,
1204
+ knownHash: "hash:remember,web_search",
1205
+ },
1206
+ ]);
1207
+ expect(ctx.recordedToolSurfaceHash).toBe("hash:remember,web_search");
1208
+ });
1209
+
1210
+ test("the recorder records the state the prompt build captured, never a re-derivation", () => {
1211
+ const sent = [makeToolDef("remember")];
1212
+
1213
+ // The loop sends the prompt built before the run, so the captured state
1214
+ // is recorded as is even where the live scope would now derive the
1215
+ // opposite: a spawn path excluded after the build (here, an allowlist
1216
+ // with none) still records the section on...
1217
+ createWireToolSurfaceRecorder(
1218
+ makeProjectionCtx({
1219
+ conversationId: "conv-captured-on",
1220
+ subagentAllowedTools: new Set(["remember"]),
1221
+ renderedDelegateIndependentTasks: true,
1222
+ }),
1223
+ )(sent);
1224
+ // ...and a path restored after the build still records it off.
1225
+ createWireToolSurfaceRecorder(
1226
+ makeProjectionCtx({
1227
+ conversationId: "conv-captured-off",
1228
+ renderedDelegateIndependentTasks: false,
1229
+ }),
1230
+ )(sent);
1231
+ // A verbatim system-prompt override captures unknown.
1232
+ createWireToolSurfaceRecorder(
1233
+ makeProjectionCtx({
1234
+ conversationId: "conv-override",
1235
+ renderedDelegateIndependentTasks: null,
1236
+ }),
1237
+ )(sent);
1238
+ // No prompt built yet: unknown as well.
1239
+ createWireToolSurfaceRecorder(
1240
+ makeProjectionCtx({ conversationId: "conv-unbuilt" }),
1241
+ )(sent);
1242
+
1243
+ expect(
1244
+ recordedSurfaces.map((r) => [
1245
+ r.conversationId,
1246
+ r.delegateIndependentTasks,
1247
+ ]),
1248
+ ).toEqual([
1249
+ ["conv-captured-on", true],
1250
+ ["conv-captured-off", false],
1251
+ ["conv-override", null],
1252
+ ["conv-unbuilt", null],
1253
+ ]);
1254
+ });
1255
+
1256
+ test("a failed record is swallowed and still counts as recorded", () => {
1257
+ recordSurfaceThrows = new Error("no such table");
1258
+ const record = createWireToolSurfaceRecorder(
1259
+ makeProjectionCtx({ conversationId: "conv-live" }),
1260
+ );
1261
+
1262
+ expect(() => record([makeToolDef("remember")])).not.toThrow();
1263
+ record([makeToolDef("remember")]);
1264
+
1265
+ // The second call carries the hash from the failed first one, so a
1266
+ // persistent failure is retried once per distinct surface, not per call.
1267
+ expect(recordedSurfaces.map((r) => r.knownHash)).toEqual([
1268
+ undefined,
1269
+ "hash:remember",
1270
+ ]);
1271
+ });
1272
+
1273
+ test("the recorder skips arrays that are not the conversation's own surface", () => {
1274
+ const tools = [makeToolDef("remember")];
1275
+
1276
+ // A replaying wake sends its source's array.
1277
+ createWireToolSurfaceRecorder(
1278
+ makeProjectionCtx({ conversationId: "conv-fork", wireToolReplay: tools }),
1279
+ )(tools);
1280
+ // A tools-disabled call sends nothing; a fork replaying [] could never
1281
+ // call remember.
1282
+ createWireToolSurfaceRecorder(
1283
+ makeProjectionCtx({ conversationId: "conv-live" }),
1284
+ )([]);
1285
+ // Disk-pressure cleanup narrows the wire to cleanup tools.
1286
+ createWireToolSurfaceRecorder(
1287
+ makeProjectionCtx({
1288
+ conversationId: "conv-live",
1289
+ diskPressureCleanupModeActive: true,
1290
+ }),
1291
+ )(tools);
1292
+
1293
+ expect(recordedSurfaces).toEqual([]);
1294
+ });
1295
+
1296
+ test("replays wireToolReplay verbatim on the wire while execution still derives from the fork's own context", () => {
1297
+ projectedSkillToolNames = ["scaffold_managed_skill"];
1298
+ const replay: ToolDefinition[] = [
1299
+ makeToolDef("bash"),
1300
+ makeToolDef("remember"),
1301
+ makeToolDef("bell_jingle"),
1302
+ {
1303
+ type: "web_search_20250305",
1304
+ name: "web_search",
1305
+ max_uses: 5,
1306
+ } as unknown as ToolDefinition,
1307
+ ];
1308
+ // The fork's own registry lacks bell_jingle (a user-plugin tool the
1309
+ // worker never loads) and web_search (a server tool the loop appends).
1310
+ const toolDefs = [makeToolDef("remember"), makeToolDef("bash")];
1311
+ const ctx = makeProjectionCtx({
1312
+ conversationId: "conv-fork",
1313
+ subagentAllowedTools: new Set(["remember"]),
1314
+ subagentToolGateMode: "execution",
1315
+ wireToolReplay: replay,
1316
+ });
1317
+ const resolve = createResolveToolsCallback(toolDefs, ctx)!;
1318
+
1319
+ const tools = resolve(EMPTY_HISTORY);
1320
+
1321
+ // Byte-identical to the source's recorded array, in the source's order,
1322
+ // including definitions this process could never resolve.
1323
+ expect(JSON.stringify(tools)).toBe(JSON.stringify(replay));
1324
+ // Execution-side inventory is still the fork's own derivation (plus the
1325
+ // preactivated skill tools), never widened by the replayed definitions.
1326
+ expect(ctx.allowedToolNames).toEqual(
1327
+ new Set(["remember", "bash", "scaffold_managed_skill"]),
1328
+ );
1329
+ });
1330
+
1331
+ test("replay returns a fresh array each call so the loop cannot mutate the recorded one", () => {
1332
+ const replay = [makeToolDef("remember")];
1333
+ const ctx = makeProjectionCtx({
1334
+ conversationId: "conv-fork",
1335
+ wireToolReplay: replay,
1336
+ });
1337
+ const resolve = createResolveToolsCallback([makeToolDef("remember")], ctx)!;
1338
+
1339
+ const first = resolve(EMPTY_HISTORY);
1340
+ first.push(makeToolDef("injected"));
1341
+
1342
+ expect(resolve(EMPTY_HISTORY).map((t) => t.name)).toEqual(["remember"]);
1343
+ expect(replay.map((t) => t.name)).toEqual(["remember"]);
1344
+ });
1345
+ });
@@ -82,6 +82,7 @@ import type {
82
82
  import type { CurrentTurnSurface } from "../daemon/conversation-surface-state.js";
83
83
  import type { SurfaceStateEntry } from "../daemon/conversation-surface-state.js";
84
84
  import type { SurfaceType } from "../daemon/message-protocol.js";
85
+ import { mockUnownedModeSessions } from "./helpers/mock-conversation.js";
85
86
 
86
87
  const CONVERSATION_ID = "conv-in-flight-surface-1";
87
88
  const SURFACE_ID = "surface-in-flight-1";
@@ -112,6 +113,7 @@ function makeContext(): Conversation {
112
113
  accumulatedSurfaceState: new Map<string, Record<string, unknown>>(),
113
114
  surfaceActionRequestIds: new Set<string>(),
114
115
  currentTurnSurfaces: [],
116
+ modeSessions: mockUnownedModeSessions(),
115
117
  pendingStandaloneSurfaces: new Map(),
116
118
  recentlyCompletedStandaloneSurfaces: new Map(),
117
119
  isProcessing: () => false,
@@ -44,6 +44,7 @@ import {
44
44
  formatShellOutput,
45
45
  MAX_OUTPUT_LENGTH,
46
46
  OUTPUT_TRUNCATED_TAG,
47
+ SHELL_DID_NOT_START_MESSAGE,
47
48
  } from "../tools/shared/shell-output.js";
48
49
  import {
49
50
  ALWAYS_INJECTED_ENV_VARS,
@@ -334,6 +335,13 @@ describe("formatShellOutput", () => {
334
335
  expect(result.isError).toBe(false);
335
336
  });
336
337
 
338
+ test("a close with exit 0 and empty pipes is an error when the process never started", () => {
339
+ const result = formatShellOutput("", "", 0, false, 120, { started: false });
340
+ expect(result.content).toBe(SHELL_DID_NOT_START_MESSAGE);
341
+ expect(result.isError).toBe(true);
342
+ expect(result.content).not.toBe("<command_completed />");
343
+ });
344
+
337
345
  test("failed command with no output shows exit code tag and descriptive message", () => {
338
346
  const result = formatShellOutput("", "", 1, false, 120);
339
347
  expect(result.content).toContain('<command_exit code="1" />');
@@ -90,6 +90,7 @@ mock.module("../messaging/providers/slack/adapter.js", () => ({
90
90
 
91
91
  import { v4 as uuid } from "uuid";
92
92
 
93
+ import * as inboundTrustReader from "../calls/inbound-trust-reader.js";
93
94
  import {
94
95
  loadRawConfig,
95
96
  saveRawConfig,
@@ -142,10 +143,15 @@ installDefaultThreadPageMock();
142
143
  backfillThreadMock.mockResolvedValue([]);
143
144
  const backfillDmMock = spyOn(slackBackfill, "backfillDm");
144
145
  backfillDmMock.mockResolvedValue([]);
146
+ // Backfilled senders are classified by the gateway verdict. With no gateway in
147
+ // the test process the real read reports unreachable, so tests that need a
148
+ // verdict stub it per call.
149
+ const readInboundTrustSpy = spyOn(inboundTrustReader, "readInboundTrust");
145
150
 
146
151
  afterAll(() => {
147
152
  backfillThreadPageMock.mockRestore();
148
153
  backfillDmMock.mockRestore();
154
+ readInboundTrustSpy.mockRestore();
149
155
  });
150
156
 
151
157
  // ---------------------------------------------------------------------------
@@ -307,6 +313,7 @@ interface PersistedRow {
307
313
  provenanceSourceChannel: string | undefined;
308
314
  provenanceGuardianExternalUserId: string | undefined;
309
315
  provenanceRequesterIdentifier: string | undefined;
316
+ provenanceContactId: string | undefined;
310
317
  }
311
318
 
312
319
  const EXTERNAL_CONTENT_WRAPPER =
@@ -340,6 +347,7 @@ function readPersistedSlackRows(conversationId: string): PersistedRow[] {
340
347
  provenanceSourceChannel: undefined,
341
348
  provenanceGuardianExternalUserId: undefined,
342
349
  provenanceRequesterIdentifier: undefined,
350
+ provenanceContactId: undefined,
343
351
  };
344
352
  if (!row.metadata) {
345
353
  out.push(blank);
@@ -402,6 +410,10 @@ function readPersistedSlackRows(conversationId: string): PersistedRow[] {
402
410
  typeof envelope.provenanceRequesterIdentifier === "string"
403
411
  ? envelope.provenanceRequesterIdentifier
404
412
  : undefined,
413
+ provenanceContactId:
414
+ typeof envelope.provenanceContactId === "string"
415
+ ? envelope.provenanceContactId
416
+ : undefined,
405
417
  });
406
418
  }
407
419
  return out;
@@ -1149,6 +1161,47 @@ describe("triggerSlackThreadBackfillIfNeeded — gap detection and persistence",
1149
1161
  expect(persisted.provenanceRequesterIdentifier).toBe("U_ANITA");
1150
1162
  });
1151
1163
 
1164
+ test("backfilled thread rows record the sender's gateway trust class and contact id", async () => {
1165
+ const conv = createTestConversation();
1166
+ readInboundTrustSpy.mockImplementationOnce(async () => ({
1167
+ ok: true,
1168
+ verdict: {
1169
+ trustClass: "trusted_contact",
1170
+ canonicalSenderId: "U_ANITA",
1171
+ contactId: "contact-anita",
1172
+ channelId: "channel-anita",
1173
+ status: "active",
1174
+ policy: "allow",
1175
+ },
1176
+ admissionPolicy: null,
1177
+ }));
1178
+ backfillThreadMock.mockImplementation(async () => [
1179
+ makeBackfillMessage({
1180
+ id: "1234.0",
1181
+ text: "the export endpoint needs a scoped token",
1182
+ threadId: undefined,
1183
+ sender: { id: "U_ANITA", name: "Anita" },
1184
+ }),
1185
+ ]);
1186
+
1187
+ await triggerSlackThreadBackfillIfNeeded({
1188
+ conversationId: conv.id,
1189
+ channelId: SLACK_CHANNEL_ID,
1190
+ threadTs: "1234.0",
1191
+ guardianExternalUserId: "U_GUARDIAN",
1192
+ });
1193
+
1194
+ const [persisted] = readPersistedSlackRows(conv.id).filter(
1195
+ (p) => p.channelTs === "1234.0",
1196
+ );
1197
+ expect(persisted?.provenanceTrustClass).toBe("trusted_contact");
1198
+ expect(persisted?.provenanceContactId).toBe("contact-anita");
1199
+ expect(readInboundTrustSpy).toHaveBeenLastCalledWith({
1200
+ channelType: "slack",
1201
+ actorExternalId: "U_ANITA",
1202
+ });
1203
+ });
1204
+
1152
1205
  test("backfilled Slack timezone metadata derives timestamp and speaker fields", async () => {
1153
1206
  const conv = createTestConversation();
1154
1207
  setConfiguredUserTimezone("America/Denver");
@@ -99,6 +99,7 @@ import {
99
99
  getCurrentSeq,
100
100
  stampAndBuffer,
101
101
  } from "../runtime/assistant-stream-state.js";
102
+ import { mockUnownedModeSessions } from "./helpers/mock-conversation.js";
102
103
 
103
104
  // ── Helpers ───────────────────────────────────────────────────────────────────
104
105
 
@@ -134,6 +135,7 @@ function createMockDeps(
134
135
  },
135
136
  markWorkspaceTopLevelDirty: () => {},
136
137
  currentTurnSurfaces: [],
138
+ modeSessions: mockUnownedModeSessions(),
137
139
  } as unknown as EventHandlerDeps["ctx"],
138
140
  onEvent: (msg: AssistantEvent) => {
139
141
  emittedEvents.push(msg);