@vellumai/assistant 0.6.2 → 0.6.3

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 (396) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docs/architecture/memory.md +1 -1
  4. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  5. package/openapi.yaml +184 -69
  6. package/package.json +41 -41
  7. package/scripts/generate-openapi.ts +1 -2
  8. package/src/__tests__/acp-session.test.ts +43 -0
  9. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  10. package/src/__tests__/app-executors.test.ts +1 -0
  11. package/src/__tests__/app-source-watcher.test.ts +37 -11
  12. package/src/__tests__/approval-routes-http.test.ts +178 -1
  13. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  14. package/src/__tests__/browser-manager.test.ts +40 -27
  15. package/src/__tests__/catalog-files.test.ts +862 -0
  16. package/src/__tests__/channel-approvals.test.ts +53 -0
  17. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  18. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  19. package/src/__tests__/config-schema.test.ts +125 -48
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  21. package/src/__tests__/context-overflow-approval.test.ts +16 -1
  22. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  24. package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
  25. package/src/__tests__/conversation-attachments.test.ts +80 -4
  26. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  27. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  28. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  29. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  30. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  31. package/src/__tests__/conversation-queue.test.ts +45 -2
  32. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  33. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  34. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  35. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  36. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  37. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  38. package/src/__tests__/conversation-store.test.ts +195 -0
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  40. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
  41. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  42. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  43. package/src/__tests__/credential-vault.test.ts +152 -13
  44. package/src/__tests__/credentials-cli.test.ts +2 -2
  45. package/src/__tests__/date-context.test.ts +4 -4
  46. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  47. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  48. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  49. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  50. package/src/__tests__/gemini-provider.test.ts +2 -2
  51. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  52. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  53. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  54. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  55. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  56. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  57. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  58. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  59. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  60. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  61. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  62. package/src/__tests__/host-browser-routes.test.ts +198 -0
  63. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  64. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  65. package/src/__tests__/host-file-proxy.test.ts +185 -1
  66. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  67. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  68. package/src/__tests__/host-shell-tool.test.ts +1 -11
  69. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  70. package/src/__tests__/integration-status.test.ts +6 -7
  71. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  72. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  73. package/src/__tests__/mcp-health-check.test.ts +10 -3
  74. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  75. package/src/__tests__/migration-export-http.test.ts +61 -2
  76. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  77. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  78. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  79. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  80. package/src/__tests__/oauth-cli.test.ts +707 -60
  81. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  82. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  83. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  84. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  85. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  86. package/src/__tests__/oauth-store.test.ts +1386 -182
  87. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  88. package/src/__tests__/onboarding-template-contract.test.ts +75 -57
  89. package/src/__tests__/openai-provider.test.ts +2 -2
  90. package/src/__tests__/outlook-categories.test.ts +1 -1
  91. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  92. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  93. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  94. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  95. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  96. package/src/__tests__/outlook-trash.test.ts +1 -1
  97. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  98. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  99. package/src/__tests__/permission-mode.test.ts +28 -56
  100. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  101. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  102. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  103. package/src/__tests__/require-fresh-approval.test.ts +40 -1
  104. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  105. package/src/__tests__/schedule-routes.test.ts +162 -0
  106. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  107. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  108. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  109. package/src/__tests__/set-permission-mode.test.ts +13 -250
  110. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  111. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  112. package/src/__tests__/slack-channel-config.test.ts +12 -15
  113. package/src/__tests__/subagent-detail.test.ts +44 -2
  114. package/src/__tests__/subagent-disposal.test.ts +1 -0
  115. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  116. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  117. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  118. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  119. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  120. package/src/__tests__/subagent-tools.test.ts +1 -0
  121. package/src/__tests__/subagent-types.test.ts +1 -0
  122. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  123. package/src/__tests__/system-prompt.test.ts +72 -1
  124. package/src/__tests__/task-scheduler.test.ts +32 -6
  125. package/src/__tests__/telegram-config.test.ts +10 -13
  126. package/src/__tests__/terminal-tools.test.ts +9 -0
  127. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  128. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  129. package/src/__tests__/top-level-renderer.test.ts +73 -1
  130. package/src/__tests__/transport-hints-queue.test.ts +14 -29
  131. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  132. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  133. package/src/acp/client-handler.ts +30 -4
  134. package/src/agent/loop.ts +12 -6
  135. package/src/approvals/guardian-request-resolvers.ts +21 -15
  136. package/src/browser-session/__tests__/manager.test.ts +297 -0
  137. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  138. package/src/browser-session/backends/extension.ts +26 -0
  139. package/src/browser-session/backends/local.ts +24 -0
  140. package/src/browser-session/events.ts +164 -0
  141. package/src/browser-session/index.ts +27 -0
  142. package/src/browser-session/manager.ts +159 -0
  143. package/src/browser-session/types.ts +28 -0
  144. package/src/channels/__tests__/types.test.ts +134 -0
  145. package/src/channels/types.ts +53 -3
  146. package/src/cli/commands/browser-relay.ts +339 -409
  147. package/src/cli/commands/credentials.ts +3 -3
  148. package/src/cli/commands/email.ts +18 -13
  149. package/src/cli/commands/mcp.ts +16 -4
  150. package/src/cli/commands/oauth/__tests__/connect.test.ts +44 -44
  151. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  152. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  153. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  154. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  155. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  156. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  157. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  158. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  159. package/src/cli/commands/oauth/apps.ts +7 -4
  160. package/src/cli/commands/oauth/connect.ts +6 -3
  161. package/src/cli/commands/oauth/disconnect.ts +1 -1
  162. package/src/cli/commands/oauth/providers.ts +200 -36
  163. package/src/cli/commands/oauth/shared.ts +5 -5
  164. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  165. package/src/cli/commands/platform/index.ts +107 -10
  166. package/src/cli/commands/usage.ts +10 -9
  167. package/src/cli/lib/daemon-credential-client.ts +4 -0
  168. package/src/cli/program.ts +1 -1
  169. package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
  170. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  171. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  172. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  173. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  174. package/src/config/bundled-skills/document/SKILL.md +4 -0
  175. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  176. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  177. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  178. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  179. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  180. package/src/config/env-registry.ts +14 -0
  181. package/src/config/env.ts +21 -0
  182. package/src/config/feature-flag-registry.json +44 -5
  183. package/src/config/loader.ts +56 -1
  184. package/src/config/sanitize-for-transfer.ts +47 -0
  185. package/src/config/schema.ts +46 -5
  186. package/src/config/schemas/host-browser.ts +66 -0
  187. package/src/config/schemas/memory-lifecycle.ts +1 -1
  188. package/src/config/schemas/memory-retrieval.ts +103 -0
  189. package/src/config/schemas/security.ts +0 -6
  190. package/src/config/schemas/services.ts +8 -0
  191. package/src/config/types.ts +0 -1
  192. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  193. package/src/context/window-manager.ts +19 -1
  194. package/src/credential-execution/approval-bridge.ts +49 -15
  195. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  196. package/src/daemon/app-source-watcher.ts +35 -0
  197. package/src/daemon/context-overflow-approval.ts +5 -0
  198. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  199. package/src/daemon/conversation-agent-loop.ts +58 -24
  200. package/src/daemon/conversation-attachments.ts +40 -0
  201. package/src/daemon/conversation-process.ts +48 -1
  202. package/src/daemon/conversation-runtime-assembly.ts +118 -36
  203. package/src/daemon/conversation-surfaces.ts +37 -36
  204. package/src/daemon/conversation-tool-setup.ts +74 -8
  205. package/src/daemon/conversation-workspace.ts +12 -0
  206. package/src/daemon/conversation.ts +226 -8
  207. package/src/daemon/date-context.ts +10 -10
  208. package/src/daemon/first-greeting.ts +3 -2
  209. package/src/daemon/handlers/conversations.ts +9 -140
  210. package/src/daemon/handlers/shared.ts +58 -0
  211. package/src/daemon/handlers/skills.ts +232 -37
  212. package/src/daemon/host-bash-proxy.ts +48 -13
  213. package/src/daemon/host-browser-proxy.ts +191 -0
  214. package/src/daemon/host-cu-proxy.ts +36 -11
  215. package/src/daemon/host-file-proxy.ts +57 -9
  216. package/src/daemon/lifecycle.ts +65 -11
  217. package/src/daemon/message-protocol.ts +7 -0
  218. package/src/daemon/message-types/conversations.ts +55 -13
  219. package/src/daemon/message-types/host-browser.ts +100 -0
  220. package/src/daemon/message-types/messages.ts +5 -5
  221. package/src/daemon/message-types/skills.ts +10 -0
  222. package/src/daemon/message-types/subagents.ts +2 -0
  223. package/src/daemon/server.ts +92 -12
  224. package/src/daemon/tool-side-effects.ts +6 -0
  225. package/src/daemon/transport-hints.ts +5 -24
  226. package/src/inbound/platform-callback-registration.ts +18 -17
  227. package/src/mcp/client.ts +59 -24
  228. package/src/memory/app-store.ts +31 -1
  229. package/src/memory/conversation-crud.ts +23 -0
  230. package/src/memory/conversation-starters-cadence.ts +76 -0
  231. package/src/memory/conversation-title-service.ts +5 -2
  232. package/src/memory/db-init.ts +12 -0
  233. package/src/memory/embedding-backend.test.ts +75 -0
  234. package/src/memory/embedding-backend.ts +131 -5
  235. package/src/memory/embedding-gemini.test.ts +54 -0
  236. package/src/memory/embedding-gemini.ts +20 -9
  237. package/src/memory/embedding-local.ts +176 -17
  238. package/src/memory/graph/consolidation.ts +10 -23
  239. package/src/memory/graph/extraction-job.ts +15 -0
  240. package/src/memory/graph/retriever.ts +40 -22
  241. package/src/memory/graph/store.test.ts +7 -3
  242. package/src/memory/graph/store.ts +47 -12
  243. package/src/memory/llm-usage-store.ts +45 -4
  244. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  245. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  246. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  247. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  248. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  249. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  250. package/src/memory/migrations/index.ts +6 -0
  251. package/src/memory/migrations/registry.ts +8 -0
  252. package/src/memory/schema/conversations.ts +1 -0
  253. package/src/memory/schema/oauth.ts +18 -13
  254. package/src/oauth/AGENTS.md +76 -0
  255. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  256. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  257. package/src/oauth/byo-connection.test.ts +8 -8
  258. package/src/oauth/byo-connection.ts +7 -7
  259. package/src/oauth/connect-orchestrator.ts +23 -21
  260. package/src/oauth/connect-types.ts +3 -3
  261. package/src/oauth/connection-resolver.test.ts +17 -4
  262. package/src/oauth/connection-resolver.ts +16 -16
  263. package/src/oauth/connection.ts +1 -1
  264. package/src/oauth/manual-token-connection.ts +13 -13
  265. package/src/oauth/oauth-store.ts +214 -100
  266. package/src/oauth/platform-connection.test.ts +3 -3
  267. package/src/oauth/platform-connection.ts +4 -4
  268. package/src/oauth/provider-serializer.ts +31 -5
  269. package/src/oauth/revoke.ts +76 -0
  270. package/src/oauth/seed-providers.ts +126 -87
  271. package/src/oauth/token-persistence.ts +1 -1
  272. package/src/permissions/permission-mode.ts +4 -11
  273. package/src/permissions/prompter.ts +13 -1
  274. package/src/permissions/v2-consent-policy.ts +87 -0
  275. package/src/prompts/system-prompt.ts +18 -21
  276. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  277. package/src/prompts/templates/BOOTSTRAP.md +59 -105
  278. package/src/providers/anthropic/client.ts +1 -0
  279. package/src/providers/types.ts +1 -1
  280. package/src/runtime/AGENTS.md +23 -0
  281. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  282. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  283. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  284. package/src/runtime/assistant-event-hub.ts +2 -2
  285. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  286. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  287. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  288. package/src/runtime/auth/middleware.ts +98 -0
  289. package/src/runtime/auth/route-policy.ts +6 -7
  290. package/src/runtime/capability-tokens.ts +414 -0
  291. package/src/runtime/channel-approvals.ts +18 -5
  292. package/src/runtime/chrome-extension-registry.ts +332 -0
  293. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  294. package/src/runtime/guardian-decision-types.ts +7 -0
  295. package/src/runtime/http-server.ts +425 -70
  296. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  297. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  298. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  299. package/src/runtime/migrations/migration-transport.ts +6 -0
  300. package/src/runtime/migrations/migration-wizard.ts +22 -2
  301. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  302. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  303. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  304. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  305. package/src/runtime/pending-interactions.ts +29 -13
  306. package/src/runtime/routes/approval-routes.ts +90 -16
  307. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  308. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  309. package/src/runtime/routes/conversation-analysis-routes.ts +2 -1
  310. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  311. package/src/runtime/routes/conversation-routes.ts +301 -27
  312. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  313. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  314. package/src/runtime/routes/host-browser-routes.ts +279 -0
  315. package/src/runtime/routes/host-file-routes.ts +9 -1
  316. package/src/runtime/routes/identity-routes.ts +259 -16
  317. package/src/runtime/routes/log-export-routes.ts +42 -22
  318. package/src/runtime/routes/memory-item-routes.ts +1 -7
  319. package/src/runtime/routes/migration-routes.ts +87 -2
  320. package/src/runtime/routes/oauth-apps.ts +15 -17
  321. package/src/runtime/routes/oauth-providers.ts +4 -0
  322. package/src/runtime/routes/schedule-routes.ts +24 -11
  323. package/src/runtime/routes/settings-routes.ts +9 -97
  324. package/src/runtime/routes/skills-routes.ts +52 -2
  325. package/src/runtime/routes/subagents-routes.ts +14 -10
  326. package/src/runtime/routes/usage-routes.ts +8 -7
  327. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  328. package/src/runtime/routes/workspace-routes.ts +8 -1
  329. package/src/runtime/routes/workspace-utils.ts +2 -0
  330. package/src/schedule/scheduler.ts +7 -5
  331. package/src/security/ces-credential-client.ts +20 -0
  332. package/src/security/ces-rpc-credential-backend.ts +17 -0
  333. package/src/security/credential-backend.ts +5 -0
  334. package/src/security/oauth2.ts +42 -25
  335. package/src/security/secure-keys.ts +118 -25
  336. package/src/security/token-manager.ts +23 -10
  337. package/src/skills/catalog-files.ts +492 -0
  338. package/src/subagent/manager.ts +131 -26
  339. package/src/subagent/types.ts +19 -0
  340. package/src/tools/apps/executors.ts +11 -2
  341. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  342. package/src/tools/browser/auth-detector.ts +43 -12
  343. package/src/tools/browser/browser-execution.ts +645 -340
  344. package/src/tools/browser/browser-manager.ts +36 -12
  345. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  346. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  347. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  348. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  349. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  350. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  351. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  352. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  353. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  354. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  355. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  356. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  357. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  358. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  359. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  360. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  361. package/src/tools/browser/cdp-client/errors.ts +34 -0
  362. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  363. package/src/tools/browser/cdp-client/factory.ts +204 -0
  364. package/src/tools/browser/cdp-client/index.ts +14 -0
  365. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  366. package/src/tools/browser/cdp-client/types.ts +52 -0
  367. package/src/tools/filesystem/edit.ts +1 -1
  368. package/src/tools/filesystem/list.ts +1 -1
  369. package/src/tools/filesystem/read.ts +1 -1
  370. package/src/tools/filesystem/write.ts +2 -1
  371. package/src/tools/host-filesystem/edit.ts +1 -1
  372. package/src/tools/host-filesystem/read.ts +12 -15
  373. package/src/tools/host-filesystem/write.ts +1 -1
  374. package/src/tools/host-terminal/host-shell.ts +21 -16
  375. package/src/tools/permission-checker.ts +77 -82
  376. package/src/tools/registry.ts +0 -2
  377. package/src/tools/secret-detection-handler.ts +34 -0
  378. package/src/tools/shared/filesystem/image-read.ts +61 -40
  379. package/src/tools/subagent/spawn.ts +47 -3
  380. package/src/tools/subagent/status.ts +2 -0
  381. package/src/tools/system/register.ts +2 -16
  382. package/src/tools/terminal/safe-env.ts +7 -0
  383. package/src/tools/terminal/shell.ts +21 -16
  384. package/src/tools/tool-approval-handler.ts +48 -2
  385. package/src/tools/types.ts +2 -0
  386. package/src/util/platform.ts +14 -19
  387. package/src/workspace/top-level-renderer.ts +19 -1
  388. package/src/__tests__/chrome-cdp.test.ts +0 -419
  389. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  390. package/src/__tests__/permission-mode-store.test.ts +0 -277
  391. package/src/browser-extension-relay/protocol.ts +0 -63
  392. package/src/browser-extension-relay/server.ts +0 -203
  393. package/src/config/schemas/sandbox.ts +0 -14
  394. package/src/permissions/permission-mode-store.ts +0 -180
  395. package/src/tools/browser/chrome-cdp.ts +0 -239
  396. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -1,6 +1,11 @@
1
1
  // Conversation lifecycle, auth, model config, and history types.
2
2
 
3
- import type { ChannelId, InterfaceId } from "../../channels/types.js";
3
+ import type {
4
+ ChannelId,
5
+ HostProxyInterfaceId,
6
+ InterfaceId,
7
+ } from "../../channels/types.js";
8
+ import { supportsHostProxy } from "../../channels/types.js";
4
9
  import type { ConversationType } from "./shared.js";
5
10
  import type { UserMessageAttachment } from "./shared.js";
6
11
 
@@ -26,26 +31,61 @@ interface BaseTransportMetadata {
26
31
  chatType?: string;
27
32
  }
28
33
 
29
- /** Transport metadata for macOS desktop clients, including host environment fields. */
30
- export interface MacosTransportMetadata extends BaseTransportMetadata {
31
- /** Interface identifier for macOS transport. */
32
- interfaceId: "macos";
33
- /** Home directory of the host macOS user. */
34
+ /**
35
+ * Transport metadata for interfaces that support the full desktop host-proxy
36
+ * set (see `HostProxyInterfaceId` / `supportsHostProxy`). Carries the host
37
+ * environment fields the client reports so the `<workspace>` block renders
38
+ * the user's actual machine rather than a containerized daemon's own OS.
39
+ *
40
+ * Today this variant is populated only by the macOS client, but the shape
41
+ * is capability-keyed (not interface-name-keyed) so future host-capable
42
+ * clients (e.g. a native Linux or Windows desktop) get the same treatment
43
+ * automatically when added to `HostProxyInterfaceId`.
44
+ */
45
+ export interface HostProxyTransportMetadata extends BaseTransportMetadata {
46
+ /** Interface identifier — restricted to interfaces that support host proxies. */
47
+ interfaceId: HostProxyInterfaceId;
48
+ /** Home directory of the user on the host machine (e.g. `NSHomeDirectory()`). */
34
49
  hostHomeDir?: string;
35
- /** Username of the host macOS user. */
50
+ /** Username of the user on the host machine (e.g. `NSUserName()`). */
36
51
  hostUsername?: string;
37
52
  }
38
53
 
39
- /** Transport metadata for non-macOS transports. */
40
- export interface NonMacosTransportMetadata extends BaseTransportMetadata {
54
+ /**
55
+ * Transport metadata for interfaces that do NOT support host-proxy tools
56
+ * (iOS, CLI, channel ingress, chrome-extension, etc.). No host environment
57
+ * because the assistant has no local filesystem to address on the client.
58
+ */
59
+ export interface NonHostProxyTransportMetadata extends BaseTransportMetadata {
41
60
  /** Interface identifier for this transport (e.g. "ios", "cli"). */
42
- interfaceId?: Exclude<InterfaceId, "macos">;
61
+ interfaceId?: Exclude<InterfaceId, HostProxyInterfaceId>;
43
62
  }
44
63
 
45
- /** Lightweight conversation transport metadata for channel identity and natural-language guidance. */
64
+ /**
65
+ * Discriminated union of transport metadata variants, keyed on whether the
66
+ * interface supports host-proxy tools (`supportsHostProxy`). The daemon uses
67
+ * that same predicate at runtime to decide whether to populate / read host
68
+ * environment fields on the conversation, so the type system and the runtime
69
+ * gate stay in lock-step as new host-capable interfaces are added.
70
+ */
46
71
  export type ConversationTransportMetadata =
47
- | MacosTransportMetadata
48
- | NonMacosTransportMetadata;
72
+ | HostProxyTransportMetadata
73
+ | NonHostProxyTransportMetadata;
74
+
75
+ /**
76
+ * Type guard: does this transport belong to an interface that supports the
77
+ * full host-proxy set? Wraps `supportsHostProxy` so the capability logic
78
+ * stays in one place (channels/types.ts) and narrows the discriminated
79
+ * union to `HostProxyTransportMetadata` for safe field access.
80
+ */
81
+ export function isHostProxyTransport(
82
+ transport: ConversationTransportMetadata,
83
+ ): transport is HostProxyTransportMetadata {
84
+ return (
85
+ transport.interfaceId !== undefined &&
86
+ supportsHostProxy(transport.interfaceId)
87
+ );
88
+ }
49
89
 
50
90
  export interface ConversationCreateRequest {
51
91
  type: "conversation_create";
@@ -171,6 +211,7 @@ export interface ConversationInfo {
171
211
  title: string;
172
212
  correlationId?: string;
173
213
  conversationType?: ConversationType;
214
+ hostAccess: boolean;
174
215
  }
175
216
 
176
217
  export interface ConversationTitleUpdated {
@@ -212,6 +253,7 @@ export interface ConversationListResponse {
212
253
  updatedAt: number;
213
254
  conversationType?: ConversationType;
214
255
  source?: string;
256
+ hostAccess: boolean;
215
257
  scheduleJobId?: string;
216
258
  channelBinding?: ChannelBinding;
217
259
  conversationOriginChannel?: ChannelId;
@@ -0,0 +1,100 @@
1
+ // Host browser proxy types.
2
+ // Enables proxying CDP commands to the desktop client (host machine)
3
+ // when running as a managed assistant.
4
+
5
+ // === Server → Client ===
6
+
7
+ export interface HostBrowserRequest {
8
+ type: "host_browser_request";
9
+ requestId: string;
10
+ conversationId: string;
11
+ /** CDP method name, e.g. "Page.navigate", "Runtime.evaluate", "Accessibility.getFullAXTree". */
12
+ cdpMethod: string;
13
+ /** Opaque JSON params object forwarded verbatim to CDP. */
14
+ cdpParams?: Record<string, unknown>;
15
+ /** Optional CDP target/session ID; omitted = "most-recently-active tab". */
16
+ cdpSessionId?: string;
17
+ /** Client-side timeout hint; defaults to 30s in the proxy. */
18
+ timeout_seconds?: number;
19
+ }
20
+
21
+ export interface HostBrowserCancelRequest {
22
+ type: "host_browser_cancel";
23
+ requestId: string;
24
+ }
25
+
26
+ // === Client → Server ===
27
+
28
+ /**
29
+ * Unsolicited CDP event forwarded from the chrome extension to the
30
+ * runtime. The extension subscribes to `chrome.debugger.onEvent` and
31
+ * pushes each event here so the runtime can observe lifecycle signals
32
+ * (e.g. `Target.targetDestroyed`, `Page.frameNavigated`,
33
+ * `Network.requestWillBeSent`) without having to round-trip a CDP
34
+ * command. Events are routed through the relay WebSocket using the
35
+ * same envelope vocabulary as `host_browser_result`.
36
+ *
37
+ * The envelope is transport-level only — the runtime dispatcher in
38
+ * `resolveHostBrowserEvent` fans out into a module-level event bus
39
+ * that tool-side consumers (currently just the
40
+ * BrowserSessionRegistry) subscribe to by method name. No request/
41
+ * response contract is implied; events can arrive at any time while
42
+ * a chrome extension is attached and there is no ordering guarantee
43
+ * relative to `host_browser_result` frames.
44
+ */
45
+ export interface HostBrowserEvent {
46
+ type: "host_browser_event";
47
+ /** CDP event method name, e.g. "Page.frameNavigated", "Target.targetDestroyed". */
48
+ method: string;
49
+ /** CDP event params forwarded verbatim. Opaque to the runtime. */
50
+ params?: unknown;
51
+ /**
52
+ * Optional CDP session id — populated for flat child sessions
53
+ * routed through `Target.attachToTarget` with `flatten: true`.
54
+ * Matches the `source.sessionId` field surfaced by Chrome 125+ in
55
+ * its `chrome.debugger.onEvent` callback.
56
+ */
57
+ cdpSessionId?: string;
58
+ }
59
+
60
+ /**
61
+ * Notification that the chrome extension has lost its debugger
62
+ * attachment to a target (tab closed, user clicked Cancel on the
63
+ * infobar, navigation across origins, another debugger took over
64
+ * via `Target.attachToTarget`, or the extension itself tore the
65
+ * session down on worker shutdown).
66
+ *
67
+ * The runtime dispatcher evicts any in-memory session state that
68
+ * references the invalidated target so the next CDP command from a
69
+ * tool force a fresh attach on the extension side. The extension's
70
+ * `host-browser-dispatcher` clears its local attach cache in the
71
+ * same way — the two signals are symmetric and together make
72
+ * reattach deterministic across the round-trip.
73
+ */
74
+ export interface HostBrowserSessionInvalidated {
75
+ type: "host_browser_session_invalidated";
76
+ /**
77
+ * Opaque target identifier. When the extension detached from a
78
+ * top-level tab target, this is the tab's id as a string. For a
79
+ * flat child session it is the CDP sessionId. Matches the shape
80
+ * used on the `cdpSessionId` field of outbound
81
+ * `host_browser_request` frames so runtime-side session lookups
82
+ * can use either field interchangeably.
83
+ */
84
+ targetId?: string;
85
+ /**
86
+ * Free-form human-readable reason surfaced by Chrome via
87
+ * `chrome.debugger.onDetach`. Used only for logging.
88
+ */
89
+ reason?: string;
90
+ }
91
+
92
+ // --- Domain-level union aliases (consumed by the barrel file) ---
93
+
94
+ export type _HostBrowserServerMessages =
95
+ | HostBrowserRequest
96
+ | HostBrowserCancelRequest;
97
+
98
+ export type _HostBrowserClientMessages =
99
+ | HostBrowserEvent
100
+ | HostBrowserSessionInvalidated;
@@ -307,10 +307,10 @@ export interface AssistantActivityState {
307
307
  statusText?: string;
308
308
  }
309
309
 
310
- /** Broadcast to clients when the two-axis permission mode changes. */
311
- export interface PermissionModeUpdate {
312
- type: "permission_mode_update";
313
- askBeforeActing: boolean;
310
+ /** Broadcast to clients when a conversation's host-access setting changes. */
311
+ export interface ConversationHostAccessUpdated {
312
+ type: "conversation_host_access_updated";
313
+ conversationId: string;
314
314
  hostAccess: boolean;
315
315
  }
316
316
 
@@ -376,4 +376,4 @@ export type _MessagesServerMessages =
376
376
  | TraceEvent
377
377
  | ConfirmationStateChanged
378
378
  | AssistantActivityState
379
- | PermissionModeUpdate;
379
+ | ConversationHostAccessUpdated;
@@ -189,6 +189,16 @@ export type SkillDetailResponse =
189
189
  | SkillsshSkillDetail
190
190
  | CustomSkillDetail;
191
191
 
192
+ // ─── Single-file content response (HTTP API) ─────────────────────────────
193
+ export interface SkillFileContentResponse {
194
+ path: string;
195
+ name: string;
196
+ size: number;
197
+ mimeType: string;
198
+ isBinary: boolean;
199
+ content: string | null;
200
+ }
201
+
192
202
  export interface SkillsDraftResponse {
193
203
  type: "skills_draft_response";
194
204
  success: boolean;
@@ -10,6 +10,7 @@ export interface SubagentSpawned {
10
10
  parentConversationId: string;
11
11
  label: string;
12
12
  objective: string;
13
+ isFork?: boolean;
13
14
  }
14
15
 
15
16
  export interface SubagentStatusChanged {
@@ -29,6 +30,7 @@ export interface SubagentDetailResponse {
29
30
  content: string;
30
31
  toolName?: string;
31
32
  isError?: boolean;
33
+ messageId?: string;
32
34
  }>;
33
35
  }
34
36
 
@@ -66,7 +66,10 @@ import {
66
66
  getWorkspacePromptPath,
67
67
  } from "../util/platform.js";
68
68
  import { registerDaemonCallbacks } from "../work-items/work-item-runner.js";
69
- import { AppSourceWatcher } from "./app-source-watcher.js";
69
+ import {
70
+ AppSourceWatcher,
71
+ setEnsureAppSourceWatcher,
72
+ } from "./app-source-watcher.js";
70
73
  import { ConfigWatcher } from "./config-watcher.js";
71
74
  import {
72
75
  Conversation,
@@ -86,6 +89,7 @@ import type {
86
89
  } from "./handlers/shared.js";
87
90
  import type { SkillOperationContext } from "./handlers/skills.js";
88
91
  import { HostBashProxy } from "./host-bash-proxy.js";
92
+ import { HostBrowserProxy } from "./host-browser-proxy.js";
89
93
  import { HostCuProxy } from "./host-cu-proxy.js";
90
94
  import { HostFileProxy } from "./host-file-proxy.js";
91
95
  import type {
@@ -158,9 +162,10 @@ function resolveCanonicalRequestSourceType(
158
162
 
159
163
  /**
160
164
  * Build an onEvent callback that registers pending interactions when the agent
161
- * loop emits confirmation_request, secret_request, host_bash_request, or
162
- * host_file_request events. This ensures that channel approval interception
163
- * can look up the conversation by requestId.
165
+ * loop emits confirmation_request, secret_request, host_bash_request,
166
+ * host_browser_request, host_file_request, or host_cu_request events. This
167
+ * ensures that channel approval interception can look up the conversation by
168
+ * requestId.
164
169
  */
165
170
  function makePendingInteractionRegistrar(
166
171
  conversation: Conversation,
@@ -249,6 +254,12 @@ function makePendingInteractionRegistrar(
249
254
  conversationId,
250
255
  kind: "host_bash",
251
256
  });
257
+ } else if (msg.type === "host_browser_request") {
258
+ pendingInteractions.register(msg.requestId, {
259
+ conversation,
260
+ conversationId,
261
+ kind: "host_browser",
262
+ });
252
263
  } else if (msg.type === "host_file_request") {
253
264
  pendingInteractions.register(msg.requestId, {
254
265
  conversation,
@@ -376,13 +387,23 @@ export class DaemonServer {
376
387
  "Transport metadata received",
377
388
  );
378
389
  conversation.setTransportHints(buildTransportHints(transport));
390
+ // Route client-reported host env through the capability-gated setter on
391
+ // Conversation so both the create/reuse path here and the queue-drain
392
+ // path in conversation-process share one implementation. The method
393
+ // gates on `supportsHostProxy` (not a specific interface name), so any
394
+ // new host-capable client added to `HostProxyInterfaceId` will flow its
395
+ // host env through automatically.
396
+ conversation.applyHostEnvFromTransport(transport);
379
397
  }
380
398
 
381
399
  constructor() {
382
400
  this.evictor = new ConversationEvictor(this.conversations);
383
401
  getSubagentManager().sharedRequestTimestamps = this.sharedRequestTimestamps;
384
402
  getSubagentManager().broadcastToAllClients = (msg) => this.broadcast(msg);
403
+ getSubagentManager().resolveParentConversation = (id) =>
404
+ this.conversations.get(id);
385
405
  setBroadcastToAllClients((msg) => this.broadcast(msg));
406
+ setEnsureAppSourceWatcher(() => this.appSourceWatcher.ensureStarted());
386
407
  this.evictor.onEvict = (conversationId: string) => {
387
408
  getSubagentManager().abortAllForParent(conversationId);
388
409
  };
@@ -880,10 +901,11 @@ export class DaemonServer {
880
901
  let conversation = this.conversations.get(conversationId);
881
902
  const sendToClient = () => {};
882
903
 
883
- if (options && Object.values(options).some((v) => v !== undefined)) {
904
+ const { taskRunId: _taskRunId, ...persistentOptions } = options ?? {};
905
+ if (Object.values(persistentOptions).some((v) => v !== undefined)) {
884
906
  this.conversationOptions.set(conversationId, {
885
907
  ...this.conversationOptions.get(conversationId),
886
- ...options,
908
+ ...persistentOptions,
887
909
  });
888
910
  }
889
911
 
@@ -1055,6 +1077,7 @@ export class DaemonServer {
1055
1077
  conversation.setAssistantId(
1056
1078
  options?.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
1057
1079
  );
1080
+ conversation.taskRunId = options?.taskRunId;
1058
1081
  // Only overwrite trust/auth context when explicitly provided. Callers that
1059
1082
  // don't supply a trust context (e.g. signal-injected messages) should
1060
1083
  // inherit whatever the conversation already has from a prior session.
@@ -1082,13 +1105,36 @@ export class DaemonServer {
1082
1105
  options?.transport?.chatType,
1083
1106
  ),
1084
1107
  );
1085
- // Only create the host bash proxy for desktop client interfaces that can
1086
- // execute commands on the user's machine. Non-desktop conversations (CLI,
1087
- // channels, headless) fall back to local execution.
1108
+ // Chrome-extension host_browser wiring is intentionally not supported
1109
+ // through this entry point. `prepareConversationForMessage` constructs
1110
+ // host_browser proxies that capture `conversation.getCurrentSender()`
1111
+ // directly, which would route browser frames through the daemon SSE
1112
+ // channel instead of the `ChromeExtensionRegistry`. Chrome-extension
1113
+ // flows reach host_browser exclusively through the
1114
+ // `/v1/messages` flow in `conversation-routes.ts`, which wires a
1115
+ // registry-aware sender and sets `hostBrowserSenderOverride`.
1116
+ //
1117
+ // Fail loudly rather than silently returning a mis-wired proxy so that
1118
+ // any future caller that tries to route chrome-extension through this
1119
+ // path discovers the gap immediately. When the time comes, factor the
1120
+ // wiring in conversation-routes.ts (registry lookup + override) into a
1121
+ // shared helper and call it from both sites.
1122
+ if (resolvedInterface === "chrome-extension") {
1123
+ throw new Error(
1124
+ "prepareConversationForMessage does not yet support chrome-extension transport — " +
1125
+ "use the conversation-routes.ts /v1/messages flow which routes host_browser through " +
1126
+ "the ChromeExtensionRegistry. If you need chrome-extension here, factor out the " +
1127
+ "wiring in conversation-routes.ts into a shared helper.",
1128
+ );
1129
+ }
1130
+ // Only create each host proxy for interfaces that support the matching
1131
+ // capability. macOS supports all four; the chrome-extension interface only
1132
+ // supports host_browser. Non-desktop conversations (CLI, channels, headless)
1133
+ // fall back to local execution.
1088
1134
  // Guard: don't replace an active proxy during concurrent turn races —
1089
1135
  // another request may have started processing between the isProcessing()
1090
1136
  // check above and the await on ensureActorScopedHistory().
1091
- if (supportsHostProxy(resolvedInterface)) {
1137
+ if (supportsHostProxy(resolvedInterface, "host_bash")) {
1092
1138
  if (!conversation.isProcessing() || !conversation.hostBashProxy) {
1093
1139
  conversation.setHostBashProxy(
1094
1140
  new HostBashProxy(conversation.getCurrentSender(), (requestId) => {
@@ -1096,6 +1142,21 @@ export class DaemonServer {
1096
1142
  }),
1097
1143
  );
1098
1144
  }
1145
+ } else if (!conversation.isProcessing()) {
1146
+ conversation.setHostBashProxy(undefined);
1147
+ }
1148
+ if (supportsHostProxy(resolvedInterface, "host_browser")) {
1149
+ if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
1150
+ conversation.setHostBrowserProxy(
1151
+ new HostBrowserProxy(conversation.getCurrentSender(), (requestId) => {
1152
+ pendingInteractions.resolve(requestId);
1153
+ }),
1154
+ );
1155
+ }
1156
+ } else if (!conversation.isProcessing()) {
1157
+ conversation.setHostBrowserProxy(undefined);
1158
+ }
1159
+ if (supportsHostProxy(resolvedInterface, "host_file")) {
1099
1160
  if (!conversation.isProcessing() || !conversation.hostFileProxy) {
1100
1161
  conversation.setHostFileProxy(
1101
1162
  new HostFileProxy(conversation.getCurrentSender(), (requestId) => {
@@ -1103,6 +1164,10 @@ export class DaemonServer {
1103
1164
  }),
1104
1165
  );
1105
1166
  }
1167
+ } else if (!conversation.isProcessing()) {
1168
+ conversation.setHostFileProxy(undefined);
1169
+ }
1170
+ if (supportsHostProxy(resolvedInterface, "host_cu")) {
1106
1171
  if (!conversation.isProcessing() || !conversation.hostCuProxy) {
1107
1172
  conversation.setHostCuProxy(
1108
1173
  new HostCuProxy(conversation.getCurrentSender(), (requestId) => {
@@ -1112,8 +1177,6 @@ export class DaemonServer {
1112
1177
  }
1113
1178
  conversation.addPreactivatedSkillId("computer-use");
1114
1179
  } else if (!conversation.isProcessing()) {
1115
- conversation.setHostBashProxy(undefined);
1116
- conversation.setHostFileProxy(undefined);
1117
1180
  conversation.setHostCuProxy(undefined);
1118
1181
  }
1119
1182
  conversation.setCommandIntent(options?.commandIntent ?? null);
@@ -1192,8 +1255,25 @@ export class DaemonServer {
1192
1255
  }
1193
1256
  }
1194
1257
  : registrar;
1258
+ // Non-interactive interfaces that still have a connected client capable
1259
+ // of handling host_browser_request events (e.g. chrome-extension) need
1260
+ // their hostBrowserProxy explicitly marked connected. The proxy
1261
+ // constructor defaults clientConnected = false, so without an explicit
1262
+ // sender update the chrome-extension proxy would be created and
1263
+ // immediately unavailable. We do NOT call updateClient(onEvent, false)
1264
+ // for that case, because flipping hasNoClient false would also enable
1265
+ // host_bash/host_file/host_cu tool gating for an interface that can't
1266
+ // service them. Instead, provision just the browser proxy's sender.
1267
+ const persistInterfaceCtx = conversation.getTurnInterfaceContext();
1268
+ const persistInterface = persistInterfaceCtx?.userMessageInterface;
1195
1269
  if (options?.isInteractive === true) {
1196
1270
  conversation.updateClient(onEvent, false);
1271
+ } else if (
1272
+ persistInterface &&
1273
+ !supportsHostProxy(persistInterface) &&
1274
+ supportsHostProxy(persistInterface, "host_browser")
1275
+ ) {
1276
+ conversation.hostBrowserProxy?.updateSender(onEvent, true);
1197
1277
  }
1198
1278
 
1199
1279
  conversation
@@ -15,6 +15,7 @@ import { deliverVerificationSlack } from "../runtime/verification-outbound-actio
15
15
  import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
16
16
  import type { ToolExecutionResult } from "../tools/types.js";
17
17
  import { getLogger } from "../util/logger.js";
18
+ import { ensureAppSourceWatcher } from "./app-source-watcher.js";
18
19
  import { refreshSurfacesForApp } from "./conversation-surfaces.js";
19
20
  import type { ToolSetupContext } from "./conversation-tool-setup.js";
20
21
  import { isDoordashCommand, updateDoordashProgress } from "./doordash-steps.js";
@@ -109,6 +110,11 @@ registerHook(
109
110
  description?: string;
110
111
  };
111
112
  if (parsed.id) {
113
+ // The apps directory may have just been created — ensure the
114
+ // filesystem watcher is running so subsequent file edits
115
+ // trigger live reload.
116
+ ensureAppSourceWatcher();
117
+
112
118
  handleAppChange(ctx, parsed.id, broadcastToAllClients);
113
119
 
114
120
  // Fire-and-forget: generate an app icon in the background.
@@ -1,33 +1,14 @@
1
- import { parseInterfaceId } from "../channels/types.js";
2
1
  import type { ConversationTransportMetadata } from "./message-types/conversations.js";
3
2
 
4
3
  /**
5
- * Build enriched transport hints from conversation transport metadata.
4
+ * Build transport hints from conversation transport metadata.
6
5
  *
7
- * Interface ID first, then host environment (macOS only), then any
8
- * client-provided hints. Shared between the conversation creation path
9
- * (server.ts) and the queue drain path (conversation-process.ts).
6
+ * Only forwards client-provided hints. Interface identity is already
7
+ * covered by `<turn_context>`, and host environment fields (home dir,
8
+ * username) are rendered in the `<workspace>` block.
10
9
  */
11
10
  export function buildTransportHints(
12
11
  transport: ConversationTransportMetadata,
13
12
  ): string[] {
14
- const hints: string[] = [];
15
-
16
- const interfaceLabel = parseInterfaceId(transport.interfaceId) ?? "vellum";
17
- hints.push(`User is messaging from interface: ${interfaceLabel}`);
18
-
19
- if (transport.interfaceId === "macos") {
20
- if (transport.hostHomeDir) {
21
- hints.push(`Host home directory: ${transport.hostHomeDir}`);
22
- }
23
- if (transport.hostUsername) {
24
- hints.push(`Host username: ${transport.hostUsername}`);
25
- }
26
- }
27
-
28
- if (transport.hints) {
29
- hints.push(...transport.hints);
30
- }
31
-
32
- return hints;
13
+ return transport.hints ? [...transport.hints] : [];
33
14
  }
@@ -1,15 +1,13 @@
1
1
  /**
2
- * Platform callback route registration for platform-managed deployments.
2
+ * Platform callback route registration.
3
3
  *
4
- * When the assistant daemon runs as a platform-managed instance (IS_PLATFORM=true)
5
- * with a configured VELLUM_PLATFORM_URL and PLATFORM_ASSISTANT_ID, external
6
- * service callbacks (Twilio webhooks, OAuth redirects, Telegram webhooks, etc.)
7
- * must route through the platform's gateway proxy instead of hitting the
8
- * assistant directly.
4
+ * Both platform-managed (IS_PLATFORM=true) and self-hosted assistants can
5
+ * register callback routes with the platform so inbound provider webhooks
6
+ * (Telegram, Twilio, email, OAuth) are forwarded correctly.
9
7
  *
10
- * This module registers callback routes with the platform's internal
11
- * gateway endpoint so the platform knows how to forward inbound provider
12
- * webhooks to the correct platform-managed assistant instance.
8
+ * Platform-managed assistants pick up context from environment variables.
9
+ * Self-hosted assistants use stored credentials (from `assistant platform
10
+ * connect` or the ensure-registration bootstrap).
13
11
  *
14
12
  * The platform endpoint is:
15
13
  * POST {VELLUM_PLATFORM_URL}/v1/internal/gateway/callback-routes/register/
@@ -41,17 +39,18 @@ export interface PlatformCallbackRegistrationContext {
41
39
  }
42
40
 
43
41
  /**
44
- * Whether the daemon should register callback routes with the platform.
42
+ * Whether the **runtime** should automatically register callback routes.
45
43
  * True when IS_PLATFORM, VELLUM_PLATFORM_URL, and PLATFORM_ASSISTANT_ID
46
- * are all set. Intentionally does **not** require the managed proxy API key
47
- * so that callback-only flows (OAuth transport, Telegram/Twilio callback
48
- * registration) work during partial bootstrap before the key is injected.
44
+ * are all set i.e. this is a platform-managed deployment.
45
+ *
46
+ * This is intentionally stricter than `context.enabled` (which also covers
47
+ * self-hosted assistants with stored credentials). Runtime auto-registration
48
+ * only applies to managed deployments; self-hosted assistants register
49
+ * explicitly via the CLI or gateway startup hooks.
49
50
  */
50
51
  export function shouldUsePlatformCallbacks(): boolean {
51
52
  return (
52
- getIsPlatform() &&
53
- !!getPlatformBaseUrl() &&
54
- !!getPlatformAssistantId()
53
+ getIsPlatform() && !!getPlatformBaseUrl() && !!getPlatformAssistantId()
55
54
  );
56
55
  }
57
56
 
@@ -86,8 +85,10 @@ export async function resolvePlatformCallbackRegistrationContext(): Promise<Plat
86
85
  hasInternalApiKey: internalApiKey.length > 0,
87
86
  hasAssistantApiKey: assistantApiKey.length > 0,
88
87
  authHeader,
88
+ // Enabled when we have enough context to register callback routes.
89
+ // Does NOT require IS_PLATFORM — self-hosted assistants with stored
90
+ // credentials can also register routes.
89
91
  enabled:
90
- platform &&
91
92
  platformBaseUrl.length > 0 &&
92
93
  assistantId.length > 0 &&
93
94
  authHeader !== null,