@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,161 @@
1
+ /**
2
+ * Tests for `memory-run-evidence.ts`: the readers of what a background
3
+ * memory run durably produced, shared by the retrospective's cursor advance
4
+ * and consolidation's buffer consumption.
5
+ */
6
+
7
+ import { describe, expect, test } from "bun:test";
8
+
9
+ import {
10
+ collectSuccessfulToolResultIds,
11
+ countDurableToolUses,
12
+ endsWithTextReply,
13
+ extractRememberContents,
14
+ hasCommittedTextReply,
15
+ type MessageLike,
16
+ } from "../memory-run-evidence.js";
17
+
18
+ const DURABLE = new Set(["file_write", "remember"]);
19
+
20
+ /**
21
+ * Persisted message rows carry their blocks as a JSON string; the readers
22
+ * parse it. Rows are built that way here so the test exercises the same
23
+ * shape the jobs read.
24
+ */
25
+ function row(role: string, blocks: unknown[]): MessageLike {
26
+ return { role, content: JSON.stringify(blocks) };
27
+ }
28
+ const use = (id: string, name: string, input: unknown = {}) => ({
29
+ type: "tool_use",
30
+ id,
31
+ name,
32
+ input,
33
+ });
34
+ const result = (id: string, isError = false) => ({
35
+ type: "tool_result",
36
+ tool_use_id: id,
37
+ is_error: isError,
38
+ content: "…",
39
+ });
40
+ const text = (value: string) => ({ type: "text", text: value });
41
+
42
+ describe("collectSuccessfulToolResultIds", () => {
43
+ test("collects non-error tool_result ids from user rows only, tolerating malformed rows", () => {
44
+ const ids = collectSuccessfulToolResultIds([
45
+ row("user", [result("ok"), result("bad", true)]),
46
+ row("assistant", [result("not-a-user-row")]),
47
+ { role: "user", content: "{not json" },
48
+ row("user", [result("second")]),
49
+ ]);
50
+ expect([...ids].sort()).toEqual(["ok", "second"]);
51
+ });
52
+ });
53
+
54
+ describe("countDurableToolUses", () => {
55
+ const messages = [
56
+ row("assistant", [
57
+ use("a", "file_write"),
58
+ use("b", "file_write"),
59
+ use("c", "file_read"),
60
+ ]),
61
+ row("user", [result("a"), result("b", true), result("c")]),
62
+ ];
63
+
64
+ test("counts only the named tools, and with a success set only verified executions", () => {
65
+ expect(countDurableToolUses(messages, DURABLE, null)).toBe(2);
66
+ expect(
67
+ countDurableToolUses(
68
+ messages,
69
+ DURABLE,
70
+ collectSuccessfulToolResultIds(messages),
71
+ ),
72
+ ).toBe(1);
73
+ expect(countDurableToolUses(messages, new Set(["file_read"]), null)).toBe(
74
+ 1,
75
+ );
76
+ });
77
+ });
78
+
79
+ describe("hasCommittedTextReply", () => {
80
+ test("true only when the LAST assistant row carries non-blank text", () => {
81
+ expect(
82
+ hasCommittedTextReply([
83
+ row("assistant", [text("narrating")]),
84
+ row("assistant", [text(" ")]),
85
+ ]),
86
+ ).toBe(false);
87
+ expect(
88
+ hasCommittedTextReply([
89
+ row("assistant", [use("a", "file_write")]),
90
+ row("user", [result("a")]),
91
+ row("assistant", [text("Done.")]),
92
+ ]),
93
+ ).toBe(true);
94
+ expect(hasCommittedTextReply([{ role: "assistant", content: "{" }])).toBe(
95
+ false,
96
+ );
97
+ });
98
+ });
99
+
100
+ describe("endsWithTextReply", () => {
101
+ test("true only when the final row is an assistant reply with text and no tool call", () => {
102
+ expect(
103
+ endsWithTextReply([
104
+ row("assistant", [use("a", "file_write")]),
105
+ row("user", [result("a")]),
106
+ row("assistant", [text("Filed it.")]),
107
+ ]),
108
+ ).toBe(true);
109
+ // Narration on the row that also calls a tool, then a tool result: the
110
+ // run stopped mid-loop, whatever the narration said.
111
+ expect(
112
+ endsWithTextReply([
113
+ row("assistant", [
114
+ text("Fixing that page now."),
115
+ use("a", "file_write"),
116
+ ]),
117
+ row("user", [result("a")]),
118
+ ]),
119
+ ).toBe(false);
120
+ expect(
121
+ endsWithTextReply([
122
+ row("assistant", [text("Done."), use("b", "file_read")]),
123
+ ]),
124
+ ).toBe(false);
125
+ expect(endsWithTextReply([row("assistant", [text(" ")])])).toBe(false);
126
+ expect(endsWithTextReply([{ role: "assistant", content: "{" }])).toBe(
127
+ false,
128
+ );
129
+ expect(endsWithTextReply([])).toBe(false);
130
+ });
131
+ });
132
+
133
+ describe("extractRememberContents", () => {
134
+ const messages = [
135
+ row("assistant", [
136
+ use("a", "remember", { content: " one " }),
137
+ use("b", "remember", { content: ["two", "", "three"] }),
138
+ use("c", "remember", { content: "failed" }),
139
+ use("d", "file_write", { content: "not a remember" }),
140
+ ]),
141
+ row("user", [result("a"), result("b"), result("c", true)]),
142
+ ];
143
+
144
+ test("flattens batched facts, trims, and drops blanks", () => {
145
+ expect(extractRememberContents(messages)).toEqual([
146
+ "one",
147
+ "two",
148
+ "three",
149
+ "failed",
150
+ ]);
151
+ });
152
+
153
+ test("with a success set, a failed remember's facts are excluded", () => {
154
+ expect(
155
+ extractRememberContents(
156
+ messages,
157
+ collectSuccessfulToolResultIds(messages),
158
+ ),
159
+ ).toEqual(["one", "two", "three"]);
160
+ });
161
+ });
@@ -52,6 +52,16 @@ export function seedRelocatedMemoryRow(
52
52
  )
53
53
  .run(conversationId, now);
54
54
  return;
55
+ case "memory_v3_pool_inputs":
56
+ raw
57
+ .query(
58
+ `INSERT INTO memory_v3_pool_inputs
59
+ (conversation_id, turn, created_at, recent_context, current_message,
60
+ candidate_text_hashes_json)
61
+ VALUES (?, 1, ?, '', '', '[]')`,
62
+ )
63
+ .run(conversationId, now);
64
+ return;
55
65
  case "activation_sessions":
56
66
  raw
57
67
  .query(
@@ -231,18 +231,26 @@ describe("spawnMemoryWorkerProcess", () => {
231
231
  }
232
232
  });
233
233
 
234
- test("reuses an already-running worker without spawning", async () => {
235
- // A live PID file (this test process) makes the probe report running.
234
+ test("spawns when the PID file names an unrelated live process", async () => {
236
235
  writeFileSync(pidPath, String(process.pid));
237
236
  let spawned = false;
238
237
  const restore = stubBunSpawn(() => {
239
238
  spawned = true;
240
- return { unref: () => {}, kill: () => {}, pid: 1, exited: neverExits() };
239
+ writeFileSync(pidPath, "4242");
240
+ return {
241
+ unref: () => {},
242
+ kill: () => {},
243
+ pid: 4242,
244
+ exited: neverExits(),
245
+ };
241
246
  });
242
247
  try {
243
- const result = await spawnMemoryWorkerProcess({ pidWaitTimeoutMs: 100 });
244
- expect(result).toEqual({ pid: process.pid, alreadyRunning: true });
245
- expect(spawned).toBe(false);
248
+ const result = await spawnMemoryWorkerProcess({
249
+ pidWaitTimeoutMs: 1_000,
250
+ pidPollIntervalMs: 10,
251
+ });
252
+ expect(result).toEqual({ pid: 4242, alreadyRunning: false });
253
+ expect(spawned).toBe(true);
246
254
  } finally {
247
255
  restore();
248
256
  }
@@ -250,6 +258,11 @@ describe("spawnMemoryWorkerProcess", () => {
250
258
  });
251
259
 
252
260
  describe("probeMemoryWorker", () => {
261
+ test("reports not_running when the PID file names a live process that is not this worker", () => {
262
+ writeFileSync(pidPath, String(process.pid));
263
+ expect(probeMemoryWorker()).toEqual({ status: "not_running" });
264
+ });
265
+
253
266
  test("reports running (not throws) when the process exists but is not signalable (EPERM)", () => {
254
267
  writeFileSync(pidPath, "4321");
255
268
  const restore = stubProcessKill(new Set(), new Set([4321]));
@@ -0,0 +1,354 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Memory buffer file: the two writers of `memory/buffer.md`
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // `memory/buffer.md` has exactly two writers, and both live here so the
6
+ // protocol between them has one home. `remember()` and the sweep job APPEND
7
+ // entries through `appendBufferAndArchive`. The consolidation job CONSUMES
8
+ // the entries it handed to a run through `consumeBufferEntries`, removing
9
+ // exactly those entries and nothing else. Everything else in the plugin
10
+ // reads the file. The entry format itself is owned by `buffer-format.ts`.
11
+ //
12
+ // The writers run in different processes: user turns append from the
13
+ // daemon, while consolidation (and its consume) runs in the memory jobs
14
+ // worker, and the sweep appends from the worker too. No in-process lock can
15
+ // order them, and the buffer must never be rewritten from a stale read: an
16
+ // entry appended between a reader's read and its write would be destroyed
17
+ // without ever being filed. The consumer therefore never trusts a read for
18
+ // longer than one synchronous stretch and never lets an append land where
19
+ // it cannot see it:
20
+ //
21
+ // 1. Open the file and keep the descriptor: it pins the inode the path
22
+ // names at that moment (call it O).
23
+ // 2. Read O through that descriptor, remove the consumed entries from what
24
+ // was read, write the remainder to a sibling temp file, and rename it
25
+ // over the path. Steps 1 and 2 run synchronously, with no await, so
26
+ // nothing in this process interleaves. From the rename on, the path
27
+ // names a new inode (N) and every appender that opens the path lands
28
+ // on N, where nothing is ever rewritten.
29
+ // 3. Drain: an appender that opened O before the rename still writes to O,
30
+ // which the held descriptor keeps alive. Compare O's size against the
31
+ // bytes read; copy anything beyond them onto the path (an append to N,
32
+ // the same operation the appenders use). Drain once immediately, then
33
+ // once more after a short grace window, and only then close O.
34
+ //
35
+ // What can still be lost: an appender whose `open` preceded the rename and
36
+ // whose `write` lands after the final drain. Both calls sit inside one
37
+ // synchronous `appendFileSync`, so that needs the appending process to be
38
+ // stopped between two adjacent syscalls for longer than the grace window (a
39
+ // debugger, SIGSTOP, or a multi-second scheduler stall). Machine sleep
40
+ // freezes both processes together and does not count. The other way out is
41
+ // the drain's own copy failing (disk full, an I/O error) on every retry;
42
+ // the descriptor cannot be held forever, so those bytes are then gone from
43
+ // the buffer and reported as unrecovered, and the entries survive only in
44
+ // the daily archive the same append wrote. Nothing after the rename throws:
45
+ // once the rename has committed the pass is consumed, and the result says
46
+ // so. If either residual ever proves reachable, the escalation is a
47
+ // short-held `wx` lock file taken by both writers around their synchronous
48
+ // critical sections (the idiom `substrate/consolidation-lock.ts` uses);
49
+ // the consume shape above does not change, only its critical section gains
50
+ // a guard.
51
+ //
52
+ // Ordering: consumption removes entries and copies the rest verbatim, so
53
+ // the file stays in append order except for a drained late append, which
54
+ // lands after any entry appended to N in the meantime. Readers only rely
55
+ // on the tail being recent, never on strict order, so that is harmless.
56
+ // The same holds if a late append's bytes were split across the two
57
+ // drains (a partial `write()` on a regular file, well below the residual
58
+ // above): the halves land in order on N, possibly with another appender's
59
+ // entry between them, so the entry is split rather than lost, and the
60
+ // next pass's snapshot selection treats an unterminated tail as
61
+ // in-flight.
62
+
63
+ import {
64
+ appendFileSync,
65
+ closeSync,
66
+ existsSync,
67
+ fstatSync,
68
+ mkdirSync,
69
+ openSync,
70
+ readFileSync,
71
+ readSync,
72
+ renameSync,
73
+ unlinkSync,
74
+ writeFileSync,
75
+ writeSync,
76
+ } from "node:fs";
77
+ import { dirname, join } from "node:path";
78
+
79
+ import {
80
+ type BufferEntryLines,
81
+ bufferEntryText,
82
+ joinBufferEntries,
83
+ splitBufferContent,
84
+ } from "./buffer-format.js";
85
+ import { getLogger } from "./logging.js";
86
+
87
+ const log = getLogger("memory-buffer-file");
88
+
89
+ /**
90
+ * How long the consumer keeps the replaced inode open after the rename
91
+ * before its final drain. Only an appender stalled between its `open` and
92
+ * its `write` for longer than this can lose an entry; a healthy appender
93
+ * completes both within microseconds.
94
+ */
95
+ const LATE_APPEND_GRACE_MS = 500;
96
+
97
+ /** Attempts to copy late-appended bytes back before giving them up. */
98
+ const LATE_APPEND_COPY_ATTEMPTS = 3;
99
+ /** Wait between those attempts; disk pressure and I/O errors are often brief. */
100
+ const LATE_APPEND_COPY_RETRY_MS = 200;
101
+
102
+ /**
103
+ * Append `entry` to `<rootDir>/buffer.md` and `<rootDir>/archive/<today>.md`,
104
+ * creating the archive directory and seeding the archive header if missing.
105
+ *
106
+ * Returns the absolute paths of both files so callers can fan out follow-up
107
+ * work.
108
+ *
109
+ * Shared by `remember()` and the background jobs (`sweep`, future LLM-driven
110
+ * extractors) so every appender writes exactly the same format and
111
+ * downstream consumers (consolidation, search) cannot tell them apart.
112
+ */
113
+ export function appendBufferAndArchive(args: {
114
+ rootDir: string;
115
+ entry: string;
116
+ now: Date;
117
+ }): { bufferPath: string; archivePath: string } {
118
+ const { rootDir, entry, now } = args;
119
+ const archiveDir = join(rootDir, "archive");
120
+ mkdirSync(archiveDir, { recursive: true });
121
+
122
+ const bufferPath = join(rootDir, "buffer.md");
123
+ appendFileSync(bufferPath, entry, "utf-8");
124
+
125
+ const yyyy = now.getFullYear();
126
+ const mm = String(now.getMonth() + 1).padStart(2, "0");
127
+ const dd = String(now.getDate()).padStart(2, "0");
128
+ const archivePath = join(archiveDir, `${yyyy}-${mm}-${dd}.md`);
129
+ if (!existsSync(archivePath)) {
130
+ const month = now.toLocaleString("en-US", { month: "short" });
131
+ appendFileSync(
132
+ archivePath,
133
+ `# ${month} ${now.getDate()}, ${yyyy}\n\n`,
134
+ "utf-8",
135
+ );
136
+ }
137
+ appendFileSync(archivePath, entry, "utf-8");
138
+
139
+ return { bufferPath, archivePath };
140
+ }
141
+
142
+ export interface ConsumeBufferEntriesResult {
143
+ /** Consumed entries found in the live file and removed. */
144
+ removed: number;
145
+ /**
146
+ * Consumed entries not present in the live file. Something other than an
147
+ * appender rewrote the file during the run; the caller decides whether
148
+ * that is worth a warning.
149
+ */
150
+ alreadyAbsent: number;
151
+ /** Bytes appended to the replaced inode after the read and copied back. */
152
+ lateAppendBytesRecovered: number;
153
+ /**
154
+ * Bytes appended to the replaced inode that could not be copied back
155
+ * after every retry. The pass is consumed regardless (the rename had
156
+ * committed); these entries remain only in the daily archive.
157
+ */
158
+ unrecoveredLateAppendBytes: number;
159
+ /**
160
+ * The replaced inode could not be inspected or read after the rename, so
161
+ * any append that landed on it is unaccounted for (not even counted in
162
+ * `unrecoveredLateAppendBytes`). The pass is consumed regardless.
163
+ */
164
+ lateAppendDrainFailed: boolean;
165
+ }
166
+
167
+ /**
168
+ * Remove `consumed` from `bufferPath`, leaving every other entry in place.
169
+ * Never throws once the rename has committed; see the result's
170
+ * `unrecoveredLateAppendBytes`.
171
+ *
172
+ * Each consumed entry is matched by its exact text ({@link bufferEntryText})
173
+ * against the live file, first occurrence, once per consumed entry, so an
174
+ * identical fact appended during the run survives when the snapshot held
175
+ * one copy. An entry that is absent from the live file is counted, never
176
+ * searched for elsewhere. A missing file consumes nothing.
177
+ *
178
+ * The critical section (read through a pinned descriptor, rewrite via temp
179
+ * file + rename) is synchronous; the drain of late appends to the replaced
180
+ * inode follows, with a second drain after `lateAppendGraceMs`. See the
181
+ * module header for why this is lossless and what the residual is.
182
+ *
183
+ * I/O failures other than a missing file throw: the caller (the
184
+ * consolidation job) treats a failed consume as no progress and leaves the
185
+ * buffer for the next pass rather than guessing at its state.
186
+ */
187
+ export async function consumeBufferEntries(
188
+ bufferPath: string,
189
+ consumed: readonly BufferEntryLines[],
190
+ options: { lateAppendGraceMs?: number } = {},
191
+ ): Promise<ConsumeBufferEntriesResult> {
192
+ const graceMs = options.lateAppendGraceMs ?? LATE_APPEND_GRACE_MS;
193
+ const pending = consumed.map(bufferEntryText);
194
+
195
+ let fd: number;
196
+ try {
197
+ fd = openSync(bufferPath, "r");
198
+ } catch (err) {
199
+ if ((err as NodeJS.ErrnoException).code === "ENOENT") {
200
+ return {
201
+ removed: 0,
202
+ alreadyAbsent: pending.length,
203
+ lateAppendBytesRecovered: 0,
204
+ unrecoveredLateAppendBytes: 0,
205
+ lateAppendDrainFailed: false,
206
+ };
207
+ }
208
+ throw err;
209
+ }
210
+
211
+ try {
212
+ // Synchronous critical section: nothing in this process runs between
213
+ // the read and the rename.
214
+ const before = readFileSync(fd);
215
+ let drainedTo = before.length;
216
+ const live = splitBufferContent(before.toString("utf-8"));
217
+ const remaining: BufferEntryLines[] = [];
218
+ let removed = 0;
219
+ for (const entry of live) {
220
+ const index = pending.indexOf(bufferEntryText(entry));
221
+ if (index === -1) {
222
+ remaining.push(entry);
223
+ continue;
224
+ }
225
+ pending.splice(index, 1);
226
+ removed += 1;
227
+ }
228
+ const tmpPath = join(
229
+ dirname(bufferPath),
230
+ `.buffer.md.${process.pid}.${Date.now()}.tmp`,
231
+ );
232
+ writeFileSync(tmpPath, joinBufferEntries(remaining), "utf-8");
233
+ try {
234
+ renameSync(tmpPath, bufferPath);
235
+ } catch (err) {
236
+ unlinkSafely(tmpPath);
237
+ throw err;
238
+ }
239
+
240
+ // Drain: appends that landed on the replaced inode after the read. The
241
+ // rename has committed, so from here nothing throws: a copy that fails
242
+ // is retried, bytes that cannot be copied are reported, and a replaced
243
+ // inode that cannot even be read is reported, all without raising.
244
+ let lateAppendBytesRecovered = 0;
245
+ let unrecoveredLateAppendBytes = 0;
246
+ let lateAppendDrainFailed = false;
247
+ // Copies through an explicit write loop so a retry resumes from the
248
+ // first unwritten byte: an append that wrote part of the bytes before
249
+ // failing (disk pressure) must not have its prefix appended twice.
250
+ const copyBack = async (bytes: Buffer): Promise<void> => {
251
+ let written = 0;
252
+ for (let attempt = 1; ; attempt++) {
253
+ try {
254
+ const out = openSync(bufferPath, "a");
255
+ try {
256
+ while (written < bytes.length) {
257
+ const n = writeSync(out, bytes, written, bytes.length - written);
258
+ if (n <= 0) {
259
+ // A regular file never returns a zero-byte write without an
260
+ // error, but a spin here would wedge the worker with the
261
+ // consolidation lock held; treat it as a failed attempt.
262
+ throw new Error("writeSync made no progress");
263
+ }
264
+ written += n;
265
+ }
266
+ } finally {
267
+ closeSync(out);
268
+ }
269
+ lateAppendBytesRecovered += bytes.length;
270
+ return;
271
+ } catch (err) {
272
+ if (attempt >= LATE_APPEND_COPY_ATTEMPTS) {
273
+ log.error(
274
+ { err, bufferPath, bytes: bytes.length, written, attempt },
275
+ "buffer consume: could not copy entries appended during the rewrite back into the buffer; giving up the rest",
276
+ );
277
+ lateAppendBytesRecovered += written;
278
+ unrecoveredLateAppendBytes += bytes.length - written;
279
+ return;
280
+ }
281
+ log.warn(
282
+ { err, bufferPath, bytes: bytes.length, written, attempt },
283
+ "buffer consume: copying late-appended entries failed; retrying from the first unwritten byte",
284
+ );
285
+ await new Promise((resolve) =>
286
+ setTimeout(resolve, LATE_APPEND_COPY_RETRY_MS),
287
+ );
288
+ }
289
+ }
290
+ };
291
+ const drain = async (): Promise<void> => {
292
+ let late: Buffer;
293
+ try {
294
+ const size = fstatSync(fd).size;
295
+ if (size <= drainedTo) {
296
+ return;
297
+ }
298
+ late = Buffer.alloc(size - drainedTo);
299
+ const read = readSync(fd, late, 0, late.length, drainedTo);
300
+ late = late.subarray(0, read);
301
+ drainedTo += read;
302
+ } catch (err) {
303
+ log.error(
304
+ { err, bufferPath },
305
+ "buffer consume: could not read the replaced inode for entries appended during the rewrite",
306
+ );
307
+ lateAppendDrainFailed = true;
308
+ return;
309
+ }
310
+ await copyBack(late);
311
+ };
312
+ await drain();
313
+ if (graceMs > 0) {
314
+ await new Promise((resolve) => setTimeout(resolve, graceMs));
315
+ }
316
+ if (!lateAppendDrainFailed) {
317
+ await drain();
318
+ }
319
+ if (lateAppendBytesRecovered > 0) {
320
+ log.info(
321
+ { bufferPath, lateAppendBytesRecovered },
322
+ "buffer consume: recovered entries appended during the rewrite",
323
+ );
324
+ }
325
+
326
+ return {
327
+ removed,
328
+ alreadyAbsent: pending.length,
329
+ lateAppendBytesRecovered,
330
+ unrecoveredLateAppendBytes,
331
+ lateAppendDrainFailed,
332
+ };
333
+ } finally {
334
+ // After the rename, a failing close must not surface as a failure of
335
+ // the consume: the pass is consumed and the drain has reported. Before
336
+ // the rename, the original error is already propagating.
337
+ try {
338
+ closeSync(fd);
339
+ } catch (err) {
340
+ log.error(
341
+ { err, bufferPath },
342
+ "buffer consume: closing the replaced buffer inode failed",
343
+ );
344
+ }
345
+ }
346
+ }
347
+
348
+ function unlinkSafely(path: string): void {
349
+ try {
350
+ unlinkSync(path);
351
+ } catch {
352
+ // best-effort cleanup of a temp file the rename never claimed
353
+ }
354
+ }
@@ -154,6 +154,46 @@ export function splitBufferEntries(
154
154
  return groups;
155
155
  }
156
156
 
157
+ /**
158
+ * Split a whole buffer FILE into entries. The file is newline-terminated
159
+ * (every append ends in `\n`), so the terminator ends the last line rather
160
+ * than opening an empty one: an entry's lines are the same whether it is
161
+ * currently last in the file or has since been followed by more entries.
162
+ * That stability is what lets a consumer match an entry it snapshotted
163
+ * earlier against the live file by exact text.
164
+ */
165
+ export function splitBufferContent(content: string): BufferEntryLines[] {
166
+ if (content.length === 0) {
167
+ return [];
168
+ }
169
+ const lines = content.split("\n");
170
+ if (lines[lines.length - 1] === "") {
171
+ lines.pop();
172
+ }
173
+ return splitBufferEntries(lines);
174
+ }
175
+
176
+ /**
177
+ * One entry's verbatim text: its lines joined, without a terminating
178
+ * newline. The identity a consumer matches on.
179
+ */
180
+ export function bufferEntryText(entry: BufferEntryLines): string {
181
+ return entry.lines.join("\n");
182
+ }
183
+
184
+ /**
185
+ * Inverse of {@link splitBufferContent}: entries back to newline-terminated
186
+ * file content, or the empty string when there are none.
187
+ */
188
+ export function joinBufferEntries(
189
+ entries: readonly BufferEntryLines[],
190
+ ): string {
191
+ if (entries.length === 0) {
192
+ return "";
193
+ }
194
+ return `${entries.map(bufferEntryText).join("\n")}\n`;
195
+ }
196
+
157
197
  /** One entry's verbatim lines, as returned by {@link splitBufferEntries}. */
158
198
  export interface BufferEntryLines {
159
199
  /** `null` for the headless group before the first entry opening. */
@@ -1,6 +1,10 @@
1
+ import {
2
+ type RecallSource,
3
+ RecallSourceSchema,
4
+ } from "../../../../api/events/tool-result.js";
1
5
  import { truncate } from "../host-utils.js";
2
- import { ALL_RECALL_SOURCES, normalizeRecallSources } from "./limits.js";
3
- import type { RecallEvidence, RecallSource } from "./types.js";
6
+ import { normalizeRecallSources } from "./limits.js";
7
+ import type { RecallEvidence } from "./types.js";
4
8
 
5
9
  export type RecallAgentConfidence = "high" | "medium" | "low";
6
10
 
@@ -76,7 +80,7 @@ export const SEARCH_SOURCES_TOOL_DEFINITION: RecallAgentToolDefinition = {
76
80
  sources: {
77
81
  type: "array",
78
82
  description: "Optional subset of internal sources to search.",
79
- items: { type: "string", enum: [...ALL_RECALL_SOURCES] },
83
+ items: { type: "string", enum: [...RecallSourceSchema.options] },
80
84
  uniqueItems: true,
81
85
  },
82
86
  limit: {
@@ -176,9 +180,9 @@ export function buildRecallAgentPromptBundle(
176
180
  ): RecallAgentPromptBundle {
177
181
  const availableSources = normalizeRecallSources(options.availableSources);
178
182
  const maxSearchCalls = options.maxSearchCalls ?? DEFAULT_MAX_SEARCH_CALLS;
179
- const evidence = prepareRecallAgentPromptEvidence(
183
+ const evidence = truncateRecallEvidenceToBudget(
180
184
  options.evidence,
181
- options.evidenceBudgetChars,
185
+ options.evidenceBudgetChars ?? DEFAULT_RECALL_AGENT_EVIDENCE_BUDGET_CHARS,
182
186
  );
183
187
  const citationIds = evidence.map((item) => item.id);
184
188
 
@@ -216,13 +220,6 @@ export function buildRecallAgentPromptBundle(
216
220
  return { prompt, evidence };
217
221
  }
218
222
 
219
- function prepareRecallAgentPromptEvidence(
220
- evidence: readonly RecallEvidence[],
221
- evidenceBudgetChars = DEFAULT_RECALL_AGENT_EVIDENCE_BUDGET_CHARS,
222
- ): RecallEvidence[] {
223
- return truncateRecallEvidenceToBudget(evidence, evidenceBudgetChars);
224
- }
225
-
226
223
  export function truncateRecallEvidenceToBudget(
227
224
  evidence: readonly RecallEvidence[],
228
225
  maxTextChars: number,