@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
@@ -0,0 +1,460 @@
1
+ import { and, asc, eq, inArray, sql } from "drizzle-orm";
2
+
3
+ import {
4
+ type ModeSessionMode,
5
+ modeSessionRowStartsDisplay,
6
+ type ModeSessionStatus,
7
+ type ModeSessionSummary,
8
+ ModeSessionSummarySchema,
9
+ } from "../api/mode-session.js";
10
+ import { type DrizzleDb, getDb } from "./db-connection.js";
11
+ import {
12
+ readMessageSentAt,
13
+ readModeSessionMetadata,
14
+ } from "./message-metadata.js";
15
+ import { conversationModeSessions, messages } from "./schema/index.js";
16
+
17
+ export type ModeSessionWriteFailureReason =
18
+ | "already_exists"
19
+ | "not_found"
20
+ | "stale_revision"
21
+ | "terminal";
22
+
23
+ export type ModeSessionWriteResult =
24
+ | { ok: true; session: ModeSessionSummary }
25
+ | {
26
+ ok: false;
27
+ reason: ModeSessionWriteFailureReason;
28
+ session?: ModeSessionSummary;
29
+ };
30
+
31
+ export interface ModeSessionStoreOptions {
32
+ db?: DrizzleDb;
33
+ }
34
+
35
+ type ModeSessionReader = Pick<DrizzleDb, "select">;
36
+
37
+ interface ModeSessionMutationOptions extends ModeSessionStoreOptions {
38
+ acceptTerminal?: (
39
+ current: typeof conversationModeSessions.$inferSelect,
40
+ ) => boolean;
41
+ }
42
+
43
+ export interface BeginModeSessionInput {
44
+ id: string;
45
+ conversationId: string;
46
+ mode: ModeSessionMode;
47
+ sourceStartedAt: number;
48
+ }
49
+
50
+ export interface RevisionedModeSessionInput {
51
+ id: string;
52
+ conversationId: string;
53
+ expectedRevision: number;
54
+ }
55
+
56
+ export interface UpdateModeSessionActivityInput extends RevisionedModeSessionInput {
57
+ lastActivityAt: number;
58
+ lastOwnedMessageId?: string | null;
59
+ }
60
+
61
+ export interface UpdateModeSessionBoundariesInput extends RevisionedModeSessionInput {
62
+ firstIncluded: { at: number; messageId: string } | null;
63
+ lastActivityAt: number;
64
+ lastOwnedMessageId: string | null;
65
+ }
66
+
67
+ interface FinalizeModeSessionInputBase extends RevisionedModeSessionInput {
68
+ endReason: string;
69
+ lastActivityAt?: number;
70
+ lastOwnedMessageId?: string | null;
71
+ }
72
+
73
+ export type FinalizeModeSessionInput = FinalizeModeSessionInputBase &
74
+ (
75
+ | { status: Extract<ModeSessionStatus, "completed">; endedAt: number }
76
+ | {
77
+ status: Extract<ModeSessionStatus, "interrupted">;
78
+ endedAt: number | null;
79
+ }
80
+ );
81
+
82
+ function toSummary(
83
+ row: typeof conversationModeSessions.$inferSelect,
84
+ ): ModeSessionSummary {
85
+ return ModeSessionSummarySchema.parse(row);
86
+ }
87
+
88
+ function getSession(
89
+ database: ModeSessionReader,
90
+ conversationId: string,
91
+ id: string,
92
+ ): typeof conversationModeSessions.$inferSelect | undefined {
93
+ return database
94
+ .select()
95
+ .from(conversationModeSessions)
96
+ .where(
97
+ and(
98
+ eq(conversationModeSessions.conversationId, conversationId),
99
+ eq(conversationModeSessions.id, id),
100
+ ),
101
+ )
102
+ .get();
103
+ }
104
+
105
+ function classifyRejectedWrite(
106
+ current: typeof conversationModeSessions.$inferSelect | undefined,
107
+ expectedRevision: number,
108
+ ): ModeSessionWriteResult {
109
+ if (!current) {
110
+ return { ok: false, reason: "not_found" };
111
+ }
112
+ const session = toSummary(current);
113
+ if (current.status !== "active") {
114
+ return { ok: false, reason: "terminal", session };
115
+ }
116
+ if (current.revision !== expectedRevision) {
117
+ return { ok: false, reason: "stale_revision", session };
118
+ }
119
+ throw new Error("Mode session write was rejected without a state conflict");
120
+ }
121
+
122
+ function mutateActiveSession(
123
+ input: RevisionedModeSessionInput,
124
+ buildValues: (
125
+ current: typeof conversationModeSessions.$inferSelect,
126
+ ) => Partial<typeof conversationModeSessions.$inferInsert>,
127
+ options?: ModeSessionMutationOptions,
128
+ ): ModeSessionWriteResult {
129
+ const database = options?.db ?? getDb();
130
+ return database.transaction(
131
+ (tx) => {
132
+ const current = getSession(tx, input.conversationId, input.id);
133
+ if (
134
+ !current ||
135
+ current.status !== "active" ||
136
+ current.revision !== input.expectedRevision
137
+ ) {
138
+ if (
139
+ current &&
140
+ current.status !== "active" &&
141
+ options?.acceptTerminal?.(current)
142
+ ) {
143
+ return { ok: true, session: toSummary(current) };
144
+ }
145
+ return classifyRejectedWrite(current, input.expectedRevision);
146
+ }
147
+
148
+ tx.update(conversationModeSessions)
149
+ .set({
150
+ ...buildValues(current),
151
+ revision: sql`${conversationModeSessions.revision} + 1`,
152
+ })
153
+ .where(
154
+ and(
155
+ eq(conversationModeSessions.conversationId, input.conversationId),
156
+ eq(conversationModeSessions.id, input.id),
157
+ eq(conversationModeSessions.status, "active"),
158
+ eq(conversationModeSessions.revision, input.expectedRevision),
159
+ ),
160
+ )
161
+ .run();
162
+
163
+ const updated = getSession(tx, input.conversationId, input.id);
164
+ if (!updated || updated.revision !== input.expectedRevision + 1) {
165
+ return classifyRejectedWrite(updated, input.expectedRevision);
166
+ }
167
+ return { ok: true, session: toSummary(updated) };
168
+ },
169
+ { behavior: "immediate" },
170
+ );
171
+ }
172
+
173
+ export function beginConversationModeSession(
174
+ input: BeginModeSessionInput,
175
+ options?: ModeSessionStoreOptions,
176
+ ): ModeSessionWriteResult {
177
+ const database = options?.db ?? getDb();
178
+ return database.transaction(
179
+ (tx) => {
180
+ const existing = tx
181
+ .select()
182
+ .from(conversationModeSessions)
183
+ .where(eq(conversationModeSessions.id, input.id))
184
+ .get();
185
+ if (existing) {
186
+ return {
187
+ ok: false,
188
+ reason: "already_exists",
189
+ ...(existing.conversationId === input.conversationId
190
+ ? { session: toSummary(existing) }
191
+ : {}),
192
+ };
193
+ }
194
+
195
+ tx.insert(conversationModeSessions)
196
+ .values({
197
+ ...input,
198
+ status: "active",
199
+ firstIncludedAt: null,
200
+ firstIncludedMessageId: null,
201
+ lastActivityAt: input.sourceStartedAt,
202
+ lastOwnedMessageId: null,
203
+ endedAt: null,
204
+ endReason: null,
205
+ revision: 1,
206
+ })
207
+ .run();
208
+ const created = getSession(tx, input.conversationId, input.id);
209
+ if (!created) {
210
+ throw new Error("Mode session insert did not create a readable row");
211
+ }
212
+ return { ok: true, session: toSummary(created) };
213
+ },
214
+ { behavior: "immediate" },
215
+ );
216
+ }
217
+
218
+ export function updateConversationModeSessionActivity(
219
+ input: UpdateModeSessionActivityInput,
220
+ options?: ModeSessionStoreOptions,
221
+ ): ModeSessionWriteResult {
222
+ return mutateActiveSession(
223
+ input,
224
+ (current) => ({
225
+ lastActivityAt: Math.max(current.lastActivityAt, input.lastActivityAt),
226
+ ...(input.lastOwnedMessageId !== undefined
227
+ ? { lastOwnedMessageId: input.lastOwnedMessageId }
228
+ : {}),
229
+ }),
230
+ options,
231
+ );
232
+ }
233
+
234
+ export function updateConversationModeSessionBoundaries(
235
+ input: UpdateModeSessionBoundariesInput,
236
+ options?: ModeSessionStoreOptions,
237
+ ): ModeSessionWriteResult {
238
+ return mutateActiveSession(
239
+ input,
240
+ (current) => ({
241
+ firstIncludedAt: input.firstIncluded?.at ?? null,
242
+ firstIncludedMessageId: input.firstIncluded?.messageId ?? null,
243
+ lastActivityAt: Math.max(current.lastActivityAt, input.lastActivityAt),
244
+ lastOwnedMessageId: input.lastOwnedMessageId,
245
+ }),
246
+ options,
247
+ );
248
+ }
249
+
250
+ export function advanceConversationModeSessionRevision(
251
+ input: RevisionedModeSessionInput,
252
+ options?: ModeSessionStoreOptions,
253
+ ): ModeSessionWriteResult {
254
+ return mutateActiveSession(input, () => ({}), options);
255
+ }
256
+
257
+ export function finalizeConversationModeSession(
258
+ input: FinalizeModeSessionInput,
259
+ options?: ModeSessionStoreOptions,
260
+ ): ModeSessionWriteResult {
261
+ return mutateActiveSession(
262
+ input,
263
+ (current) => {
264
+ const lastActivityAt = Math.max(
265
+ current.lastActivityAt,
266
+ input.lastActivityAt ?? current.lastActivityAt,
267
+ );
268
+ if (input.endedAt !== null && input.endedAt < lastActivityAt) {
269
+ throw new Error("Mode session end cannot precede its last activity");
270
+ }
271
+ return {
272
+ status: input.status,
273
+ endedAt: input.endedAt,
274
+ endReason: input.endReason,
275
+ lastActivityAt,
276
+ ...(input.lastOwnedMessageId !== undefined
277
+ ? { lastOwnedMessageId: input.lastOwnedMessageId }
278
+ : {}),
279
+ };
280
+ },
281
+ {
282
+ ...options,
283
+ acceptTerminal: (current) =>
284
+ current.status === input.status &&
285
+ current.endedAt === input.endedAt &&
286
+ current.endReason === input.endReason &&
287
+ (input.lastActivityAt === undefined ||
288
+ input.lastActivityAt <= current.lastActivityAt) &&
289
+ (input.lastOwnedMessageId === undefined ||
290
+ input.lastOwnedMessageId === current.lastOwnedMessageId),
291
+ },
292
+ );
293
+ }
294
+
295
+ export function getConversationModeSession(
296
+ conversationId: string,
297
+ id: string,
298
+ options?: ModeSessionStoreOptions,
299
+ ): ModeSessionSummary | null {
300
+ const row = getSession(options?.db ?? getDb(), conversationId, id);
301
+ return row ? toSummary(row) : null;
302
+ }
303
+
304
+ export function listConversationModeSessionsByIds(
305
+ conversationId: string,
306
+ ids: readonly string[],
307
+ options?: ModeSessionStoreOptions,
308
+ ): ModeSessionSummary[] {
309
+ if (ids.length === 0) {
310
+ return [];
311
+ }
312
+ const rows = (options?.db ?? getDb())
313
+ .select()
314
+ .from(conversationModeSessions)
315
+ .where(
316
+ and(
317
+ eq(conversationModeSessions.conversationId, conversationId),
318
+ inArray(conversationModeSessions.id, [...new Set(ids)]),
319
+ ),
320
+ )
321
+ .all();
322
+ return rows.map(toSummary);
323
+ }
324
+
325
+ export function recoverActiveConversationModeSessions(
326
+ options?: ModeSessionStoreOptions,
327
+ ): number {
328
+ const result = (options?.db ?? getDb())
329
+ .update(conversationModeSessions)
330
+ .set({
331
+ status: "interrupted",
332
+ endedAt: null,
333
+ endReason: "assistant_restarted",
334
+ revision: sql`${conversationModeSessions.revision} + 1`,
335
+ })
336
+ .where(eq(conversationModeSessions.status, "active"))
337
+ .run() as unknown as { changes: number };
338
+ return result.changes;
339
+ }
340
+
341
+ /** Recompute replaceable row boundaries after destructive transcript edits. */
342
+ export function repairConversationModeSessionBoundaries(
343
+ conversationId: string,
344
+ options?: ModeSessionStoreOptions,
345
+ ): number {
346
+ const database = options?.db ?? getDb();
347
+ return database.transaction(
348
+ (tx) => {
349
+ const sessions = tx
350
+ .select()
351
+ .from(conversationModeSessions)
352
+ .where(eq(conversationModeSessions.conversationId, conversationId))
353
+ .all();
354
+ if (sessions.length === 0) {
355
+ return 0;
356
+ }
357
+ const sessionsById = new Map(
358
+ sessions.map((session) => [session.id, session]),
359
+ );
360
+ const boundaries = new Map<
361
+ string,
362
+ {
363
+ firstAt: number | null;
364
+ firstMessageId: string | null;
365
+ lastAt: number;
366
+ lastMessageId: string;
367
+ }
368
+ >();
369
+ for (const message of tx
370
+ .select({
371
+ id: messages.id,
372
+ role: messages.role,
373
+ createdAt: messages.createdAt,
374
+ metadata: messages.metadata,
375
+ })
376
+ .from(messages)
377
+ .where(eq(messages.conversationId, conversationId))
378
+ .orderBy(asc(messages.createdAt), asc(messages.id))
379
+ .all()) {
380
+ const owner = readModeSessionMetadata(message.metadata);
381
+ if (!owner) {
382
+ continue;
383
+ }
384
+ const session = sessionsById.get(owner.id);
385
+ if (!session || session.mode !== owner.mode) {
386
+ continue;
387
+ }
388
+ const at = readMessageSentAt(message.metadata) ?? message.createdAt;
389
+ const startsDisplayBoundary = modeSessionRowStartsDisplay(
390
+ session.mode,
391
+ message.role === "assistant",
392
+ );
393
+ const current = boundaries.get(owner.id);
394
+ if (!current) {
395
+ boundaries.set(owner.id, {
396
+ firstAt: startsDisplayBoundary ? at : null,
397
+ firstMessageId: startsDisplayBoundary ? message.id : null,
398
+ lastAt: at,
399
+ lastMessageId: message.id,
400
+ });
401
+ } else {
402
+ if (
403
+ startsDisplayBoundary &&
404
+ (current.firstAt === null || at < current.firstAt)
405
+ ) {
406
+ current.firstAt = at;
407
+ current.firstMessageId = message.id;
408
+ }
409
+ current.lastAt = Math.max(current.lastAt, at);
410
+ current.lastMessageId = message.id;
411
+ }
412
+ }
413
+
414
+ let repaired = 0;
415
+ for (const session of sessions) {
416
+ const boundary = boundaries.get(session.id);
417
+ const firstIncludedAt = boundary?.firstAt ?? null;
418
+ const firstIncludedMessageId = boundary?.firstMessageId ?? null;
419
+ const lastOwnedMessageId = boundary?.lastMessageId ?? null;
420
+ const observedLastActivityAt =
421
+ boundary?.lastAt ?? session.lastActivityAt;
422
+ const lastActivityAt =
423
+ session.endedAt === null
424
+ ? Math.max(session.lastActivityAt, observedLastActivityAt)
425
+ : Math.min(
426
+ session.endedAt,
427
+ Math.max(session.lastActivityAt, observedLastActivityAt),
428
+ );
429
+ if (
430
+ session.firstIncludedAt === firstIncludedAt &&
431
+ session.firstIncludedMessageId === firstIncludedMessageId &&
432
+ session.lastOwnedMessageId === lastOwnedMessageId &&
433
+ session.lastActivityAt === lastActivityAt
434
+ ) {
435
+ continue;
436
+ }
437
+ const result = tx
438
+ .update(conversationModeSessions)
439
+ .set({
440
+ firstIncludedAt,
441
+ firstIncludedMessageId,
442
+ lastOwnedMessageId,
443
+ lastActivityAt,
444
+ revision: sql`${conversationModeSessions.revision} + 1`,
445
+ })
446
+ .where(
447
+ and(
448
+ eq(conversationModeSessions.conversationId, conversationId),
449
+ eq(conversationModeSessions.id, session.id),
450
+ eq(conversationModeSessions.revision, session.revision),
451
+ ),
452
+ )
453
+ .run() as unknown as { changes: number };
454
+ repaired += result.changes;
455
+ }
456
+ return repaired;
457
+ },
458
+ { behavior: "immediate" },
459
+ );
460
+ }
@@ -1,3 +1,4 @@
1
+ import type { ToolDefinition } from "../providers/types.js";
1
2
  import type {
2
3
  AddMessageOptions,
3
4
  ConversationRow,
@@ -5,6 +6,7 @@ import type {
5
6
  MessageRow,
6
7
  } from "./conversation-crud.js";
7
8
  import type { ArchiveStatusFilter } from "./conversation-queries.js";
9
+ import type { ConversationToolSurface } from "./conversation-tool-surface.js";
8
10
  import type { ConversationType } from "./conversation-types.js";
9
11
 
10
12
  /**
@@ -52,6 +54,34 @@ export async function getMessages(
52
54
  return fn(conversationId);
53
55
  }
54
56
 
57
+ /**
58
+ * What the conversation's most recent live turn sent to the provider that a
59
+ * replaying fork reproduces verbatim (its tool definitions and the
60
+ * delegation-section state of its system prompt), or `null` when none has
61
+ * been recorded.
62
+ */
63
+ export async function getRecordedConversationToolSurface(
64
+ conversationId: string,
65
+ ): Promise<ConversationToolSurface | null> {
66
+ const { getConversationToolSurface: fn } =
67
+ await import("./conversation-tool-surface.js");
68
+ return fn(conversationId);
69
+ }
70
+
71
+ /**
72
+ * The tool definitions the conversation's most recent live turn sent to the
73
+ * provider, or `null` when none has been recorded. A projection of
74
+ * {@link getRecordedConversationToolSurface}: a fork replaying the source's
75
+ * request needs the whole record, whose delegation-section state the system
76
+ * prompt tier of the provider cache prefix depends on.
77
+ */
78
+ export async function getConversationToolSurface(
79
+ conversationId: string,
80
+ ): Promise<ToolDefinition[] | null> {
81
+ const surface = await getRecordedConversationToolSurface(conversationId);
82
+ return surface?.tools ?? null;
83
+ }
84
+
55
85
  /** Whether the conversation currently has a turn in flight. */
56
86
  export async function isConversationProcessing(id: string): Promise<boolean> {
57
87
  const { isConversationProcessing: fn } =
@@ -955,19 +955,6 @@ function likeContainsPattern(query: string): string {
955
955
  .replace(/_/g, "\\_")}%`;
956
956
  }
957
957
 
958
- /**
959
- * Whether the sparse Qdrant `messages_lexical` index — the only source of
960
- * message-content matches — is a safe read source. Content matching is
961
- * unavailable (title matches only) until the one-time upgrade backfill has
962
- * fully drained: a partially populated collection would silently miss older
963
- * content (an empty result — not a throw). Indexing itself is unconditional
964
- * host infrastructure, so completion is the only gate; the recall read site
965
- * applies the same one via the shared {@link isLexicalBackfillComplete}.
966
- */
967
- function isMessageContentSearchAvailable(): boolean {
968
- return isLexicalBackfillComplete();
969
- }
970
-
971
958
  /**
972
959
  * Full-text search across message content.
973
960
  *
@@ -976,9 +963,9 @@ function isMessageContentSearchAvailable(): boolean {
976
963
  * merged with a `LIKE` match on conversation titles; matching conversations
977
964
  * return with their relevant messages, ordered by most recently updated.
978
965
  *
979
- * Content matching is index-only — there is no `messages.content` scan
966
+ * Content matching is index-only: there is no `messages.content` scan
980
967
  * fallback and no other content source. Only the title arm can match while
981
- * the index is not a safe read source ({@link isMessageContentSearchAvailable}),
968
+ * the index is not a safe read source ({@link isLexicalBackfillComplete}),
982
969
  * for a query that tokenizes to nothing under the shared tokenizer (non-ASCII
983
970
  * or single-char input like "你", "é", "C++"), or when the Qdrant lexical
984
971
  * lookup fails (logged). An unindexed or unreachable index yields fewer
@@ -1017,7 +1004,7 @@ export async function searchConversations(
1017
1004
  const maxMsgsPerConv = opts?.maxMessagesPerConversation ?? 3;
1018
1005
 
1019
1006
  const hasTokens = hasLexicalTokens(trimmed);
1020
- const contentSearchAvailable = isMessageContentSearchAvailable();
1007
+ const contentSearchAvailable = isLexicalBackfillComplete();
1021
1008
 
1022
1009
  // LIKE pattern for title matching (message-content indexes don't cover titles).
1023
1010
  const titlePattern = likeContainsPattern(query);
@@ -1453,9 +1440,9 @@ function buildExcerptFromText(
1453
1440
  text.length,
1454
1441
  match.index + match.length + EXCERPT_WINDOW,
1455
1442
  );
1456
- const excerpt =
1443
+ return (
1457
1444
  (start > 0 ? "\u2026" : "") +
1458
1445
  text.slice(start, end).replace(/\s+/g, " ").trim() +
1459
- (end < text.length ? "\u2026" : "");
1460
- return excerpt;
1446
+ (end < text.length ? "\u2026" : "")
1447
+ );
1461
1448
  }
@@ -0,0 +1,135 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import { eq, sql } from "drizzle-orm";
4
+
5
+ import type { ToolDefinition } from "../providers/types.js";
6
+ import { getDb } from "./db-connection.js";
7
+ import { conversationToolSurfaces } from "./schema/index.js";
8
+
9
+ /**
10
+ * Per-conversation record of what the most recent live turn sent to the
11
+ * provider that a fork wake cannot re-derive (`conversation_tool_surfaces`).
12
+ *
13
+ * The provider prompt cache is a byte-exact prefix match over
14
+ * `tools -> system -> messages`, so a background wake that forks a
15
+ * conversation can only reuse the source's cached prefix by sending the SAME
16
+ * tools array under the SAME system prompt. Re-deriving either on the fork
17
+ * cannot guarantee that: the fork may run in another process (a different
18
+ * tool registry), with no connected clients (different host-tool gates),
19
+ * under a presence the persisted message stamps do not encode, or under a
20
+ * wake scope that cannot spawn subagents where the source could (the system
21
+ * prompt's delegation section). Recording the resolved values and replaying
22
+ * them verbatim can.
23
+ */
24
+
25
+ /** What a live turn sent that a replaying fork reproduces verbatim. */
26
+ export interface ConversationToolSurface {
27
+ /** The tool definitions the turn sent, exactly as resolved. */
28
+ tools: ToolDefinition[];
29
+ /**
30
+ * Whether the turn's system prompt rendered the parallel-delegation
31
+ * section (`01-parallel-tasks`), which the prompt derives from the same
32
+ * resolved tool surface plus the turn's channel. `null` when unknown: the
33
+ * turn ran on a system-prompt override, or the row predates the column.
34
+ */
35
+ delegateIndependentTasks: boolean | null;
36
+ }
37
+
38
+ /** Content hash of the serialized surface. */
39
+ export function hashConversationToolSurface(
40
+ surface: ConversationToolSurface,
41
+ ): string {
42
+ return hashSurface(
43
+ JSON.stringify(surface.tools),
44
+ surface.delegateIndependentTasks,
45
+ );
46
+ }
47
+
48
+ function hashSurface(
49
+ toolsJson: string,
50
+ delegateIndependentTasks: boolean | null,
51
+ ): string {
52
+ const marker =
53
+ delegateIndependentTasks === null
54
+ ? ""
55
+ : delegateIndependentTasks
56
+ ? "1"
57
+ : "0";
58
+ return createHash("sha256")
59
+ .update(toolsJson)
60
+ .update("\n")
61
+ .update(marker)
62
+ .digest("hex")
63
+ .slice(0, 32);
64
+ }
65
+
66
+ /**
67
+ * Persist `surface` as the conversation's current wire surface and return
68
+ * its hash. `knownHash` is the hash the caller last recorded for this
69
+ * conversation (undefined when it has recorded nothing this process
70
+ * lifetime): a matching hash skips the statement outright. Otherwise the
71
+ * upsert only rewrites a row whose stored hash differs, so a conversation
72
+ * reloaded from disk never rewrites an unchanged surface either.
73
+ */
74
+ export function recordConversationToolSurface(
75
+ conversationId: string,
76
+ surface: ConversationToolSurface,
77
+ knownHash?: string,
78
+ ): string {
79
+ const toolsJson = JSON.stringify(surface.tools);
80
+ const { delegateIndependentTasks } = surface;
81
+ const toolsHash = hashSurface(toolsJson, delegateIndependentTasks);
82
+ if (knownHash === toolsHash) {
83
+ return toolsHash;
84
+ }
85
+ const updatedAt = Date.now();
86
+ getDb()
87
+ .insert(conversationToolSurfaces)
88
+ .values({
89
+ conversationId,
90
+ toolsJson,
91
+ toolsHash,
92
+ delegateIndependentTasks,
93
+ updatedAt,
94
+ })
95
+ .onConflictDoUpdate({
96
+ target: conversationToolSurfaces.conversationId,
97
+ set: { toolsJson, toolsHash, delegateIndependentTasks, updatedAt },
98
+ setWhere: sql`${conversationToolSurfaces.toolsHash} <> excluded.tools_hash`,
99
+ })
100
+ .run();
101
+ return toolsHash;
102
+ }
103
+
104
+ /**
105
+ * The surface the conversation's most recent live turn sent, or `null` when
106
+ * no turn has recorded one (or the stored JSON is unreadable).
107
+ */
108
+ export function getConversationToolSurface(
109
+ conversationId: string,
110
+ ): ConversationToolSurface | null {
111
+ const row = getDb()
112
+ .select({
113
+ toolsJson: conversationToolSurfaces.toolsJson,
114
+ delegateIndependentTasks:
115
+ conversationToolSurfaces.delegateIndependentTasks,
116
+ })
117
+ .from(conversationToolSurfaces)
118
+ .where(eq(conversationToolSurfaces.conversationId, conversationId))
119
+ .get();
120
+ if (!row) {
121
+ return null;
122
+ }
123
+ try {
124
+ const parsed: unknown = JSON.parse(row.toolsJson);
125
+ if (!Array.isArray(parsed)) {
126
+ return null;
127
+ }
128
+ return {
129
+ tools: parsed as ToolDefinition[],
130
+ delegateIndependentTasks: row.delegateIndependentTasks ?? null,
131
+ };
132
+ } catch {
133
+ return null;
134
+ }
135
+ }