@vellumai/assistant 0.7.1 → 0.7.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 (535) hide show
  1. package/ARCHITECTURE.md +32 -49
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/security.md +20 -0
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +1 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
  19. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  20. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  21. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  22. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  23. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  24. package/openapi.yaml +565 -12
  25. package/package.json +6 -3
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  27. package/src/__tests__/app-bundler.test.ts +170 -1
  28. package/src/__tests__/app-control-flow.test.ts +374 -0
  29. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  30. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  31. package/src/__tests__/app-executors.test.ts +30 -43
  32. package/src/__tests__/approval-routes-http.test.ts +23 -6
  33. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  34. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  35. package/src/__tests__/assistant-event-hub.test.ts +109 -2
  36. package/src/__tests__/assistant-event.test.ts +10 -0
  37. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
  39. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  40. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  41. package/src/__tests__/btw-routes.test.ts +13 -4
  42. package/src/__tests__/call-controller.test.ts +49 -1
  43. package/src/__tests__/call-domain.test.ts +0 -2
  44. package/src/__tests__/call-routes-http.test.ts +0 -2
  45. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  46. package/src/__tests__/checker.test.ts +3 -4
  47. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  48. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  49. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  50. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  51. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  54. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  55. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  56. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  57. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  58. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  59. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  60. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  61. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  62. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  64. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  65. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  66. package/src/__tests__/credentials-cli.test.ts +5 -12
  67. package/src/__tests__/cu-unified-flow.test.ts +185 -23
  68. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  69. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  70. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  71. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  72. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  73. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  74. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  75. package/src/__tests__/heartbeat-service.test.ts +718 -1
  76. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  77. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  78. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  79. package/src/__tests__/host-bash-proxy.test.ts +246 -47
  80. package/src/__tests__/host-bash-routes.test.ts +294 -0
  81. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  82. package/src/__tests__/host-browser-routes.test.ts +39 -13
  83. package/src/__tests__/host-cu-proxy.test.ts +41 -52
  84. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  85. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  86. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  87. package/src/__tests__/host-file-proxy.test.ts +37 -43
  88. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  89. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  90. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  91. package/src/__tests__/host-proxy-base.test.ts +312 -0
  92. package/src/__tests__/host-shell-tool.test.ts +22 -4
  93. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  94. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  95. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  96. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  97. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  98. package/src/__tests__/identity-routes.test.ts +103 -1
  99. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  100. package/src/__tests__/inline-command-runner.test.ts +0 -1
  101. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  102. package/src/__tests__/integration-status.test.ts +85 -5
  103. package/src/__tests__/intent-routing.test.ts +0 -1
  104. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  105. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  106. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  107. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  108. package/src/__tests__/mcp-cli.test.ts +338 -2
  109. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  110. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  111. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  112. package/src/__tests__/oauth-cli.test.ts +0 -2
  113. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  114. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  115. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  116. package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
  117. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  118. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  119. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  120. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  121. package/src/__tests__/retry-backoff.test.ts +87 -0
  122. package/src/__tests__/runtime-events-sse.test.ts +10 -6
  123. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  124. package/src/__tests__/schedule-retry.test.ts +715 -0
  125. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  126. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  127. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  128. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  129. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  130. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  131. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  132. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  133. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  134. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  135. package/src/__tests__/slack-channel-config.test.ts +9 -14
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  137. package/src/__tests__/system-prompt.test.ts +0 -1
  138. package/src/__tests__/telegram-config.test.ts +0 -1
  139. package/src/__tests__/test-preload.ts +8 -0
  140. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  141. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  142. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  143. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  145. package/src/__tests__/tool-executor.test.ts +0 -1
  146. package/src/__tests__/twilio-config.test.ts +3 -16
  147. package/src/__tests__/twilio-routes.test.ts +3 -5
  148. package/src/__tests__/twilio-validation.test.ts +93 -0
  149. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  150. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  151. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  152. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  153. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  154. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  155. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  156. package/src/backup/__tests__/paths.test.ts +0 -22
  157. package/src/backup/__tests__/restore.test.ts +51 -151
  158. package/src/backup/paths.ts +2 -18
  159. package/src/backup/restore.ts +107 -231
  160. package/src/bundler/app-bundler.ts +51 -3
  161. package/src/calls/relay-server.ts +4 -44
  162. package/src/calls/twilio-config.ts +2 -17
  163. package/src/calls/twilio-rest.ts +33 -105
  164. package/src/calls/twilio-routes.ts +11 -12
  165. package/src/channels/types.ts +8 -7
  166. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  167. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  168. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  169. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  170. package/src/cli/commands/backup.ts +6 -331
  171. package/src/cli/commands/clients.ts +36 -37
  172. package/src/cli/commands/contacts.ts +73 -0
  173. package/src/cli/commands/conversations.ts +2 -5
  174. package/src/cli/commands/credentials.ts +15 -7
  175. package/src/cli/commands/domain.ts +66 -15
  176. package/src/cli/commands/gateway.ts +183 -0
  177. package/src/cli/commands/keys.ts +9 -6
  178. package/src/cli/commands/mcp.ts +116 -156
  179. package/src/cli/commands/memory-v2.ts +296 -1
  180. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  181. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  182. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  183. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  184. package/src/cli/commands/platform/disconnect.ts +5 -4
  185. package/src/cli/commands/platform/index.ts +0 -18
  186. package/src/cli/lib/daemon-credential-client.ts +110 -28
  187. package/src/cli/program.ts +2 -0
  188. package/src/config/assistant-feature-flags.ts +67 -10
  189. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  190. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  191. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  192. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  193. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  194. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  195. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  196. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  197. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  198. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  199. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  200. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  201. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  202. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  203. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  204. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  205. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  206. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  207. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  208. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  209. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  210. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  211. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  212. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  213. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  214. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  215. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  216. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  217. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  218. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  219. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  220. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  221. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  222. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  223. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  224. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  225. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  226. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  227. package/src/config/bundled-tool-registry.ts +21 -0
  228. package/src/config/env-registry.ts +0 -2
  229. package/src/config/env.ts +19 -12
  230. package/src/config/feature-flag-registry.json +21 -133
  231. package/src/config/loader.ts +73 -99
  232. package/src/config/sanitize-for-transfer.ts +2 -0
  233. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  234. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
  235. package/src/config/schemas/calls.ts +0 -9
  236. package/src/config/schemas/heartbeat.ts +63 -0
  237. package/src/config/schemas/ingress.ts +10 -6
  238. package/src/config/schemas/llm.ts +5 -10
  239. package/src/config/schemas/memory-lifecycle.ts +77 -24
  240. package/src/config/schemas/memory-v2.ts +48 -4
  241. package/src/config/schemas/platform.ts +6 -0
  242. package/src/config/schemas/services.ts +1 -15
  243. package/src/config/schemas/skills.ts +0 -6
  244. package/src/config/seed-inference-profiles.ts +1 -1
  245. package/src/contacts/contact-store.ts +0 -30
  246. package/src/contacts/contacts-write.ts +0 -27
  247. package/src/context/window-manager.ts +1 -2
  248. package/src/credential-execution/feature-gates.ts +10 -10
  249. package/src/credential-execution/process-manager.ts +12 -41
  250. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  251. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  252. package/src/daemon/config-watcher.ts +4 -3
  253. package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
  254. package/src/daemon/conversation-agent-loop.ts +32 -28
  255. package/src/daemon/conversation-lifecycle.ts +8 -1
  256. package/src/daemon/conversation-process.ts +16 -11
  257. package/src/daemon/conversation-runtime-assembly.ts +2 -2
  258. package/src/daemon/conversation-surfaces.ts +125 -4
  259. package/src/daemon/conversation-tool-setup.ts +16 -55
  260. package/src/daemon/conversation.ts +21 -2
  261. package/src/daemon/doordash-steps.ts +1 -1
  262. package/src/daemon/handlers/shared.ts +4 -1
  263. package/src/daemon/host-app-control-proxy.ts +293 -0
  264. package/src/daemon/host-bash-proxy.ts +84 -74
  265. package/src/daemon/host-browser-proxy.ts +67 -82
  266. package/src/daemon/host-cu-proxy.ts +81 -86
  267. package/src/daemon/host-file-proxy.ts +93 -69
  268. package/src/daemon/host-proxy-base.ts +294 -0
  269. package/src/daemon/host-proxy-preactivation.ts +82 -0
  270. package/src/daemon/host-transfer-proxy.ts +247 -129
  271. package/src/daemon/lifecycle.ts +115 -117
  272. package/src/daemon/message-protocol.ts +3 -8
  273. package/src/daemon/message-types/contacts.ts +23 -1
  274. package/src/daemon/message-types/conversations.ts +11 -8
  275. package/src/daemon/message-types/host-app-control.ts +150 -0
  276. package/src/daemon/message-types/host-bash.ts +4 -0
  277. package/src/daemon/message-types/host-cu.ts +2 -0
  278. package/src/daemon/message-types/host-file.ts +4 -0
  279. package/src/daemon/message-types/host-transfer.ts +3 -0
  280. package/src/daemon/message-types/schedules.ts +8 -3
  281. package/src/daemon/message-types/skills.ts +2 -2
  282. package/src/daemon/process-message.ts +18 -1
  283. package/src/daemon/shutdown-handlers.ts +0 -3
  284. package/src/daemon/tool-setup-types.ts +51 -0
  285. package/src/daemon/tool-side-effects.ts +1 -1
  286. package/src/events/tool-audit-listener.ts +2 -1
  287. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
  288. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  289. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  290. package/src/heartbeat/heartbeat-service.ts +280 -49
  291. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  292. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  293. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  294. package/src/home/post-connect-feed.ts +68 -0
  295. package/src/home/relationship-state-writer.ts +17 -92
  296. package/src/home/suggested-prompts.ts +46 -10
  297. package/src/inbound/public-ingress-urls.ts +32 -34
  298. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  299. package/src/ipc/assistant-server.ts +14 -1
  300. package/src/ipc/cli-client.ts +32 -1
  301. package/src/live-voice/live-voice-metrics.ts +10 -10
  302. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  303. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  304. package/src/mcp/mcp-auth-state.ts +133 -0
  305. package/src/mcp/mcp-oauth-provider.ts +19 -0
  306. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  307. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  308. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  309. package/src/memory/anisotropy.test.ts +247 -0
  310. package/src/memory/anisotropy.ts +443 -0
  311. package/src/memory/auto-analysis-constants.ts +17 -0
  312. package/src/memory/auto-analysis-guard.ts +5 -15
  313. package/src/memory/canonical-guardian-store.ts +7 -7
  314. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  315. package/src/memory/context-search/agent-protocol.ts +6 -6
  316. package/src/memory/context-search/agent-runner.ts +32 -7
  317. package/src/memory/context-search/sources/memory-v2.ts +17 -5
  318. package/src/memory/conversation-crud.ts +1 -1
  319. package/src/memory/conversation-key-store.ts +2 -15
  320. package/src/memory/db-init.ts +4 -0
  321. package/src/memory/embedding-backend.ts +9 -21
  322. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
  323. package/src/memory/graph/conversation-graph-memory.ts +1 -24
  324. package/src/memory/graph/graph-search.ts +8 -0
  325. package/src/memory/graph/retriever.ts +28 -0
  326. package/src/memory/graph/tools.ts +1 -1
  327. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  328. package/src/memory/jobs/embed-concept-page.ts +28 -2
  329. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  330. package/src/memory/jobs-store.ts +66 -22
  331. package/src/memory/jobs-worker.ts +112 -63
  332. package/src/memory/memory-v2-activation-log-store.ts +1 -1
  333. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  334. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  335. package/src/memory/migrations/index.ts +5 -0
  336. package/src/memory/migrations/registry.ts +8 -0
  337. package/src/memory/pkb/pkb-search.ts +7 -0
  338. package/src/memory/qdrant-client.ts +50 -20
  339. package/src/memory/schema/infrastructure.ts +15 -0
  340. package/src/memory/search/semantic.ts +7 -0
  341. package/src/memory/sparse-tokenize.ts +49 -0
  342. package/src/memory/v2/__tests__/activation.test.ts +77 -95
  343. package/src/memory/v2/__tests__/injection.test.ts +43 -21
  344. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  345. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  346. package/src/memory/v2/__tests__/static-context.test.ts +0 -1
  347. package/src/memory/v2/activation.ts +69 -88
  348. package/src/memory/v2/consolidation-job.ts +3 -5
  349. package/src/memory/v2/constants.ts +7 -0
  350. package/src/memory/v2/injection.ts +86 -53
  351. package/src/memory/v2/prompts/consolidation.ts +312 -91
  352. package/src/memory/v2/qdrant.ts +99 -1
  353. package/src/memory/v2/sim.ts +126 -16
  354. package/src/memory/v2/skill-qdrant.ts +12 -3
  355. package/src/memory/v2/skill-store.ts +16 -1
  356. package/src/memory/v2/sparse-bm25.ts +245 -0
  357. package/src/memory/v2/static-context.ts +6 -5
  358. package/src/messaging/providers/gmail/types.ts +0 -49
  359. package/src/messaging/providers/slack/adapter.ts +1 -31
  360. package/src/messaging/providers/slack/types.ts +0 -32
  361. package/src/notifications/README.md +10 -10
  362. package/src/notifications/broadcaster.ts +1 -1
  363. package/src/notifications/guardian-question-mode.ts +5 -5
  364. package/src/oauth/connect-orchestrator.ts +4 -0
  365. package/src/oauth/credential-token-resolver.ts +1 -3
  366. package/src/oauth/manual-token-connection.ts +0 -4
  367. package/src/outbound-proxy/index.ts +1 -37
  368. package/src/outbound-proxy/logging.ts +1 -1
  369. package/src/outbound-proxy/policy.ts +6 -5
  370. package/src/outbound-proxy/router.ts +2 -1
  371. package/src/permissions/approval-policy.test.ts +6 -275
  372. package/src/permissions/approval-policy.ts +0 -51
  373. package/src/permissions/checker.test.ts +0 -1
  374. package/src/permissions/checker.ts +3 -17
  375. package/src/permissions/gateway-threshold-reader.ts +2 -0
  376. package/src/permissions/prompter.ts +34 -1
  377. package/src/permissions/secret-prompter.ts +6 -2
  378. package/src/prompts/bootstrap-cleanup.ts +27 -0
  379. package/src/prompts/system-prompt.ts +3 -18
  380. package/src/prompts/templates/SOUL.md +13 -1
  381. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  382. package/src/runtime/assistant-event-hub.ts +118 -96
  383. package/src/runtime/assistant-event.ts +1 -0
  384. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  385. package/src/runtime/auth/middleware.ts +0 -96
  386. package/src/runtime/auth/route-policy.ts +19 -0
  387. package/src/runtime/btw-sidechain.ts +2 -3
  388. package/src/runtime/channel-invite-transport.ts +2 -48
  389. package/src/runtime/channel-invite-transports/email.ts +1 -1
  390. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  391. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  392. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  393. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  394. package/src/runtime/channel-invite-types.ts +54 -0
  395. package/src/runtime/channel-readiness-service.ts +32 -13
  396. package/src/runtime/http-server.ts +3 -329
  397. package/src/runtime/http-types.ts +0 -5
  398. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  399. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  400. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  401. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  402. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  403. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  404. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  405. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  406. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  407. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  408. package/src/runtime/migrations/migration-transport.ts +7 -7
  409. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  410. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  411. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  412. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  413. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  414. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  415. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  416. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  417. package/src/runtime/pending-interactions.ts +35 -9
  418. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  419. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  420. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  421. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  422. package/src/runtime/routes/approval-interception-types.ts +13 -0
  423. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  424. package/src/runtime/routes/backup-routes.ts +15 -38
  425. package/src/runtime/routes/btw-routes.ts +14 -37
  426. package/src/runtime/routes/client-routes.ts +1 -0
  427. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  428. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  429. package/src/runtime/routes/conversation-routes.ts +30 -13
  430. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  431. package/src/runtime/routes/documents-routes.ts +30 -0
  432. package/src/runtime/routes/errors.ts +19 -4
  433. package/src/runtime/routes/events-routes.ts +12 -6
  434. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  435. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  436. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  437. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  438. package/src/runtime/routes/host-bash-routes.ts +36 -6
  439. package/src/runtime/routes/host-browser-routes.ts +108 -13
  440. package/src/runtime/routes/host-cu-routes.ts +44 -14
  441. package/src/runtime/routes/host-file-routes.ts +33 -10
  442. package/src/runtime/routes/host-transfer-routes.ts +64 -24
  443. package/src/runtime/routes/http-adapter.ts +1 -0
  444. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  445. package/src/runtime/routes/identity-routes.ts +15 -43
  446. package/src/runtime/routes/inbound-message-handler.ts +1 -9
  447. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  448. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  449. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  450. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  451. package/src/runtime/routes/index.ts +8 -0
  452. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  453. package/src/runtime/routes/memory-item-routes.ts +10 -12
  454. package/src/runtime/routes/memory-v2-routes.ts +441 -1
  455. package/src/runtime/routes/migration-routes.ts +96 -0
  456. package/src/runtime/routes/schedule-routes.ts +7 -0
  457. package/src/runtime/verification-templates.ts +4 -7
  458. package/src/schedule/integration-status.ts +66 -2
  459. package/src/schedule/recurrence-engine.ts +4 -1
  460. package/src/schedule/retry-backoff.ts +18 -0
  461. package/src/schedule/retry-policy.ts +82 -0
  462. package/src/schedule/schedule-recovery.ts +64 -0
  463. package/src/schedule/schedule-store.ts +106 -2
  464. package/src/schedule/scheduler-types.ts +25 -0
  465. package/src/schedule/scheduler.ts +63 -38
  466. package/src/security/oauth-callback-registry.ts +8 -0
  467. package/src/sequence/analytics.ts +5 -5
  468. package/src/sequence/engine.ts +1 -1
  469. package/src/skills/catalog-files.ts +2 -8
  470. package/src/skills/include-graph.ts +5 -5
  471. package/src/skills/remote-skill-policy.ts +5 -5
  472. package/src/skills/skill-file-provider.ts +1 -1
  473. package/src/skills/skill-file-types.ts +13 -0
  474. package/src/skills/skillssh-audit-types.ts +28 -0
  475. package/src/skills/skillssh-registry.ts +8 -21
  476. package/src/telemetry/types.ts +2 -0
  477. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  478. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  479. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  480. package/src/tools/apps/executors.ts +56 -69
  481. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  482. package/src/tools/browser/browser-execution.ts +2 -2
  483. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  484. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  485. package/src/tools/browser/cdp-client/factory.ts +23 -24
  486. package/src/tools/browser/cdp-client/index.ts +1 -14
  487. package/src/tools/computer-use/definitions.ts +42 -20
  488. package/src/tools/executor.ts +2 -0
  489. package/src/tools/host-filesystem/edit.ts +26 -0
  490. package/src/tools/host-filesystem/read.ts +26 -0
  491. package/src/tools/host-filesystem/transfer.ts +31 -1
  492. package/src/tools/host-filesystem/write.ts +26 -0
  493. package/src/tools/host-terminal/host-shell.ts +58 -0
  494. package/src/tools/schedule/create.ts +6 -0
  495. package/src/tools/schedule/list.ts +2 -0
  496. package/src/tools/schedule/update.ts +10 -0
  497. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  498. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  499. package/src/tools/skills/load.ts +0 -32
  500. package/src/tools/tool-approval-handler.ts +1 -5
  501. package/src/tools/types.ts +4 -0
  502. package/src/usage/pricing.ts +1 -1
  503. package/src/workspace/hatched-date.ts +86 -0
  504. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  505. package/src/workspace/migrations/006-services-config.ts +8 -5
  506. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  507. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  508. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  509. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  510. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  511. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  512. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  513. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  514. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  515. package/src/workspace/migrations/AGENTS.md +1 -1
  516. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  517. package/src/workspace/migrations/utils.ts +21 -0
  518. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  519. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  520. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  521. package/src/__tests__/twilio-rest.test.ts +0 -34
  522. package/src/backup/__tests__/backup-key.test.ts +0 -152
  523. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  524. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  525. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  526. package/src/backup/backup-key.ts +0 -137
  527. package/src/backup/backup-worker.ts +0 -472
  528. package/src/backup/offsite-writer.ts +0 -222
  529. package/src/backup/stream-crypt.ts +0 -263
  530. package/src/daemon/message-types/pairing.ts +0 -58
  531. package/src/outbound-proxy/config.ts +0 -20
  532. package/src/outbound-proxy/health.ts +0 -18
  533. package/src/outbound-proxy/types.ts +0 -150
  534. package/src/runtime/capability-tokens.ts +0 -190
  535. package/src/signals/mcp-reload.ts +0 -18
@@ -21,12 +21,6 @@ function proxyExecute(): Promise<ToolExecutionResult> {
21
21
  );
22
22
  }
23
23
 
24
- const activityProperty = {
25
- type: "string" as const,
26
- description:
27
- "Brief non-technical explanation of why this tool is being called",
28
- };
29
-
30
24
  // ---------------------------------------------------------------------------
31
25
  // click (unified - click_type selects single / double / right)
32
26
  // ---------------------------------------------------------------------------
@@ -69,7 +63,11 @@ export const computerUseClickTool: Tool = {
69
63
  description:
70
64
  "Explanation of what you see and why you are clicking here",
71
65
  },
72
- activity: activityProperty,
66
+ target_client_id: {
67
+ type: "string",
68
+ description:
69
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
70
+ },
73
71
  },
74
72
  required: ["reasoning"],
75
73
  },
@@ -106,7 +104,11 @@ export const computerUseTypeTextTool: Tool = {
106
104
  type: "string",
107
105
  description: "Explanation of what you are typing and why",
108
106
  },
109
- activity: activityProperty,
107
+ target_client_id: {
108
+ type: "string",
109
+ description:
110
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
111
+ },
110
112
  },
111
113
  required: ["text", "reasoning"],
112
114
  },
@@ -144,7 +146,11 @@ export const computerUseKeyTool: Tool = {
144
146
  type: "string",
145
147
  description: "Explanation of why you are pressing this key",
146
148
  },
147
- activity: activityProperty,
149
+ target_client_id: {
150
+ type: "string",
151
+ description:
152
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
153
+ },
148
154
  },
149
155
  required: ["key", "reasoning"],
150
156
  },
@@ -199,7 +205,11 @@ export const computerUseScrollTool: Tool = {
199
205
  type: "string",
200
206
  description: "Explanation of why you are scrolling",
201
207
  },
202
- activity: activityProperty,
208
+ target_client_id: {
209
+ type: "string",
210
+ description:
211
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
212
+ },
203
213
  },
204
214
  required: ["direction", "amount", "reasoning"],
205
215
  },
@@ -260,7 +270,11 @@ export const computerUseDragTool: Tool = {
260
270
  type: "string",
261
271
  description: "Explanation of what you are dragging and why",
262
272
  },
263
- activity: activityProperty,
273
+ target_client_id: {
274
+ type: "string",
275
+ description:
276
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
277
+ },
264
278
  },
265
279
  required: ["reasoning"],
266
280
  },
@@ -296,7 +310,11 @@ export const computerUseWaitTool: Tool = {
296
310
  type: "string",
297
311
  description: "Explanation of what you are waiting for",
298
312
  },
299
- activity: activityProperty,
313
+ target_client_id: {
314
+ type: "string",
315
+ description:
316
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
317
+ },
300
318
  },
301
319
  required: ["duration_ms", "reasoning"],
302
320
  },
@@ -335,7 +353,11 @@ export const computerUseOpenAppTool: Tool = {
335
353
  description:
336
354
  "Explanation of why you need to open or switch to this app",
337
355
  },
338
- activity: activityProperty,
356
+ target_client_id: {
357
+ type: "string",
358
+ description:
359
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
360
+ },
339
361
  },
340
362
  required: ["app_name", "reasoning"],
341
363
  },
@@ -373,7 +395,11 @@ export const computerUseRunAppleScriptTool: Tool = {
373
395
  description:
374
396
  "Explanation of what this script does and why AppleScript is better than UI interaction for this step",
375
397
  },
376
- activity: activityProperty,
398
+ target_client_id: {
399
+ type: "string",
400
+ description:
401
+ "ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
402
+ },
377
403
  },
378
404
  required: ["script", "reasoning"],
379
405
  },
@@ -406,7 +432,6 @@ export const computerUseDoneTool: Tool = {
406
432
  type: "string",
407
433
  description: "Human-readable summary of what was accomplished",
408
434
  },
409
- activity: activityProperty,
410
435
  },
411
436
  required: ["summary"],
412
437
  },
@@ -443,7 +468,6 @@ export const computerUseRespondTool: Tool = {
443
468
  type: "string",
444
469
  description: "Explanation of how you determined the answer",
445
470
  },
446
- activity: activityProperty,
447
471
  },
448
472
  required: ["answer", "reasoning"],
449
473
  },
@@ -471,10 +495,8 @@ const computerUseObserveTool: Tool = {
471
495
  description: this.description,
472
496
  input_schema: {
473
497
  type: "object",
474
- properties: {
475
- activity: activityProperty,
476
- },
477
- required: ["activity"],
498
+ properties: {},
499
+ required: [],
478
500
  },
479
501
  };
480
502
  },
@@ -406,6 +406,8 @@ export class ToolExecutor {
406
406
  requestId: context.requestId,
407
407
  riskLevel,
408
408
  matchedTrustRuleId: permMatchedTrustRuleId,
409
+ approvalMode: permApprovalMode,
410
+ approvalReason: permApprovalReason,
409
411
  decision,
410
412
  durationMs,
411
413
  result: safeResult,
@@ -1,6 +1,8 @@
1
+ import { supportsHostProxy } from "../../channels/types.js";
1
2
  import { HostFileProxy } from "../../daemon/host-file-proxy.js";
2
3
  import { RiskLevel } from "../../permissions/types.js";
3
4
  import type { ToolDefinition } from "../../providers/types.js";
5
+ import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
4
6
  import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
5
7
  import { formatEditDiff } from "../shared/filesystem/format-diff.js";
6
8
  import { hostPolicy } from "../shared/filesystem/path-policy.js";
@@ -37,6 +39,11 @@ class HostFileEditTool implements Tool {
37
39
  description:
38
40
  "Replace all occurrences instead of requiring a unique match (default: false)",
39
41
  },
42
+ target_client_id: {
43
+ type: "string",
44
+ description:
45
+ "ID of the specific client to execute this on. Required when multiple clients support host_file; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_file`.",
46
+ },
40
47
  },
41
48
  required: ["path", "old_string", "new_string"],
42
49
  },
@@ -84,6 +91,24 @@ class HostFileEditTool implements Tool {
84
91
 
85
92
  const replaceAll = input.replace_all === true;
86
93
 
94
+ const targetClientId =
95
+ typeof input.target_client_id === "string" && input.target_client_id !== ""
96
+ ? input.target_client_id
97
+ : undefined;
98
+
99
+ const transportInterface = context.transportInterface;
100
+ if (
101
+ targetClientId == null &&
102
+ transportInterface != null &&
103
+ !supportsHostProxy(transportInterface) &&
104
+ assistantEventHub.listClientsByCapability("host_file").length > 1
105
+ ) {
106
+ return {
107
+ content: `Error: multiple clients support host_file. Specify which client to use with \`target_client_id\`. Run \`assistant clients list --capability host_file\` to see client IDs and labels.`,
108
+ isError: true,
109
+ };
110
+ }
111
+
87
112
  // Proxy to connected client for execution on the user's machine
88
113
  // when a capable client is available (managed/cloud-hosted mode).
89
114
  if (HostFileProxy.instance.isAvailable()) {
@@ -94,6 +119,7 @@ class HostFileEditTool implements Tool {
94
119
  old_string: oldString as string,
95
120
  new_string: newString as string,
96
121
  replace_all: replaceAll,
122
+ targetClientId,
97
123
  },
98
124
  context.conversationId,
99
125
  context.signal,
@@ -1,8 +1,10 @@
1
1
  import { extname } from "node:path";
2
2
 
3
+ import { supportsHostProxy } from "../../channels/types.js";
3
4
  import { HostFileProxy } from "../../daemon/host-file-proxy.js";
4
5
  import { RiskLevel } from "../../permissions/types.js";
5
6
  import type { ToolDefinition } from "../../providers/types.js";
7
+ import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
6
8
  import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
7
9
  import {
8
10
  IMAGE_EXTENSIONS,
@@ -37,6 +39,11 @@ class HostFileReadTool implements Tool {
37
39
  type: "number",
38
40
  description: "Maximum number of lines to read",
39
41
  },
42
+ target_client_id: {
43
+ type: "string",
44
+ description:
45
+ "ID of the specific client to execute this on. Required when multiple clients support host_file; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_file`.",
46
+ },
40
47
  },
41
48
  required: ["path"],
42
49
  },
@@ -55,6 +62,24 @@ class HostFileReadTool implements Tool {
55
62
  };
56
63
  }
57
64
 
65
+ const targetClientId =
66
+ typeof input.target_client_id === "string" && input.target_client_id !== ""
67
+ ? input.target_client_id
68
+ : undefined;
69
+
70
+ const transportInterface = context.transportInterface;
71
+ if (
72
+ targetClientId == null &&
73
+ transportInterface != null &&
74
+ !supportsHostProxy(transportInterface) &&
75
+ assistantEventHub.listClientsByCapability("host_file").length > 1
76
+ ) {
77
+ return {
78
+ content: `Error: multiple clients support host_file. Specify which client to use with \`target_client_id\`. Run \`assistant clients list --capability host_file\` to see client IDs and labels.`,
79
+ isError: true,
80
+ };
81
+ }
82
+
58
83
  // Proxy to connected client for execution on the user's machine
59
84
  // when a capable client is available (managed/cloud-hosted mode),
60
85
  // including image reads that need the host filesystem view.
@@ -65,6 +90,7 @@ class HostFileReadTool implements Tool {
65
90
  path: rawPath,
66
91
  offset: typeof input.offset === "number" ? input.offset : undefined,
67
92
  limit: typeof input.limit === "number" ? input.limit : undefined,
93
+ targetClientId,
68
94
  },
69
95
  context.conversationId,
70
96
  context.signal,
@@ -2,16 +2,18 @@ import { constants } from "node:fs";
2
2
  import { copyFile, lstat, mkdir, realpath } from "node:fs/promises";
3
3
  import { dirname, isAbsolute } from "node:path";
4
4
 
5
+ import { supportsHostProxy } from "../../channels/types.js";
5
6
  import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
6
7
  import { RiskLevel } from "../../permissions/types.js";
7
8
  import type { ToolDefinition } from "../../providers/types.js";
9
+ import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
8
10
  import { sandboxPolicy } from "../shared/filesystem/path-policy.js";
9
11
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
10
12
 
11
13
  class HostFileTransferTool implements Tool {
12
14
  name = "host_file_transfer";
13
15
  description =
14
- "Copy a file between the assistant's workspace and the user's host machine. Set direction to 'to_host' to send a workspace file to the host, or 'to_sandbox' to pull a host file into the workspace.";
16
+ "Copy a file between the assistant's workspace and the user's host machine. Set direction to 'to_host' to send a workspace file to the host, or 'to_sandbox' to pull a host file into the workspace. When multiple clients support host_file, specify which one to use with target_client_id.";
15
17
  category = "host-filesystem";
16
18
  defaultRiskLevel = RiskLevel.Medium;
17
19
 
@@ -48,6 +50,11 @@ class HostFileTransferTool implements Tool {
48
50
  description:
49
51
  "Brief description of why the file is being transferred (for audit logging)",
50
52
  },
53
+ target_client_id: {
54
+ type: "string",
55
+ description:
56
+ "ID of the specific client to transfer files to/from. Required when multiple clients support host_file; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_file`.",
57
+ },
51
58
  },
52
59
  required: ["source_path", "dest_path", "direction"],
53
60
  },
@@ -85,6 +92,20 @@ class HostFileTransferTool implements Tool {
85
92
 
86
93
  const overwrite = input.overwrite === true;
87
94
 
95
+ const targetClientId =
96
+ typeof input.target_client_id === "string" && input.target_client_id !== ""
97
+ ? input.target_client_id
98
+ : undefined;
99
+
100
+ if (
101
+ targetClientId == null &&
102
+ context.transportInterface != null &&
103
+ !supportsHostProxy(context.transportInterface) &&
104
+ assistantEventHub.listClientsByCapability("host_file").length > 1
105
+ ) {
106
+ return { content: `Error: multiple clients support host_file. Specify which client to use with \`target_client_id\`. Run \`assistant clients list --capability host_file\` to see client IDs and labels.`, isError: true };
107
+ }
108
+
88
109
  // Validate that host-side paths are absolute.
89
110
  if (direction === "to_host" && !isAbsolute(destPath)) {
90
111
  return {
@@ -134,6 +155,7 @@ class HostFileTransferTool implements Tool {
134
155
  destPath,
135
156
  overwrite,
136
157
  conversationId: context.conversationId,
158
+ targetClientId,
137
159
  },
138
160
  context.signal,
139
161
  );
@@ -144,11 +166,19 @@ class HostFileTransferTool implements Tool {
144
166
  destPath: resolvedDestPath,
145
167
  overwrite,
146
168
  conversationId: context.conversationId,
169
+ targetClientId,
147
170
  },
148
171
  context.signal,
149
172
  );
150
173
  }
151
174
 
175
+ if (targetClientId != null) {
176
+ return {
177
+ content: `Error: target_client_id '${targetClientId}' was specified but no host client is available. Ensure the client is connected.`,
178
+ isError: true,
179
+ };
180
+ }
181
+
152
182
  // Local mode: direct filesystem copy.
153
183
  return this.executeLocal(resolvedSourcePath, resolvedDestPath, overwrite);
154
184
  }
@@ -1,6 +1,8 @@
1
+ import { supportsHostProxy } from "../../channels/types.js";
1
2
  import { HostFileProxy } from "../../daemon/host-file-proxy.js";
2
3
  import { RiskLevel } from "../../permissions/types.js";
3
4
  import type { ToolDefinition } from "../../providers/types.js";
5
+ import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
4
6
  import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
5
7
  import { formatWriteSummary } from "../shared/filesystem/format-diff.js";
6
8
  import { hostPolicy } from "../shared/filesystem/path-policy.js";
@@ -28,6 +30,11 @@ class HostFileWriteTool implements Tool {
28
30
  type: "string",
29
31
  description: "The content to write to the file",
30
32
  },
33
+ target_client_id: {
34
+ type: "string",
35
+ description:
36
+ "ID of the specific client to execute this on. Required when multiple clients support host_file; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_file`.",
37
+ },
31
38
  },
32
39
  required: ["path", "content"],
33
40
  },
@@ -54,6 +61,24 @@ class HostFileWriteTool implements Tool {
54
61
  };
55
62
  }
56
63
 
64
+ const targetClientId =
65
+ typeof input.target_client_id === "string" && input.target_client_id !== ""
66
+ ? input.target_client_id
67
+ : undefined;
68
+
69
+ const transportInterface = context.transportInterface;
70
+ if (
71
+ targetClientId == null &&
72
+ transportInterface != null &&
73
+ !supportsHostProxy(transportInterface) &&
74
+ assistantEventHub.listClientsByCapability("host_file").length > 1
75
+ ) {
76
+ return {
77
+ content: `Error: multiple clients support host_file. Specify which client to use with \`target_client_id\`. Run \`assistant clients list --capability host_file\` to see client IDs and labels.`,
78
+ isError: true,
79
+ };
80
+ }
81
+
57
82
  // Proxy to connected client for execution on the user's machine
58
83
  // when a capable client is available (managed/cloud-hosted mode).
59
84
  if (HostFileProxy.instance.isAvailable()) {
@@ -62,6 +87,7 @@ class HostFileWriteTool implements Tool {
62
87
  operation: "write",
63
88
  path: rawPath,
64
89
  content: fileContent,
90
+ targetClientId,
65
91
  },
66
92
  context.conversationId,
67
93
  context.signal,
@@ -18,6 +18,7 @@ import { existsSync } from "node:fs";
18
18
  import { homedir } from "node:os";
19
19
  import { isAbsolute } from "node:path";
20
20
 
21
+ import { supportsHostProxy } from "../../channels/types.js";
21
22
  import { getConfig } from "../../config/loader.js";
22
23
  import { isCesShellLockdownEnabled } from "../../credential-execution/feature-gates.js";
23
24
  import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
@@ -25,6 +26,7 @@ import { RiskLevel } from "../../permissions/types.js";
25
26
  import type { ToolDefinition } from "../../providers/types.js";
26
27
  import { isUntrustedTrustClass } from "../../runtime/actor-trust-resolver.js";
27
28
  import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
29
+ import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
28
30
  import { redactSecrets } from "../../security/secret-scanner.js";
29
31
  import { getLogger } from "../../util/logger.js";
30
32
  import {
@@ -131,6 +133,11 @@ class HostShellTool implements Tool {
131
133
  description:
132
134
  "Run the command in the background on the host machine. The tool returns immediately with a background tool ID. When the process exits, its output is delivered to the conversation as a wake.",
133
135
  },
136
+ target_client_id: {
137
+ type: "string",
138
+ description:
139
+ "ID of the specific client to execute this command on. Required when multiple clients support host_bash; omit when only one client is connected. Obtain IDs from `assistant clients list --capability host_bash`.",
140
+ },
134
141
  },
135
142
  required: ["command", "activity"],
136
143
  },
@@ -173,6 +180,11 @@ class HostShellTool implements Tool {
173
180
  }
174
181
  const background = input.background === true;
175
182
 
183
+ const targetClientId =
184
+ typeof input.target_client_id === "string" && input.target_client_id !== ""
185
+ ? input.target_client_id
186
+ : undefined;
187
+
176
188
  const config = getConfig();
177
189
  const { shellDefaultTimeoutSec, shellMaxTimeoutSec } = config.timeouts;
178
190
 
@@ -190,6 +202,50 @@ class HostShellTool implements Tool {
190
202
  isCesShellLockdownEnabled(config) &&
191
203
  isUntrustedTrustClass(context.trustClass);
192
204
 
205
+ // Guard: non-host-proxy interfaces need an explicit target when multiple
206
+ // capable clients are connected to avoid ambiguous untargeted broadcasts.
207
+ const transportInterface = context.transportInterface;
208
+ if (
209
+ targetClientId == null &&
210
+ transportInterface != null &&
211
+ !supportsHostProxy(transportInterface) &&
212
+ assistantEventHub.listClientsByCapability("host_bash").length > 1
213
+ ) {
214
+ return {
215
+ content: `Error: multiple clients support host_bash. Specify which client to use with \`target_client_id\`. Run \`assistant clients list --capability host_bash\` to see client IDs and labels.`,
216
+ isError: true,
217
+ };
218
+ }
219
+
220
+ // Guard: non-host-proxy interfaces with no capable clients connected.
221
+ if (
222
+ targetClientId == null &&
223
+ transportInterface != null &&
224
+ !supportsHostProxy(transportInterface) &&
225
+ !HostBashProxy.instance.isAvailable()
226
+ ) {
227
+ return {
228
+ content:
229
+ "Error: no client with host_bash capability is connected. Connect a macOS client to use host_bash from a non-desktop interface.",
230
+ isError: true,
231
+ };
232
+ }
233
+
234
+ // Guard: explicit targetClientId provided but proxy is unavailable (client
235
+ // disconnected between tool-definition and tool-execution). Without this
236
+ // guard both targetClientId != null guards above are bypassed, and the
237
+ // code falls through to local daemon execution — silently running commands
238
+ // inside the Docker container instead of on the intended host machine.
239
+ if (
240
+ targetClientId != null &&
241
+ !HostBashProxy.instance.isAvailable()
242
+ ) {
243
+ return {
244
+ content: `Error: target client "${targetClientId}" is no longer connected. The specified client may have disconnected since the tool was called. Run \`assistant clients list --capability host_bash\` to see currently connected clients.`,
245
+ isError: true,
246
+ };
247
+ }
248
+
193
249
  // Proxy to connected client for execution on the user's machine
194
250
  // when a capable client is available (managed/cloud-hosted mode).
195
251
  if (HostBashProxy.instance.isAvailable()) {
@@ -227,6 +283,7 @@ class HostShellTool implements Tool {
227
283
  working_dir: rawWorkingDir as string | undefined,
228
284
  timeout_seconds: normalizedTimeout,
229
285
  env: proxyEnv,
286
+ targetClientId,
230
287
  },
231
288
  context.conversationId,
232
289
  abortController.signal,
@@ -273,6 +330,7 @@ class HostShellTool implements Tool {
273
330
  working_dir: rawWorkingDir as string | undefined,
274
331
  timeout_seconds: normalizedTimeout,
275
332
  env: proxyEnv,
333
+ targetClientId,
276
334
  },
277
335
  context.conversationId,
278
336
  context.signal,
@@ -44,6 +44,8 @@ export async function executeScheduleCreate(
44
44
  | undefined;
45
45
  const quiet = (input.quiet as boolean) ?? false;
46
46
  const reuseConversation = (input.reuse_conversation as boolean) ?? false;
47
+ const maxRetries = input.max_retries as number | undefined;
48
+ const retryBackoffMs = input.retry_backoff_ms as number | undefined;
47
49
 
48
50
  if (!name || typeof name !== "string") {
49
51
  return {
@@ -130,6 +132,8 @@ export async function executeScheduleCreate(
130
132
  routingHints,
131
133
  quiet,
132
134
  reuseConversation,
135
+ maxRetries,
136
+ retryBackoffMs,
133
137
  });
134
138
 
135
139
  const fireDate = formatLocalDate(job.nextRunAt);
@@ -208,6 +212,8 @@ export async function executeScheduleCreate(
208
212
  routingHints,
209
213
  quiet,
210
214
  reuseConversation,
215
+ maxRetries,
216
+ retryBackoffMs,
211
217
  });
212
218
 
213
219
  const scheduleDescription =
@@ -77,6 +77,8 @@ export async function executeScheduleList(
77
77
  ` Last run: ${job.lastRunAt ? formatLocalDate(job.lastRunAt) : "never"}`,
78
78
  ` Last status: ${job.lastStatus ?? "n/a"}`,
79
79
  ` Retry count: ${job.retryCount}`,
80
+ ` Max retries: ${job.maxRetries}`,
81
+ ` Retry backoff: ${job.retryBackoffMs}ms`,
80
82
  ` Created: ${formatLocalDate(job.createdAt)}`,
81
83
  );
82
84
 
@@ -108,6 +108,14 @@ export async function executeScheduleUpdate(
108
108
  updates.reuseConversation = input.reuse_conversation;
109
109
  }
110
110
 
111
+ // Retry policy
112
+ if (input.max_retries !== undefined) {
113
+ updates.maxRetries = input.max_retries;
114
+ }
115
+ if (input.retry_backoff_ms !== undefined) {
116
+ updates.retryBackoffMs = input.retry_backoff_ms;
117
+ }
118
+
111
119
  // Auto-detect syntax when expression changes without explicit syntax
112
120
  if (input.expression !== undefined || input.syntax !== undefined) {
113
121
  const resolved = normalizeScheduleSyntax({
@@ -173,6 +181,8 @@ export async function executeScheduleUpdate(
173
181
  routingHints?: Record<string, unknown>;
174
182
  quiet?: boolean;
175
183
  reuseConversation?: boolean;
184
+ maxRetries?: number;
185
+ retryBackoffMs?: number;
176
186
  },
177
187
  );
178
188
 
@@ -52,6 +52,8 @@ function pathError(
52
52
  return Err.pathNotAbsolute(path);
53
53
  case "out_of_bounds":
54
54
  return { code: "PATH_OUT_OF_BOUNDS", message: detail, path };
55
+ case "denied":
56
+ return { code: "PATH_OUT_OF_BOUNDS", message: detail, path };
55
57
  }
56
58
  }
57
59
 
@@ -11,7 +11,14 @@ import {
11
11
  /**
12
12
  * Result type shared by both sandbox and host path policies.
13
13
  */
14
- export type PathFailureReason = "not_absolute" | "out_of_bounds";
14
+ export type PathFailureReason = "not_absolute" | "out_of_bounds" | "denied";
15
+
16
+ /**
17
+ * Basenames that must never be read or written by the assistant, regardless
18
+ * of where they resolve. Defense-in-depth: even if a key file is accidentally
19
+ * placed inside the workspace boundary, the assistant cannot access it.
20
+ */
21
+ const DENIED_BASENAMES = new Set([".backup.key", "backup.key"]);
15
22
 
16
23
  export type PathResult =
17
24
  | { ok: true; resolved: string }
@@ -106,6 +113,16 @@ export function sandboxPolicy(
106
113
  };
107
114
  }
108
115
 
116
+ // Check both the logical path and the symlink-resolved path so a symlink
117
+ // with a non-denied name pointing at a denied file is still caught.
118
+ if (DENIED_BASENAMES.has(basename(resolved)) || DENIED_BASENAMES.has(basename(realResolved))) {
119
+ return {
120
+ ok: false,
121
+ reason: "denied",
122
+ error: `Access to "${basename(resolved)}" is denied`,
123
+ };
124
+ }
125
+
109
126
  return { ok: true, resolved };
110
127
  }
111
128
 
@@ -125,5 +142,12 @@ export function hostPolicy(rawPath: string): PathResult {
125
142
  error: `path must be absolute for host file access: ${rawPath}`,
126
143
  };
127
144
  }
145
+ if (DENIED_BASENAMES.has(basename(rawPath))) {
146
+ return {
147
+ ok: false,
148
+ reason: "denied",
149
+ error: `Access to "${basename(rawPath)}" is denied`,
150
+ };
151
+ }
128
152
  return { ok: true, resolved: rawPath };
129
153
  }
@@ -29,9 +29,6 @@ import { getWorkspaceDirDisplay } from "../../util/platform.js";
29
29
  import { registerTool } from "../registry.js";
30
30
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
31
31
 
32
- /** Canonical feature flag key for inline skill command expansion. */
33
- const INLINE_COMMANDS_FLAG_KEY = "inline-skill-commands";
34
-
35
32
  /** Skill sources eligible for inline command expansion in v1. */
36
33
  const INLINE_COMMAND_ELIGIBLE_SOURCES = new Set([
37
34
  "bundled",
@@ -300,20 +297,6 @@ export class SkillLoadTool implements Tool {
300
297
  skill.inlineCommandExpansions && skill.inlineCommandExpansions.length > 0;
301
298
 
302
299
  if (hasInlineCommands) {
303
- const inlineFlagEnabled = isAssistantFeatureFlagEnabled(
304
- INLINE_COMMANDS_FLAG_KEY,
305
- config,
306
- );
307
-
308
- if (!inlineFlagEnabled) {
309
- // Feature flag is off: fail closed instead of leaving live tokens in
310
- // the prompt that the LLM might try to interpret.
311
- return {
312
- content: `Error: skill "${skill.id}" contains inline command expansions but the inline-skill-commands feature flag is disabled. Enable the flag to use this skill.`,
313
- isError: true,
314
- };
315
- }
316
-
317
300
  if (skill.source === "extra") {
318
301
  // Third-party extra roots are out of scope for inline command
319
302
  // expansion in v1. Reject explicitly so the failure is clear.
@@ -391,21 +374,6 @@ export class SkillLoadTool implements Tool {
391
374
  childLoaded.skill.inlineCommandExpansions.length > 0;
392
375
 
393
376
  if (childHasInlineCommands) {
394
- const childInlineFlagEnabled = isAssistantFeatureFlagEnabled(
395
- INLINE_COMMANDS_FLAG_KEY,
396
- config,
397
- );
398
-
399
- // Fail closed: if the flag is off, reject the entire skill_load
400
- // just like we do for root skills. Leaving raw !`...` tokens in
401
- // the prompt would violate the documented fail-closed contract.
402
- if (!childInlineFlagEnabled) {
403
- return {
404
- content: `Error: included skill "${childId}" contains inline command expansions but the inline-skill-commands feature flag is disabled. Enable the flag to use skill "${skill.id}".`,
405
- isError: true,
406
- };
407
- }
408
-
409
377
  if (childLoaded.skill.source === "extra") {
410
378
  return {
411
379
  content: `Error: included skill "${childId}" contains inline command expansions but inline commands are not supported for third-party (extra) skill sources.`,