@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
@@ -1,8 +1,8 @@
1
- import { getConfig } from "../../config/loader.js";
2
1
  import type {
3
2
  WebSearchMetadata,
4
3
  WebSearchResultItem,
5
- } from "../../daemon/message-types/web-activity.js";
4
+ } from "../../api/events/tool-result.js";
5
+ import { getConfig } from "../../config/loader.js";
6
6
  import { RiskLevel } from "../../permissions/types.js";
7
7
  import { getProviderKeyAsync } from "../../security/secure-keys.js";
8
8
  import { wrapUntrustedContent } from "../../security/untrusted-content.js";
@@ -44,6 +44,7 @@ const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
44
44
  const TAVILY_API_URL = "https://api.tavily.com/search";
45
45
  const FIRECRAWL_API_URL = "https://api.firecrawl.dev/v2/search";
46
46
  const FASTCRW_SEARCH_PATH = "/v1/search";
47
+ const TINYFISH_DEFAULT_SEARCH_API_BASE = "https://api.search.tinyfish.ai";
47
48
  // Keenable is keyless by default: the public path needs no key (rate-limited);
48
49
  // a key switches to the authenticated path and lifts the cap.
49
50
  const KEENABLE_API_BASE_URL = "https://api.keenable.ai";
@@ -56,7 +57,9 @@ type WebSearchProvider =
56
57
  | "tavily"
57
58
  | "firecrawl"
58
59
  | "keenable"
59
- | "fastcrw";
60
+ | "fastcrw"
61
+ | "searxng"
62
+ | "tinyfish";
60
63
 
61
64
  /**
62
65
  * Arguments passed to every {@link WebSearchAdapter}. The full superset is
@@ -167,6 +170,38 @@ interface KeenableSearchResponse {
167
170
  results?: KeenableSearchResult[];
168
171
  }
169
172
 
173
+ interface SearxngSearchResult {
174
+ title?: string;
175
+ url?: string;
176
+ content?: string;
177
+ }
178
+
179
+ interface SearxngSearchResponse {
180
+ query?: string;
181
+ results?: SearxngSearchResult[];
182
+ }
183
+
184
+ interface TinyfishSearchResult {
185
+ position?: number;
186
+ site_name?: string;
187
+ title?: string;
188
+ snippet?: string;
189
+ url?: string;
190
+ date?: string;
191
+ }
192
+
193
+ interface TinyfishSearchResponse {
194
+ query?: string;
195
+ results?: TinyfishSearchResult[];
196
+ total_results?: number;
197
+ page?: number;
198
+ }
199
+
200
+ const SEARXNG_MISSING_INSTANCE_MESSAGE =
201
+ "SearXNG needs an instance URL. Set API Base in Settings under Web Search.";
202
+ const SEARXNG_JSON_DISABLED_MESSAGE =
203
+ "This SearXNG instance did not return JSON. Enable the JSON format on the instance, or point API Base at an instance that allows it.";
204
+
170
205
  function getWebSearchProvider(): WebSearchProvider {
171
206
  const config = getConfig();
172
207
  const configured = config.services["web-search"].provider ?? "perplexity";
@@ -573,6 +608,159 @@ function buildKeenableMetadata(
573
608
  };
574
609
  }
575
610
 
611
+ function formatSearxngResults(
612
+ data: SearxngSearchResponse,
613
+ query: string,
614
+ ): string {
615
+ const results = data.results ?? [];
616
+ if (results.length === 0) {
617
+ return `No results found for "${query}".`;
618
+ }
619
+
620
+ const lines: string[] = [`Web search results for "${query}":\n`];
621
+ for (let i = 0; i < results.length; i++) {
622
+ const r = results[i];
623
+ const title = r.title?.trim() || r.url?.trim() || "Untitled result";
624
+ lines.push(`${i + 1}. ${title}`);
625
+ if (r.url) {
626
+ lines.push(` URL: ${r.url}`);
627
+ }
628
+ if (r.content) {
629
+ lines.push(` ${r.content}`);
630
+ }
631
+ lines.push("");
632
+ }
633
+ return lines.join("\n");
634
+ }
635
+
636
+ function buildSearxngMetadata(
637
+ data: SearxngSearchResponse,
638
+ query: string,
639
+ durationMs: number,
640
+ ): WebSearchMetadata {
641
+ const results = data.results ?? [];
642
+ const items: WebSearchResultItem[] = results.map((r, i) => {
643
+ const url = r.url ?? "";
644
+ const domain = extractDomain(url);
645
+ return {
646
+ rank: i + 1,
647
+ title: r.title?.trim() || url.trim() || "Untitled result",
648
+ url,
649
+ domain,
650
+ faviconUrl: faviconUrlForDomain(domain),
651
+ snippet: r.content?.trim() || undefined,
652
+ };
653
+ });
654
+ return {
655
+ query,
656
+ provider: "searxng",
657
+ resultCount: items.length,
658
+ durationMs,
659
+ results: items,
660
+ };
661
+ }
662
+
663
+ function formatTinyfishResults(
664
+ data: TinyfishSearchResponse,
665
+ query: string,
666
+ ): string {
667
+ const results = data.results ?? [];
668
+ if (results.length === 0) {
669
+ return `No results found for "${query}".`;
670
+ }
671
+
672
+ const lines: string[] = [`Web search results for "${query}":\n`];
673
+ for (let i = 0; i < results.length; i++) {
674
+ const result = results[i];
675
+ const title =
676
+ result.title?.trim() || result.url?.trim() || "Untitled result";
677
+ lines.push(`${i + 1}. ${title}`);
678
+ if (result.url) {
679
+ lines.push(` URL: ${result.url}`);
680
+ }
681
+ if (result.snippet) {
682
+ lines.push(` ${result.snippet}`);
683
+ }
684
+ if (result.date) {
685
+ lines.push(` Published: ${result.date}`);
686
+ }
687
+ lines.push("");
688
+ }
689
+ return lines.join("\n");
690
+ }
691
+
692
+ function buildTinyfishMetadata(
693
+ data: TinyfishSearchResponse,
694
+ query: string,
695
+ durationMs: number,
696
+ ): WebSearchMetadata {
697
+ const results = data.results ?? [];
698
+ const items: WebSearchResultItem[] = results.map((result, index) => {
699
+ const url = result.url ?? "";
700
+ const domain = extractDomain(url);
701
+ return {
702
+ rank: index + 1,
703
+ title: result.title?.trim() || url.trim() || "Untitled result",
704
+ url,
705
+ domain,
706
+ faviconUrl: faviconUrlForDomain(domain),
707
+ snippet: result.snippet?.trim() || undefined,
708
+ };
709
+ });
710
+ return {
711
+ query,
712
+ provider: "tinyfish",
713
+ resultCount: items.length,
714
+ durationMs,
715
+ results: items,
716
+ };
717
+ }
718
+
719
+ function tinyfishRecencyMinutesForFreshness(
720
+ freshness: string | undefined,
721
+ ): number | undefined {
722
+ switch (freshness) {
723
+ case "pd":
724
+ return 24 * 60;
725
+ case "pw":
726
+ return 7 * 24 * 60;
727
+ case "pm":
728
+ return 30 * 24 * 60;
729
+ case "py":
730
+ return 365 * 24 * 60;
731
+ default:
732
+ return undefined;
733
+ }
734
+ }
735
+
736
+ /**
737
+ * Map the tool's `freshness` window onto SearXNG's `time_range`
738
+ * (`day` / `month` / `year`). SearXNG has no week filter, so `pw` is omitted.
739
+ */
740
+ function searxngTimeRangeForFreshness(
741
+ freshness: string | undefined,
742
+ ): "day" | "month" | "year" | undefined {
743
+ switch (freshness) {
744
+ case "pd":
745
+ return "day";
746
+ case "pm":
747
+ return "month";
748
+ case "py":
749
+ return "year";
750
+ default:
751
+ return undefined;
752
+ }
753
+ }
754
+
755
+ function isNonJsonSearchBody(contentType: string, bodyText: string): boolean {
756
+ const type = contentType.toLowerCase();
757
+ if (type.includes("text/html") || type.includes("application/xhtml")) {
758
+ return true;
759
+ }
760
+ const trimmed = bodyText.trimStart();
761
+ return trimmed.startsWith("<");
762
+ }
763
+
576
764
  /**
577
765
  * Map the tool's `freshness` window onto a Keenable `published_after` date
578
766
  * (YYYY-MM-DD). Keenable filters by absolute publication date rather than a
@@ -1358,6 +1546,261 @@ async function executeKeenableSearch(
1358
1546
  );
1359
1547
  }
1360
1548
 
1549
+ async function executeSearxngSearch(
1550
+ query: string,
1551
+ count: number,
1552
+ freshness: string | undefined,
1553
+ apiKey: string,
1554
+ signal?: AbortSignal,
1555
+ ): Promise<ToolExecutionResult> {
1556
+ const startedAt = Date.now();
1557
+ const apiBase = getConfig().services["web-search"]?.apiBase?.trim() ?? "";
1558
+ if (apiBase.length === 0) {
1559
+ return errorResult(
1560
+ query,
1561
+ "searxng",
1562
+ startedAt,
1563
+ SEARXNG_MISSING_INSTANCE_MESSAGE,
1564
+ );
1565
+ }
1566
+
1567
+ const params = new URLSearchParams({
1568
+ q: query,
1569
+ format: "json",
1570
+ });
1571
+ const timeRange = searxngTimeRangeForFreshness(freshness);
1572
+ if (timeRange) {
1573
+ params.set("time_range", timeRange);
1574
+ }
1575
+ const url = `${resolveProviderApiUrl(apiBase, "/search", apiBase)}?${params.toString()}`;
1576
+
1577
+ const headers: Record<string, string> = {
1578
+ Accept: "application/json",
1579
+ };
1580
+ const trimmedKey = apiKey.trim();
1581
+ if (trimmedKey.length > 0) {
1582
+ headers.Authorization = `Bearer ${trimmedKey}`;
1583
+ }
1584
+
1585
+ for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
1586
+ let response: Response;
1587
+ try {
1588
+ response = await fetch(url, {
1589
+ headers,
1590
+ signal,
1591
+ });
1592
+ } catch (err) {
1593
+ return networkFailureResult(query, "searxng", startedAt, err, signal);
1594
+ }
1595
+
1596
+ const bodyText = await response.text();
1597
+ const contentType = response.headers.get("content-type") ?? "";
1598
+ if (isNonJsonSearchBody(contentType, bodyText)) {
1599
+ return errorResult(
1600
+ query,
1601
+ "searxng",
1602
+ startedAt,
1603
+ SEARXNG_JSON_DISABLED_MESSAGE,
1604
+ );
1605
+ }
1606
+
1607
+ if (response.ok) {
1608
+ let data: SearxngSearchResponse;
1609
+ try {
1610
+ data = JSON.parse(bodyText) as SearxngSearchResponse;
1611
+ } catch {
1612
+ return errorResult(
1613
+ query,
1614
+ "searxng",
1615
+ startedAt,
1616
+ SEARXNG_JSON_DISABLED_MESSAGE,
1617
+ );
1618
+ }
1619
+ if (data.results && data.results.length > count) {
1620
+ data.results = data.results.slice(0, count);
1621
+ }
1622
+ const durationMs = Date.now() - startedAt;
1623
+ return {
1624
+ content:
1625
+ wrapUntrustedContent(formatSearxngResults(data, query), {
1626
+ source: "search",
1627
+ sourceDetail: "searxng",
1628
+ }) + CITATION_INSTRUCTION,
1629
+ isError: false,
1630
+ activityMetadata: {
1631
+ webSearch: buildSearxngMetadata(data, query, durationMs),
1632
+ },
1633
+ };
1634
+ }
1635
+
1636
+ if (response.status === 401 || response.status === 403) {
1637
+ return errorResult(
1638
+ query,
1639
+ "searxng",
1640
+ startedAt,
1641
+ "SearXNG rejected the request. Check the instance URL, optional token, and that JSON search is enabled.",
1642
+ );
1643
+ }
1644
+
1645
+ if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
1646
+ const delayMs = getHttpRetryDelay(
1647
+ response,
1648
+ attempt,
1649
+ DEFAULT_BASE_DELAY_MS,
1650
+ );
1651
+ log.warn(
1652
+ { attempt: attempt + 1, delayMs },
1653
+ "SearXNG Search rate limited, retrying",
1654
+ );
1655
+ await sleep(delayMs);
1656
+ continue;
1657
+ }
1658
+
1659
+ log.warn({ status: response.status }, "SearXNG Search API error");
1660
+ return backendFailureResult(
1661
+ query,
1662
+ "searxng",
1663
+ startedAt,
1664
+ { statusCode: response.status, error: rawBodyDetail(bodyText) },
1665
+ response.status === 429
1666
+ ? "SearXNG Search rate limit exceeded after retries. Try again shortly."
1667
+ : `SearXNG Search API returned status ${response.status}`,
1668
+ );
1669
+ }
1670
+
1671
+ return backendFailureResult(
1672
+ query,
1673
+ "searxng",
1674
+ startedAt,
1675
+ { statusCode: 429 },
1676
+ "SearXNG Search rate limit exceeded after retries. Try again shortly.",
1677
+ );
1678
+ }
1679
+
1680
+ async function executeTinyfishSearch(
1681
+ query: string,
1682
+ count: number,
1683
+ freshness: string | undefined,
1684
+ apiKey: string,
1685
+ signal?: AbortSignal,
1686
+ ): Promise<ToolExecutionResult> {
1687
+ const startedAt = Date.now();
1688
+ const apiBase = getConfig().services["web-search"]?.apiBase;
1689
+ const endpoint = resolveProviderApiUrl(
1690
+ apiBase,
1691
+ "/",
1692
+ TINYFISH_DEFAULT_SEARCH_API_BASE,
1693
+ );
1694
+ const url = new URL(endpoint);
1695
+ url.searchParams.set("query", query);
1696
+ const recencyMinutes = tinyfishRecencyMinutesForFreshness(freshness);
1697
+ if (recencyMinutes !== undefined) {
1698
+ url.searchParams.set("recency_minutes", String(recencyMinutes));
1699
+ }
1700
+
1701
+ const headers = {
1702
+ Accept: "application/json",
1703
+ "X-API-Key": apiKey.trim(),
1704
+ };
1705
+
1706
+ for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
1707
+ let response: Response;
1708
+ try {
1709
+ response = await fetch(url.toString(), { headers, signal });
1710
+ } catch (err) {
1711
+ return networkFailureResult(query, "tinyfish", startedAt, err, signal);
1712
+ }
1713
+
1714
+ const bodyText = await response.text();
1715
+ if (response.ok) {
1716
+ let data: TinyfishSearchResponse;
1717
+ try {
1718
+ data = JSON.parse(bodyText) as TinyfishSearchResponse;
1719
+ } catch {
1720
+ return errorResult(
1721
+ query,
1722
+ "tinyfish",
1723
+ startedAt,
1724
+ "TinyFish Search returned an invalid JSON payload.",
1725
+ );
1726
+ }
1727
+ if (data.results && data.results.length > count) {
1728
+ data.results = data.results.slice(0, count);
1729
+ }
1730
+ const durationMs = Date.now() - startedAt;
1731
+ return {
1732
+ content:
1733
+ wrapUntrustedContent(formatTinyfishResults(data, query), {
1734
+ source: "search",
1735
+ sourceDetail: "tinyfish",
1736
+ }) + CITATION_INSTRUCTION,
1737
+ isError: false,
1738
+ activityMetadata: {
1739
+ webSearch: buildTinyfishMetadata(data, query, durationMs),
1740
+ },
1741
+ };
1742
+ }
1743
+
1744
+ if (response.status === 401) {
1745
+ return errorResult(
1746
+ query,
1747
+ "tinyfish",
1748
+ startedAt,
1749
+ "Invalid or expired TinyFish API key",
1750
+ );
1751
+ }
1752
+ if (response.status === 402) {
1753
+ return errorResult(
1754
+ query,
1755
+ "tinyfish",
1756
+ startedAt,
1757
+ "TinyFish Search API access is not enabled for this account.",
1758
+ );
1759
+ }
1760
+ if (response.status === 403) {
1761
+ return errorResult(
1762
+ query,
1763
+ "tinyfish",
1764
+ startedAt,
1765
+ "TinyFish Search request was forbidden by the upstream service.",
1766
+ );
1767
+ }
1768
+
1769
+ if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
1770
+ const delayMs = getHttpRetryDelay(
1771
+ response,
1772
+ attempt,
1773
+ DEFAULT_BASE_DELAY_MS,
1774
+ );
1775
+ log.warn(
1776
+ { attempt: attempt + 1, delayMs },
1777
+ "TinyFish Search rate limited, retrying",
1778
+ );
1779
+ await sleep(delayMs);
1780
+ continue;
1781
+ }
1782
+
1783
+ log.warn({ status: response.status }, "TinyFish Search API error");
1784
+ return backendFailureResult(
1785
+ query,
1786
+ "tinyfish",
1787
+ startedAt,
1788
+ { statusCode: response.status, error: rawBodyDetail(bodyText) },
1789
+ response.status === 429
1790
+ ? "TinyFish Search rate limit exceeded after retries. Try again shortly."
1791
+ : `TinyFish Search API returned status ${response.status}`,
1792
+ );
1793
+ }
1794
+
1795
+ return backendFailureResult(
1796
+ query,
1797
+ "tinyfish",
1798
+ startedAt,
1799
+ { statusCode: 429 },
1800
+ "TinyFish Search rate limit exceeded after retries. Try again shortly.",
1801
+ );
1802
+ }
1803
+
1361
1804
  // ----------------------------------------------------------------------------
1362
1805
  // Adapter registry
1363
1806
  //
@@ -1424,6 +1867,23 @@ const fastcrwSearchAdapter: WebSearchAdapter = {
1424
1867
  executeFastcrwSearch(query, count, freshness, apiKey, signal),
1425
1868
  };
1426
1869
 
1870
+ const searxngSearchAdapter: WebSearchAdapter = {
1871
+ id: "searxng",
1872
+ providerKeyName: "searxng",
1873
+ fallbackOrder: 7,
1874
+ keyless: true,
1875
+ execute: ({ query, count, freshness, apiKey, signal }) =>
1876
+ executeSearxngSearch(query, count, freshness, apiKey, signal),
1877
+ };
1878
+
1879
+ const tinyfishSearchAdapter: WebSearchAdapter = {
1880
+ id: "tinyfish",
1881
+ providerKeyName: "tinyfish",
1882
+ fallbackOrder: 8,
1883
+ execute: ({ query, count, freshness, apiKey, signal }) =>
1884
+ executeTinyfishSearch(query, count, freshness, apiKey, signal),
1885
+ };
1886
+
1427
1887
  /**
1428
1888
  * All built-in web-search adapters keyed by provider id. The
1429
1889
  * `Record<WebSearchProvider, ...>` shape forces TypeScript to flag any
@@ -1436,6 +1896,8 @@ const WEB_SEARCH_ADAPTERS: Record<WebSearchProvider, WebSearchAdapter> = {
1436
1896
  firecrawl: firecrawlSearchAdapter,
1437
1897
  keenable: keenableSearchAdapter,
1438
1898
  fastcrw: fastcrwSearchAdapter,
1899
+ searxng: searxngSearchAdapter,
1900
+ tinyfish: tinyfishSearchAdapter,
1439
1901
  };
1440
1902
 
1441
1903
  /**
@@ -1467,7 +1929,7 @@ export const webSearchTool = {
1467
1929
  count: {
1468
1930
  type: "number",
1469
1931
  description:
1470
- "Number of results to return (1-20, default 10). Used with Brave, Tavily, Firecrawl, Keenable, and fastCRW providers.",
1932
+ "Number of results to return (1-20, default 10). Used with Brave, Tavily, Firecrawl, Keenable, fastCRW, SearXNG, and TinyFish providers.",
1471
1933
  },
1472
1934
  offset: {
1473
1935
  type: "number",
@@ -1477,7 +1939,7 @@ export const webSearchTool = {
1477
1939
  freshness: {
1478
1940
  type: "string",
1479
1941
  description:
1480
- 'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave, Tavily, Firecrawl, Keenable, and fastCRW providers.',
1942
+ 'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave, Tavily, Firecrawl, Keenable, fastCRW, SearXNG, and TinyFish providers. SearXNG maps day/month/year and omits week.',
1481
1943
  },
1482
1944
  },
1483
1945
  required: ["query"],
@@ -1593,7 +2055,7 @@ export const webSearchTool = {
1593
2055
  query,
1594
2056
  provider,
1595
2057
  startedAt,
1596
- "No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, `keys set tavily <key>`, `keys set firecrawl <key>`, or `keys set fastcrw <key>`, or configure it from the Settings page under API Keys. Or switch the web-search provider to Keenable, which works without a key.",
2058
+ "No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, `keys set tavily <key>`, `keys set firecrawl <key>`, or `keys set fastcrw <key>`, or `keys set tinyfish <key>`, or configure it from the Settings page under API Keys. Or switch the web-search provider to Keenable, which works without a key, or SearXNG with your instance URL.",
1597
2059
  );
1598
2060
  }
1599
2061
  }
@@ -119,8 +119,8 @@ export class PermissionChecker {
119
119
  >,
120
120
  classification?: RiskClassificationWithMeta,
121
121
  ): Promise<PermissionDecision> {
122
- // Sandbox/host routing for the prompt comes from the tool's manifest.
123
- const executionTarget = resolveExecutionTarget(tool);
122
+ // Policy and prompts use the invocation's execution target.
123
+ const executionTarget = resolveExecutionTarget(tool, input, context);
124
124
  classification ??= await classifyRisk(
125
125
  name,
126
126
  input,
@@ -149,7 +149,7 @@ export class PermissionChecker {
149
149
  // this, the executor's catch block would fall back to the default
150
150
  // low risk, degrading audit/alert accuracy for high-risk attempts.
151
151
  try {
152
- const policyContext = buildPolicyContext(tool, context);
152
+ const policyContext = buildPolicyContext(tool, context, input);
153
153
  const result = await check(
154
154
  name,
155
155
  input,
@@ -3,6 +3,7 @@ import { isSkillImprovementActive } from "../config/memory-v3-gate.js";
3
3
  import type { ExecutionContext } from "../permissions/approval-policy.js";
4
4
  import type { ChannelPermissionCoordinates } from "../permissions/channel-permission-query.js";
5
5
  import type { PolicyContext } from "../permissions/types.js";
6
+ import { resolveExecutionTarget } from "./execution-target.js";
6
7
  import { getToolOwner } from "./registry.js";
7
8
  import type { Tool, ToolContext } from "./types.js";
8
9
 
@@ -48,6 +49,7 @@ function deriveExecutionContext(context?: ToolContext): ExecutionContext {
48
49
  export function buildPolicyContext(
49
50
  tool: Tool,
50
51
  context?: ToolContext,
52
+ input?: Record<string, unknown>,
51
53
  ): PolicyContext {
52
54
  const executionContext = deriveExecutionContext(context);
53
55
 
@@ -73,7 +75,7 @@ export function buildPolicyContext(
73
75
  const ownerKind = getToolOwner(tool.name)?.kind;
74
76
  if (ownerKind === "skill" || ownerKind === "plugin") {
75
77
  return {
76
- executionTarget: tool.executionTarget,
78
+ executionTarget: resolveExecutionTarget(tool, input, context),
77
79
  executionContext,
78
80
  conversationId,
79
81
  ...originSignals,
@@ -4,6 +4,7 @@ import { dirname, join } from "node:path";
4
4
  import { minimatch } from "minimatch";
5
5
 
6
6
  import { ensureDir, pathExists } from "../../../util/fs.js";
7
+ import { surrogateSafeWindow } from "../../../util/unicode.js";
7
8
  import { isAbortLikeError } from "../abort.js";
8
9
  import { applyEdit } from "./edit-engine.js";
9
10
  import * as Err from "./errors.js";
@@ -102,37 +103,6 @@ function truncationNotice(
102
103
  return `\n\n[Truncated: characters ${start}-${end} of ${totalChars}. Read on with start_index=${end}.]`;
103
104
  }
104
105
 
105
- const isHighSurrogate = (code: number): boolean =>
106
- code >= 0xd800 && code <= 0xdbff;
107
- const isLowSurrogate = (code: number): boolean =>
108
- code >= 0xdc00 && code <= 0xdfff;
109
-
110
- /**
111
- * Character window that never splits a surrogate pair. A split leaves a lone
112
- * half at each edge, and each encodes to U+FFFD, so the character is lost from
113
- * both this window and the next one paged in after it.
114
- */
115
- export function surrogateSafeWindow(
116
- total: number,
117
- charCodeAt: (index: number) => number,
118
- requestedStart: number,
119
- maxChars: number,
120
- ): { start: number; end: number } {
121
- let start = Math.max(0, Math.min(requestedStart, total));
122
- if (start > 0 && start < total && isLowSurrogate(charCodeAt(start))) {
123
- start -= 1;
124
- }
125
-
126
- let end = Math.min(total, start + maxChars);
127
- if (end > start && end < total && isHighSurrogate(charCodeAt(end - 1))) {
128
- // Backing off would empty a one-character window, which stalls paging on
129
- // the same offset, so take the whole pair instead.
130
- end = end - 1 > start ? end - 1 : Math.min(total, end + 1);
131
- }
132
-
133
- return { start, end };
134
- }
135
-
136
106
  export class FileSystemOps {
137
107
  private policy: PathPolicy;
138
108
  private sizeLimit: number | undefined;
@@ -7,6 +7,7 @@ import {
7
7
  formatShellOutput,
8
8
  MAX_OUTPUT_LENGTH,
9
9
  OUTPUT_TRUNCATED_TAG,
10
+ SHELL_DID_NOT_START_MESSAGE,
10
11
  } from "./shell-output.js";
11
12
 
12
13
  describe("BoundedStdioCollector", () => {
@@ -85,6 +86,15 @@ describe("attachBoundedStdio", () => {
85
86
  });
86
87
  });
87
88
 
89
+ describe("formatShellOutput launch start", () => {
90
+ test("does not report command_completed when the process never started", () => {
91
+ const result = formatShellOutput("", "", 0, false, 120, { started: false });
92
+ expect(result.isError).toBe(true);
93
+ expect(result.content).toBe(SHELL_DID_NOT_START_MESSAGE);
94
+ expect(result.content).not.toContain("<command_completed />");
95
+ });
96
+ });
97
+
88
98
  describe("formatShellOutput truncation", () => {
89
99
  test("truncates an already-materialized oversized string without a file path", () => {
90
100
  const longOutput = "x".repeat(30_000);
@@ -4,6 +4,9 @@ export const MAX_OUTPUT_LENGTH = 20_000;
4
4
 
5
5
  export const OUTPUT_TRUNCATED_TAG = `<output_truncated limit="20K" />`;
6
6
 
7
+ export const SHELL_DID_NOT_START_MESSAGE =
8
+ "Error: the shell command did not start. No process was created, so the command did not run.";
9
+
7
10
  export interface ShellOutputResult {
8
11
  content: string;
9
12
  status: string | undefined;
@@ -31,8 +34,16 @@ export function formatShellOutput(
31
34
  code: number | null,
32
35
  timedOut: boolean,
33
36
  timeoutSec: number,
34
- options?: { truncated?: boolean },
37
+ options?: { truncated?: boolean; started?: boolean },
35
38
  ): ShellOutputResult {
39
+ if (options?.started === false) {
40
+ return {
41
+ content: SHELL_DID_NOT_START_MESSAGE,
42
+ status: undefined,
43
+ isError: true,
44
+ };
45
+ }
46
+
36
47
  let output = stdout;
37
48
  if (stderr) {
38
49
  output += (output ? "\n" : "") + stderr;
@@ -137,6 +148,7 @@ export class BoundedStdioCollector {
137
148
  code: number | null,
138
149
  timedOut: boolean,
139
150
  timeoutSec: number,
151
+ options?: { started?: boolean },
140
152
  ): ShellOutputResult {
141
153
  return formatShellOutput(
142
154
  Buffer.concat(this.stdoutParts).toString(),
@@ -144,7 +156,7 @@ export class BoundedStdioCollector {
144
156
  code,
145
157
  timedOut,
146
158
  timeoutSec,
147
- { truncated: this.truncated },
159
+ { truncated: this.truncated, started: options?.started },
148
160
  );
149
161
  }
150
162
  }