@vellumai/assistant 0.6.1 → 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 (463) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docker-entrypoint.sh +12 -2
  4. package/docs/architecture/memory.md +1 -1
  5. package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
  6. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  7. package/openapi.yaml +184 -69
  8. package/package.json +41 -41
  9. package/scripts/generate-openapi.ts +1 -2
  10. package/src/__tests__/acp-session.test.ts +43 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  12. package/src/__tests__/app-executors.test.ts +1 -0
  13. package/src/__tests__/app-source-watcher.test.ts +37 -11
  14. package/src/__tests__/approval-routes-http.test.ts +178 -1
  15. package/src/__tests__/assistant-event-hub.test.ts +30 -0
  16. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  17. package/src/__tests__/browser-manager.test.ts +40 -27
  18. package/src/__tests__/catalog-files.test.ts +862 -0
  19. package/src/__tests__/channel-approvals.test.ts +53 -0
  20. package/src/__tests__/checker.test.ts +104 -170
  21. package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
  22. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  23. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  24. package/src/__tests__/config-schema.test.ts +125 -48
  25. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  26. package/src/__tests__/context-overflow-approval.test.ts +21 -6
  27. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  28. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  29. package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
  30. package/src/__tests__/conversation-attachments.test.ts +80 -4
  31. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  32. package/src/__tests__/conversation-directories-parse.test.ts +105 -0
  33. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  34. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  35. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  36. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  37. package/src/__tests__/conversation-queue.test.ts +45 -2
  38. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  39. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  40. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  42. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  43. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  44. package/src/__tests__/conversation-store.test.ts +195 -0
  45. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  46. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -3
  47. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  48. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  49. package/src/__tests__/credential-vault.test.ts +152 -13
  50. package/src/__tests__/credentials-cli.test.ts +2 -2
  51. package/src/__tests__/date-context.test.ts +4 -4
  52. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  53. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  54. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  55. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  56. package/src/__tests__/gemini-provider.test.ts +2 -2
  57. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  58. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  59. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  60. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  61. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  62. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  63. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  64. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  65. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  66. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  67. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  68. package/src/__tests__/host-browser-routes.test.ts +198 -0
  69. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  70. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  71. package/src/__tests__/host-file-proxy.test.ts +185 -1
  72. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  73. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  74. package/src/__tests__/host-shell-tool.test.ts +1 -11
  75. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  76. package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
  77. package/src/__tests__/inline-command-runner.test.ts +7 -5
  78. package/src/__tests__/integration-status.test.ts +6 -7
  79. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  80. package/src/__tests__/log-export-workspace.test.ts +190 -0
  81. package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
  82. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  83. package/src/__tests__/mcp-health-check.test.ts +10 -3
  84. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  85. package/src/__tests__/migration-export-http.test.ts +61 -2
  86. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  87. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  88. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  89. package/src/__tests__/navigate-settings-tab.test.ts +14 -1
  90. package/src/__tests__/notification-broadcaster.test.ts +65 -0
  91. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  92. package/src/__tests__/oauth-cli.test.ts +707 -60
  93. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  94. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  95. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  96. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  97. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  98. package/src/__tests__/oauth-store.test.ts +1386 -182
  99. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  100. package/src/__tests__/onboarding-template-contract.test.ts +74 -55
  101. package/src/__tests__/openai-provider.test.ts +2 -2
  102. package/src/__tests__/outlook-categories.test.ts +1 -1
  103. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  104. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  105. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  106. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  107. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  108. package/src/__tests__/outlook-trash.test.ts +1 -1
  109. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  110. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  111. package/src/__tests__/permission-mode.test.ts +28 -56
  112. package/src/__tests__/pkb-autoinject.test.ts +96 -0
  113. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  114. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  115. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  116. package/src/__tests__/require-fresh-approval.test.ts +40 -3
  117. package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
  118. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  119. package/src/__tests__/schedule-routes.test.ts +162 -0
  120. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  121. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  123. package/src/__tests__/set-permission-mode.test.ts +13 -250
  124. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  125. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  126. package/src/__tests__/slack-channel-config.test.ts +12 -15
  127. package/src/__tests__/subagent-detail.test.ts +44 -2
  128. package/src/__tests__/subagent-disposal.test.ts +1 -0
  129. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  130. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  131. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  132. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  134. package/src/__tests__/subagent-tools.test.ts +1 -0
  135. package/src/__tests__/subagent-types.test.ts +1 -0
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  137. package/src/__tests__/system-prompt.test.ts +72 -1
  138. package/src/__tests__/task-scheduler.test.ts +32 -6
  139. package/src/__tests__/telegram-config.test.ts +10 -13
  140. package/src/__tests__/terminal-sandbox.test.ts +1 -1
  141. package/src/__tests__/terminal-tools.test.ts +11 -5
  142. package/src/__tests__/test-preload.ts +14 -0
  143. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  144. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
  145. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
  146. package/src/__tests__/tool-executor.test.ts +0 -1
  147. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  148. package/src/__tests__/top-level-renderer.test.ts +73 -1
  149. package/src/__tests__/transport-hints-queue.test.ts +62 -0
  150. package/src/__tests__/trust-store.test.ts +4 -4
  151. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  152. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  153. package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
  154. package/src/__tests__/workspace-policy.test.ts +2 -7
  155. package/src/acp/client-handler.ts +30 -4
  156. package/src/agent/loop.ts +12 -35
  157. package/src/approvals/guardian-request-resolvers.ts +21 -15
  158. package/src/browser-session/__tests__/manager.test.ts +297 -0
  159. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  160. package/src/browser-session/backends/extension.ts +26 -0
  161. package/src/browser-session/backends/local.ts +24 -0
  162. package/src/browser-session/events.ts +164 -0
  163. package/src/browser-session/index.ts +27 -0
  164. package/src/browser-session/manager.ts +159 -0
  165. package/src/browser-session/types.ts +28 -0
  166. package/src/channels/__tests__/types.test.ts +134 -0
  167. package/src/channels/types.ts +55 -0
  168. package/src/cli/__tests__/run-assistant-command.ts +34 -7
  169. package/src/cli/__tests__/unknown-command.test.ts +33 -0
  170. package/src/cli/commands/browser-relay.ts +339 -409
  171. package/src/cli/commands/credentials.ts +3 -3
  172. package/src/cli/commands/default-action.ts +68 -1
  173. package/src/cli/commands/email.ts +18 -13
  174. package/src/cli/commands/mcp.ts +16 -4
  175. package/src/cli/commands/oauth/__tests__/connect.test.ts +68 -41
  176. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  177. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  178. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  179. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  180. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  181. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  182. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  183. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  184. package/src/cli/commands/oauth/apps.ts +7 -4
  185. package/src/cli/commands/oauth/connect.ts +16 -2
  186. package/src/cli/commands/oauth/disconnect.ts +1 -1
  187. package/src/cli/commands/oauth/providers.ts +200 -36
  188. package/src/cli/commands/oauth/shared.ts +5 -5
  189. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  190. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  191. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  192. package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
  193. package/src/cli/commands/platform/index.ts +107 -10
  194. package/src/cli/commands/usage.ts +10 -9
  195. package/src/cli/lib/daemon-credential-client.ts +4 -0
  196. package/src/cli/program.ts +10 -3
  197. package/src/config/assistant-feature-flags.ts +59 -55
  198. package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
  199. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  200. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  201. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  202. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  203. package/src/config/bundled-skills/document/SKILL.md +4 -0
  204. package/src/config/bundled-skills/gmail/SKILL.md +12 -7
  205. package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
  206. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
  207. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  208. package/src/config/bundled-skills/settings/TOOLS.json +1 -1
  209. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
  210. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  211. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  212. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  213. package/src/config/env-registry.ts +14 -0
  214. package/src/config/env.ts +21 -0
  215. package/src/config/feature-flag-registry.json +46 -7
  216. package/src/config/loader.ts +56 -1
  217. package/src/config/sanitize-for-transfer.ts +47 -0
  218. package/src/config/schema.ts +46 -5
  219. package/src/config/schemas/host-browser.ts +66 -0
  220. package/src/config/schemas/memory-lifecycle.ts +1 -1
  221. package/src/config/schemas/memory-retrieval.ts +103 -0
  222. package/src/config/schemas/security.ts +0 -6
  223. package/src/config/schemas/services.ts +16 -0
  224. package/src/config/types.ts +0 -1
  225. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  226. package/src/context/window-manager.ts +19 -1
  227. package/src/credential-execution/approval-bridge.ts +49 -16
  228. package/src/credential-execution/managed-catalog.ts +3 -7
  229. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  230. package/src/daemon/app-source-watcher.ts +35 -0
  231. package/src/daemon/config-watcher.ts +6 -2
  232. package/src/daemon/context-overflow-approval.ts +5 -1
  233. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  234. package/src/daemon/conversation-agent-loop.ts +74 -19
  235. package/src/daemon/conversation-attachments.ts +40 -1
  236. package/src/daemon/conversation-messaging.ts +3 -0
  237. package/src/daemon/conversation-process.ts +66 -3
  238. package/src/daemon/conversation-queue-manager.ts +8 -0
  239. package/src/daemon/conversation-runtime-assembly.ts +159 -20
  240. package/src/daemon/conversation-surfaces.ts +78 -12
  241. package/src/daemon/conversation-tool-setup.ts +74 -11
  242. package/src/daemon/conversation-workspace.ts +12 -0
  243. package/src/daemon/conversation.ts +227 -11
  244. package/src/daemon/date-context.ts +10 -10
  245. package/src/daemon/first-greeting.ts +3 -2
  246. package/src/daemon/handlers/conversations.ts +9 -139
  247. package/src/daemon/handlers/shared.ts +65 -0
  248. package/src/daemon/handlers/skills.ts +232 -37
  249. package/src/daemon/host-bash-proxy.ts +48 -13
  250. package/src/daemon/host-browser-proxy.ts +191 -0
  251. package/src/daemon/host-cu-proxy.ts +36 -11
  252. package/src/daemon/host-file-proxy.ts +57 -9
  253. package/src/daemon/lifecycle.ts +86 -12
  254. package/src/daemon/message-protocol.ts +7 -0
  255. package/src/daemon/message-types/conversations.ts +59 -13
  256. package/src/daemon/message-types/host-browser.ts +100 -0
  257. package/src/daemon/message-types/messages.ts +5 -6
  258. package/src/daemon/message-types/notifications.ts +12 -0
  259. package/src/daemon/message-types/settings.ts +12 -0
  260. package/src/daemon/message-types/skills.ts +10 -0
  261. package/src/daemon/message-types/subagents.ts +2 -0
  262. package/src/daemon/server.ts +112 -35
  263. package/src/daemon/tool-side-effects.ts +6 -0
  264. package/src/daemon/transport-hints.ts +14 -0
  265. package/src/inbound/platform-callback-registration.ts +18 -17
  266. package/src/index.ts +1 -1
  267. package/src/mcp/client.ts +59 -24
  268. package/src/memory/app-store.ts +31 -1
  269. package/src/memory/conversation-crud.ts +38 -10
  270. package/src/memory/conversation-directories.ts +39 -0
  271. package/src/memory/conversation-group-migration.ts +65 -5
  272. package/src/memory/conversation-starters-cadence.ts +76 -0
  273. package/src/memory/conversation-title-service.ts +5 -2
  274. package/src/memory/db-init.ts +12 -0
  275. package/src/memory/embedding-backend.test.ts +75 -0
  276. package/src/memory/embedding-backend.ts +131 -5
  277. package/src/memory/embedding-gemini.test.ts +54 -0
  278. package/src/memory/embedding-gemini.ts +20 -9
  279. package/src/memory/embedding-local.ts +177 -18
  280. package/src/memory/graph/capability-seed.ts +3 -5
  281. package/src/memory/graph/consolidation.ts +10 -23
  282. package/src/memory/graph/extraction-job.ts +15 -0
  283. package/src/memory/graph/retriever.ts +40 -22
  284. package/src/memory/graph/store.test.ts +7 -3
  285. package/src/memory/graph/store.ts +47 -12
  286. package/src/memory/group-crud.ts +25 -9
  287. package/src/memory/llm-usage-store.ts +45 -4
  288. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  289. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  290. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  291. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  292. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  293. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  294. package/src/memory/migrations/index.ts +6 -0
  295. package/src/memory/migrations/registry.ts +8 -0
  296. package/src/memory/schema/conversations.ts +1 -0
  297. package/src/memory/schema/oauth.ts +18 -13
  298. package/src/messaging/provider.ts +1 -1
  299. package/src/notifications/broadcaster.ts +6 -0
  300. package/src/notifications/conversation-pairing.ts +12 -4
  301. package/src/notifications/emit-signal.ts +14 -0
  302. package/src/notifications/signal.ts +11 -0
  303. package/src/oauth/AGENTS.md +76 -0
  304. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  305. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  306. package/src/oauth/byo-connection.test.ts +8 -8
  307. package/src/oauth/byo-connection.ts +7 -7
  308. package/src/oauth/connect-orchestrator.ts +23 -21
  309. package/src/oauth/connect-types.ts +3 -3
  310. package/src/oauth/connection-resolver.test.ts +17 -4
  311. package/src/oauth/connection-resolver.ts +16 -16
  312. package/src/oauth/connection.ts +1 -1
  313. package/src/oauth/manual-token-connection.ts +13 -13
  314. package/src/oauth/oauth-store.ts +214 -100
  315. package/src/oauth/platform-connection.test.ts +5 -5
  316. package/src/oauth/platform-connection.ts +4 -4
  317. package/src/oauth/provider-serializer.ts +31 -5
  318. package/src/oauth/revoke.ts +76 -0
  319. package/src/oauth/seed-providers.ts +127 -87
  320. package/src/oauth/token-persistence.ts +1 -1
  321. package/src/permissions/checker.ts +3 -3
  322. package/src/permissions/defaults.ts +7 -8
  323. package/src/permissions/permission-mode.ts +4 -11
  324. package/src/permissions/prompter.ts +13 -3
  325. package/src/permissions/v2-consent-policy.ts +87 -0
  326. package/src/platform/client.ts +1 -1
  327. package/src/prompts/system-prompt.ts +18 -21
  328. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  329. package/src/prompts/templates/BOOTSTRAP.md +59 -96
  330. package/src/prompts/templates/SOUL.md +11 -11
  331. package/src/providers/anthropic/client.ts +1 -0
  332. package/src/providers/types.ts +1 -1
  333. package/src/runtime/AGENTS.md +23 -0
  334. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  335. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  336. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  337. package/src/runtime/assistant-event-hub.ts +24 -2
  338. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  339. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  340. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  341. package/src/runtime/auth/middleware.ts +98 -0
  342. package/src/runtime/auth/route-policy.ts +6 -7
  343. package/src/runtime/auth/token-service.ts +8 -0
  344. package/src/runtime/capability-tokens.ts +414 -0
  345. package/src/runtime/channel-approvals.ts +18 -5
  346. package/src/runtime/chrome-extension-registry.ts +332 -0
  347. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  348. package/src/runtime/guardian-decision-types.ts +7 -0
  349. package/src/runtime/http-server.ts +425 -70
  350. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  351. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  352. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  353. package/src/runtime/migrations/migration-transport.ts +6 -0
  354. package/src/runtime/migrations/migration-wizard.ts +22 -2
  355. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  356. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  357. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  358. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  359. package/src/runtime/pending-interactions.ts +29 -13
  360. package/src/runtime/routes/approval-routes.ts +90 -16
  361. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  362. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  363. package/src/runtime/routes/conversation-analysis-routes.ts +18 -5
  364. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  365. package/src/runtime/routes/conversation-routes.ts +308 -28
  366. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  367. package/src/runtime/routes/group-routes.ts +22 -8
  368. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  369. package/src/runtime/routes/host-browser-routes.ts +279 -0
  370. package/src/runtime/routes/host-file-routes.ts +9 -1
  371. package/src/runtime/routes/identity-routes.ts +259 -16
  372. package/src/runtime/routes/log-export/AGENTS.md +104 -0
  373. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
  374. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
  375. package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
  376. package/src/runtime/routes/log-export-routes.ts +60 -25
  377. package/src/runtime/routes/memory-item-routes.ts +1 -7
  378. package/src/runtime/routes/migration-routes.ts +87 -2
  379. package/src/runtime/routes/oauth-apps.ts +15 -17
  380. package/src/runtime/routes/oauth-providers.ts +4 -0
  381. package/src/runtime/routes/schedule-routes.ts +24 -11
  382. package/src/runtime/routes/settings-routes.ts +9 -97
  383. package/src/runtime/routes/skills-routes.ts +52 -2
  384. package/src/runtime/routes/subagents-routes.ts +14 -10
  385. package/src/runtime/routes/usage-routes.ts +8 -7
  386. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  387. package/src/runtime/routes/workspace-routes.ts +8 -1
  388. package/src/runtime/routes/workspace-utils.ts +2 -0
  389. package/src/schedule/scheduler.ts +7 -5
  390. package/src/security/ces-credential-client.ts +20 -0
  391. package/src/security/ces-rpc-credential-backend.ts +17 -0
  392. package/src/security/credential-backend.ts +5 -0
  393. package/src/security/oauth2.ts +42 -25
  394. package/src/security/secure-keys.ts +118 -25
  395. package/src/security/token-manager.ts +23 -10
  396. package/src/skills/catalog-files.ts +492 -0
  397. package/src/skills/inline-command-runner.ts +12 -14
  398. package/src/subagent/manager.ts +131 -26
  399. package/src/subagent/types.ts +19 -0
  400. package/src/tools/apps/executors.ts +11 -2
  401. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  402. package/src/tools/browser/auth-detector.ts +43 -12
  403. package/src/tools/browser/browser-execution.ts +645 -340
  404. package/src/tools/browser/browser-manager.ts +36 -12
  405. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  406. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  407. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  408. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  409. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  410. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  411. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  412. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  413. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  414. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  415. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  416. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  417. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  418. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  419. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  420. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  421. package/src/tools/browser/cdp-client/errors.ts +34 -0
  422. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  423. package/src/tools/browser/cdp-client/factory.ts +204 -0
  424. package/src/tools/browser/cdp-client/index.ts +14 -0
  425. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  426. package/src/tools/browser/cdp-client/types.ts +52 -0
  427. package/src/tools/filesystem/edit.ts +1 -1
  428. package/src/tools/filesystem/list.ts +1 -1
  429. package/src/tools/filesystem/read.ts +1 -1
  430. package/src/tools/filesystem/write.ts +2 -1
  431. package/src/tools/host-filesystem/edit.ts +1 -1
  432. package/src/tools/host-filesystem/read.ts +12 -15
  433. package/src/tools/host-filesystem/write.ts +1 -1
  434. package/src/tools/host-terminal/host-shell.ts +21 -16
  435. package/src/tools/permission-checker.ts +77 -100
  436. package/src/tools/registry.ts +0 -2
  437. package/src/tools/secret-detection-handler.ts +34 -1
  438. package/src/tools/shared/filesystem/image-read.ts +61 -40
  439. package/src/tools/skills/sandbox-runner.ts +3 -6
  440. package/src/tools/subagent/spawn.ts +47 -3
  441. package/src/tools/subagent/status.ts +2 -0
  442. package/src/tools/system/register.ts +2 -16
  443. package/src/tools/terminal/safe-env.ts +7 -0
  444. package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
  445. package/src/tools/terminal/sandbox.ts +4 -1
  446. package/src/tools/terminal/shell.ts +24 -21
  447. package/src/tools/tool-approval-handler.ts +48 -2
  448. package/src/tools/types.ts +2 -3
  449. package/src/util/platform.ts +14 -19
  450. package/src/watcher/provider-types.ts +1 -1
  451. package/src/workspace/migrations/029-seed-pkb.ts +1 -0
  452. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
  453. package/src/workspace/migrations/registry.ts +2 -0
  454. package/src/workspace/top-level-renderer.ts +19 -1
  455. package/src/__tests__/chrome-cdp.test.ts +0 -419
  456. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  457. package/src/__tests__/permission-mode-store.test.ts +0 -277
  458. package/src/browser-extension-relay/protocol.ts +0 -63
  459. package/src/browser-extension-relay/server.ts +0 -203
  460. package/src/config/schemas/sandbox.ts +0 -14
  461. package/src/permissions/permission-mode-store.ts +0 -180
  462. package/src/tools/browser/chrome-cdp.ts +0 -239
  463. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -22,7 +22,9 @@ import type {
22
22
  TurnChannelContext,
23
23
  TurnInterfaceContext,
24
24
  } from "../channels/types.js";
25
+ import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
25
26
  import { getConfig } from "../config/loader.js";
27
+ import { derefToolResultReReads,postTurnTruncateToolResults } from "../context/post-turn-tool-result-truncation.js";
26
28
  import { estimatePromptTokens } from "../context/token-estimator.js";
27
29
  import type { ContextWindowManager } from "../context/window-manager.js";
28
30
  import type { ToolProfiler } from "../events/tool-profiling-listener.js";
@@ -44,6 +46,7 @@ import {
44
46
  updateConversationTitle,
45
47
  updateMessageMetadata,
46
48
  } from "../memory/conversation-crud.js";
49
+ import { getResolvedConversationDirPath } from "../memory/conversation-directories.js";
47
50
  import { syncMessageToDisk } from "../memory/conversation-disk-view.js";
48
51
  import {
49
52
  isReplaceableTitle,
@@ -58,6 +61,7 @@ import type { ContentBlock, Message } from "../providers/types.js";
58
61
  import type { Provider } from "../providers/types.js";
59
62
  import { resolveActorTrust } from "../runtime/actor-trust-resolver.js";
60
63
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
64
+ import { getSubagentManager } from "../subagent/index.js";
61
65
  import type { UsageActor } from "../usage/actors.js";
62
66
  import { getLogger } from "../util/logger.js";
63
67
  import { truncate } from "../util/truncate.js";
@@ -100,6 +104,7 @@ import type {
100
104
  } from "./conversation-runtime-assembly.js";
101
105
  import {
102
106
  applyRuntimeInjections,
107
+ buildSubagentStatusBlock,
103
108
  buildUnifiedTurnContextBlock,
104
109
  findLastInjectedNowContent,
105
110
  inboundActorContextFromTrust,
@@ -109,6 +114,7 @@ import {
109
114
  stripInjectionsForCompaction,
110
115
  } from "./conversation-runtime-assembly.js";
111
116
  import type { SkillProjectionCache } from "./conversation-skill-tools.js";
117
+ import { markSurfaceCompleted } from "./conversation-surfaces.js";
112
118
  import { resolveTrustClass } from "./conversation-tool-setup.js";
113
119
  import { recordUsage } from "./conversation-usage.js";
114
120
  import { formatTurnTimestamp } from "./date-context.js";
@@ -260,6 +266,8 @@ export interface AgentLoopConversationContext {
260
266
  lastAttachmentWarnings: string[];
261
267
 
262
268
  hasNoClient: boolean;
269
+ /** True when this conversation is itself a subagent (suppresses subagent status injection). */
270
+ isSubagent?: boolean;
263
271
  headlessLock?: boolean;
264
272
  readonly streamThinking: boolean;
265
273
  readonly prompter: PermissionPrompter;
@@ -438,6 +446,7 @@ export async function runAgentLoopImpl(
438
446
  surfaceId,
439
447
  summary: "Dismissed",
440
448
  });
449
+ markSurfaceCompleted(ctx, surfaceId, "Dismissed");
441
450
  ctx.pendingSurfaceActions.delete(surfaceId);
442
451
  }
443
452
  }
@@ -501,6 +510,7 @@ export async function runAgentLoopImpl(
501
510
 
502
511
  const isFirstMessage = ctx.messages.length === 1;
503
512
  let shouldInjectWorkspace = isFirstMessage;
513
+ let compactedThisTurn = false;
504
514
 
505
515
  const compactCheck = ctx.contextWindowManager.shouldCompact(ctx.messages);
506
516
  if (compactCheck.needed) {
@@ -556,6 +566,9 @@ export async function runAgentLoopImpl(
556
566
  collapseRawResponses(compacted.summaryRawResponses),
557
567
  );
558
568
  shouldInjectWorkspace = true;
569
+ if (compacted.compactedPersistedMessages > 0) {
570
+ compactedThisTurn = true;
571
+ }
559
572
  }
560
573
 
561
574
  const state = createEventHandlerState();
@@ -776,16 +789,24 @@ export async function runAgentLoopImpl(
776
789
  const isInteractiveResolved =
777
790
  options?.isInteractive ?? (!ctx.hasNoClient && !ctx.headlessLock);
778
791
 
779
- // Only inject NOW.md if it changed since the last injection in the
780
- // conversation. Keeping the previous injection in place avoids mutating
781
- // historical user messages and preserves the cached prefix.
792
+ // Inject NOW.md and PKB content only on the first turn (or after
793
+ // compaction re-strips them). Old injections persist in history and
794
+ // are never stripped on normal turns — this preserves the cached prefix.
782
795
  const currentNowContent = readNowScratchpad();
783
- const lastInjectedNow = findLastInjectedNowContent(ctx.messages);
784
- const nowScratchpad =
785
- currentNowContent !== lastInjectedNow ? currentNowContent : null;
796
+ const shouldInjectNowAndPkb = isFirstMessage || compactedThisTurn;
797
+ const nowScratchpad = shouldInjectNowAndPkb ? currentNowContent : null;
786
798
 
787
- // Read PKB always-loaded files (INDEX, essentials, threads, buffer)
788
799
  const currentPkbContent = readPkbContext();
800
+ const pkbContext = shouldInjectNowAndPkb ? currentPkbContent : null;
801
+ const pkbActive = currentPkbContent !== null;
802
+
803
+ // Subagent status injection — gives the parent LLM visibility into active/completed children.
804
+ // Skipped when this conversation IS a subagent (no nesting) or has no children.
805
+ const subagentStatusBlock = ctx.isSubagent
806
+ ? null
807
+ : buildSubagentStatusBlock(
808
+ getSubagentManager().getChildrenOf(ctx.conversationId),
809
+ );
789
810
 
790
811
  // Shared injection options — reused whenever we need to re-inject after reduction.
791
812
  const injectionOpts = {
@@ -796,11 +817,13 @@ export async function runAgentLoopImpl(
796
817
  channelCapabilities: ctx.channelCapabilities ?? null,
797
818
  channelCommandContext: ctx.commandIntent ?? null,
798
819
  unifiedTurnContext: unifiedTurnContextStr,
799
- pkbContext: currentPkbContent,
820
+ pkbContext,
821
+ pkbActive,
800
822
  nowScratchpad,
801
823
  voiceCallControlPrompt: ctx.voiceCallControlPrompt ?? null,
802
824
  transportHints: ctx.transportHints ?? null,
803
825
  isNonInteractive: !isInteractiveResolved,
826
+ subagentStatusBlock,
804
827
  } as const;
805
828
 
806
829
  let currentInjectionMode: InjectionMode = "full";
@@ -922,7 +945,7 @@ export async function runAgentLoopImpl(
922
945
  // value from injectionOpts to avoid duplicate injection.
923
946
  runMessages = applyRuntimeInjections(ctx.messages, {
924
947
  ...injectionOpts,
925
- pkbContext: currentPkbContent,
948
+ ...(step.compactionResult?.compacted && { pkbContext: currentPkbContent }),
926
949
  ...(step.compactionResult?.compacted && { nowScratchpad: currentNowContent }),
927
950
  workspaceTopLevelContext: shouldInjectWorkspace
928
951
  ? ctx.workspaceTopLevelContext
@@ -1202,8 +1225,16 @@ export async function runAgentLoopImpl(
1202
1225
  // limit), incorporate those new messages into ctx.messages so the
1203
1226
  // convergence loop operates on the full (larger) history.
1204
1227
  if (state.contextTooLargeDetected) {
1228
+ // Detect whether ctx.messages currently lacks NOW.md so we know if
1229
+ // it needs to be re-injected. Mid-loop compaction (line ~1067) may
1230
+ // have already stripped injections before escalating here, so we
1231
+ // check actual message state rather than tracking mutation sites.
1232
+ let convergenceStripped =
1233
+ findLastInjectedNowContent(ctx.messages) === null;
1234
+
1205
1235
  if (updatedHistory.length > preRunHistoryLength) {
1206
1236
  ctx.messages = stripInjectionsForCompaction(updatedHistory);
1237
+ convergenceStripped = true;
1207
1238
  preRepairMessages = updatedHistory;
1208
1239
  preRunHistoryLength = updatedHistory.length;
1209
1240
  }
@@ -1326,12 +1357,13 @@ export async function runAgentLoopImpl(
1326
1357
  shouldInjectWorkspace = true;
1327
1358
  }
1328
1359
 
1329
- // ctx.messages has been stripped (line 1206/1373) so NOW.md must
1330
- // always be re-injected regardless of whether compaction ran.
1360
+ // Only re-inject NOW.md when ctx.messages was actually stripped;
1361
+ // otherwise the existing NOW.md block is still present and
1362
+ // re-injecting would duplicate it.
1331
1363
  runMessages = applyRuntimeInjections(ctx.messages, {
1332
1364
  ...injectionOpts,
1333
1365
  pkbContext: currentPkbContent,
1334
- nowScratchpad: currentNowContent,
1366
+ nowScratchpad: convergenceStripped ? currentNowContent : null,
1335
1367
  workspaceTopLevelContext: shouldInjectWorkspace
1336
1368
  ? ctx.workspaceTopLevelContext
1337
1369
  : null,
@@ -1373,6 +1405,7 @@ export async function runAgentLoopImpl(
1373
1405
  // pre-rerun messages.
1374
1406
  if (updatedHistory.length > preRunHistoryLength) {
1375
1407
  ctx.messages = stripInjectionsForCompaction(updatedHistory);
1408
+ convergenceStripped = true;
1376
1409
  preRepairMessages = updatedHistory;
1377
1410
  preRunHistoryLength = updatedHistory.length;
1378
1411
  }
@@ -1448,12 +1481,12 @@ export async function runAgentLoopImpl(
1448
1481
  shouldInjectWorkspace = true;
1449
1482
  }
1450
1483
 
1451
- // ctx.messages was already stripped before the convergence
1452
- // loop, so NOW.md must always be re-injected here.
1484
+ // Only re-inject NOW.md when ctx.messages was actually stripped;
1485
+ // otherwise the existing block is still present.
1453
1486
  runMessages = applyRuntimeInjections(ctx.messages, {
1454
1487
  ...injectionOpts,
1455
1488
  pkbContext: currentPkbContent,
1456
- nowScratchpad: currentNowContent,
1489
+ nowScratchpad: convergenceStripped ? currentNowContent : null,
1457
1490
  workspaceTopLevelContext: shouldInjectWorkspace
1458
1491
  ? ctx.workspaceTopLevelContext
1459
1492
  : null,
@@ -1568,12 +1601,12 @@ export async function runAgentLoopImpl(
1568
1601
  shouldInjectWorkspace = true;
1569
1602
  }
1570
1603
 
1571
- // ctx.messages was already stripped before the convergence
1572
- // loop, so NOW.md must always be re-injected here.
1604
+ // Only re-inject NOW.md when ctx.messages was actually stripped;
1605
+ // otherwise the existing block is still present.
1573
1606
  runMessages = applyRuntimeInjections(ctx.messages, {
1574
1607
  ...injectionOpts,
1575
1608
  pkbContext: currentPkbContent,
1576
- nowScratchpad: currentNowContent,
1609
+ nowScratchpad: convergenceStripped ? currentNowContent : null,
1577
1610
  workspaceTopLevelContext: shouldInjectWorkspace
1578
1611
  ? ctx.workspaceTopLevelContext
1579
1612
  : null,
@@ -1712,7 +1745,29 @@ export async function runAgentLoopImpl(
1712
1745
  // would create a duplicate plain-text bubble below the alert card.
1713
1746
  }
1714
1747
 
1715
- const restoredHistory = [...preRepairMessages, ...newMessages];
1748
+ let restoredHistory = [...preRepairMessages, ...newMessages];
1749
+
1750
+ // Post-turn tool result truncation: save large results to disk and
1751
+ // replace in-context content with a prefix/suffix stub + file pointer.
1752
+ if (isAssistantFeatureFlagEnabled("tool-result-truncation", config)) {
1753
+ try {
1754
+ const conv = getConversation(ctx.conversationId);
1755
+ if (conv) {
1756
+ const convDir = getResolvedConversationDirPath(ctx.conversationId, conv.createdAt);
1757
+ const { messages: derefMessages, dereferencedCount } = derefToolResultReReads(restoredHistory);
1758
+ const { messages: truncatedMessages, truncatedCount } = postTurnTruncateToolResults(derefMessages, { conversationDir: convDir });
1759
+ if (truncatedCount > 0 || dereferencedCount > 0) {
1760
+ rlog.info(
1761
+ { truncatedCount, dereferencedCount },
1762
+ "Post-turn tool result truncation applied",
1763
+ );
1764
+ }
1765
+ restoredHistory = truncatedMessages;
1766
+ }
1767
+ } catch (err) {
1768
+ rlog.warn({ err }, "Post-turn tool result truncation failed (non-fatal)");
1769
+ }
1770
+ }
1716
1771
 
1717
1772
  const postLoopContextEstimate = estimatePromptTokens(
1718
1773
  restoredHistory,
@@ -13,6 +13,11 @@ import {
13
13
  import type { PermissionPrompter } from "../permissions/prompter.js";
14
14
  import { addRule } from "../permissions/trust-store.js";
15
15
  import { isAllowDecision } from "../permissions/types.js";
16
+ import {
17
+ CONVERSATION_HOST_ACCESS_PROMPT,
18
+ isConversationHostAccessEnabled,
19
+ isPermissionControlsV2Enabled,
20
+ } from "../permissions/v2-consent-policy.js";
16
21
  import type { ContentBlock } from "../providers/types.js";
17
22
  import { getLogger } from "../util/logger.js";
18
23
  import {
@@ -45,6 +50,41 @@ export async function approveHostAttachmentRead(
45
50
  ): Promise<boolean> {
46
51
  const toolName = "host_file_read";
47
52
  const input = { path: filePath };
53
+
54
+ if (isPermissionControlsV2Enabled()) {
55
+ if (isConversationHostAccessEnabled(conversationId)) {
56
+ return true;
57
+ }
58
+
59
+ // HTTP-created sessions use a no-op sendToClient — prompting would
60
+ // block for the full permission timeout before auto-denying.
61
+ if (hasNoClient) {
62
+ log.info(
63
+ { filePath },
64
+ "Denying host attachment read: no interactive client connected",
65
+ );
66
+ return false;
67
+ }
68
+
69
+ const response = await prompter.prompt(
70
+ toolName,
71
+ input,
72
+ "low",
73
+ CONVERSATION_HOST_ACCESS_PROMPT.allowlistOptions,
74
+ CONVERSATION_HOST_ACCESS_PROMPT.scopeOptions,
75
+ undefined,
76
+ conversationId,
77
+ "host",
78
+ CONVERSATION_HOST_ACCESS_PROMPT.persistentDecisionsAllowed,
79
+ undefined,
80
+ CONVERSATION_HOST_ACCESS_PROMPT.temporaryOptionsAvailable,
81
+ undefined,
82
+ true,
83
+ );
84
+
85
+ return response.decision === "allow";
86
+ }
87
+
48
88
  const decision = await check(toolName, input, workingDir);
49
89
 
50
90
  if (decision.decision === "allow") {
@@ -71,7 +111,6 @@ export async function approveHostAttachmentRead(
71
111
  await generateAllowlistOptions(toolName, input),
72
112
  generateScopeOptions(workingDir, toolName),
73
113
  undefined,
74
- undefined,
75
114
  conversationId,
76
115
  "host",
77
116
  );
@@ -41,6 +41,7 @@ import type {
41
41
  ServerMessage,
42
42
  UserMessageAttachment,
43
43
  } from "./message-protocol.js";
44
+ import type { ConversationTransportMetadata } from "./message-types/conversations.js";
44
45
 
45
46
  const log = getLogger("conversation-messaging");
46
47
 
@@ -222,6 +223,7 @@ export function enqueueMessage(
222
223
  metadata?: Record<string, unknown>,
223
224
  options?: { isInteractive?: boolean },
224
225
  displayContent?: string,
226
+ transport?: ConversationTransportMetadata,
225
227
  ): { queued: boolean; requestId: string; rejected?: boolean } {
226
228
  if (!ctx.processing) {
227
229
  return { queued: false, requestId };
@@ -246,6 +248,7 @@ export function enqueueMessage(
246
248
  turnChannelContext,
247
249
  turnInterfaceContext,
248
250
  isInteractive: options?.isInteractive,
251
+ transport,
249
252
  displayContent,
250
253
  sentAt: Date.now(),
251
254
  });
@@ -15,7 +15,11 @@ import type {
15
15
  TurnChannelContext,
16
16
  TurnInterfaceContext,
17
17
  } from "../channels/types.js";
18
- import { parseChannelId, parseInterfaceId } from "../channels/types.js";
18
+ import {
19
+ parseChannelId,
20
+ parseInterfaceId,
21
+ supportsHostProxy,
22
+ } from "../channels/types.js";
19
23
  import { getConfig } from "../config/loader.js";
20
24
  import type { ContextWindowResult } from "../context/window-manager.js";
21
25
  import { listPendingRequestsByConversationScope } from "../memory/canonical-guardian-store.js";
@@ -43,7 +47,9 @@ import type {
43
47
  UsageStats,
44
48
  UserMessageAttachment,
45
49
  } from "./message-protocol.js";
50
+ import type { ConversationTransportMetadata } from "./message-types/conversations.js";
46
51
  import type { TraceEmitter } from "./trace-emitter.js";
52
+ import { buildTransportHints } from "./transport-hints.js";
47
53
  import { resolveVerificationSessionIntent } from "./verification-session-intent.js";
48
54
 
49
55
  const log = getLogger("conversation-process");
@@ -131,6 +137,12 @@ export interface ProcessConversationContext {
131
137
  clearProxyAvailability(): void;
132
138
  /** Restore host proxy availability based on whether a real client is connected. */
133
139
  restoreProxyAvailability(): void;
140
+ /** Restore only the host browser proxy (used by chrome-extension drains). */
141
+ restoreBrowserProxyAvailability(): void;
142
+ /** Replace or clear the conversation's host browser proxy. */
143
+ setHostBrowserProxy(
144
+ proxy: import("./host-browser-proxy.js").HostBrowserProxy | undefined,
145
+ ): void;
134
146
  emitActivityState(
135
147
  phase:
136
148
  | "idle"
@@ -157,6 +169,15 @@ export interface ProcessConversationContext {
157
169
  ): void;
158
170
  /** Force context compaction regardless of threshold/cooldown. */
159
171
  forceCompact(): Promise<ContextWindowResult>;
172
+ /** Set transport-derived hints for the conversation. */
173
+ setTransportHints(hints: string[] | undefined): void;
174
+ /**
175
+ * Apply client-reported host env (home dir, username) from transport
176
+ * metadata, gating on `supportsHostProxy` so non-host-proxy interfaces
177
+ * clear any stale values. Shared between the create/reuse path in
178
+ * `DaemonServer.applyTransportMetadata` and the queue-drain path below.
179
+ */
180
+ applyHostEnvFromTransport(transport: ConversationTransportMetadata): void;
160
181
  }
161
182
 
162
183
  function resolveQueuedTurnContext(
@@ -290,22 +311,64 @@ export async function drainQueue(
290
311
  conversation.setTurnInterfaceContext(queuedInterfaceCtx);
291
312
  }
292
313
 
314
+ // Apply transport hints from the queued message so each turn uses the
315
+ // transport metadata that arrived with its message. Messages without
316
+ // transport (subagent notifications, surface actions, etc.) inherit the
317
+ // conversation's existing hints — clearing them would erase the user's
318
+ // environment context for internal turns.
319
+ if (next.transport) {
320
+ conversation.setTransportHints(buildTransportHints(next.transport));
321
+ // Route client-reported host env through the same capability-gated
322
+ // setter used by DaemonServer.applyTransportMetadata so create/reuse
323
+ // and queue-drain stay in sync without duplicating the gate logic.
324
+ conversation.applyHostEnvFromTransport(next.transport);
325
+ }
326
+
293
327
  // Non-interactive queued messages (channel requests) must not execute tools
294
328
  // via the desktop host proxy. Clear proxy availability so isAvailable()
295
329
  // returns false and tool execution falls back to local.
296
330
  if (next.isInteractive === false) {
297
331
  conversation.clearProxyAvailability();
332
+ // chrome-extension is non-interactive (no SSE prompter UI) but DOES have
333
+ // a connected client that can service host_browser_request events. The
334
+ // unconditional clear above turned its hostBrowserProxy off; restore it
335
+ // here so the queued turn can still drive the browser via CDP.
336
+ const drainInterfaceCtx =
337
+ queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
338
+ const drainInterface = drainInterfaceCtx?.userMessageInterface;
339
+ if (
340
+ drainInterface &&
341
+ !supportsHostProxy(drainInterface) &&
342
+ supportsHostProxy(drainInterface, "host_browser")
343
+ ) {
344
+ conversation.restoreBrowserProxyAvailability();
345
+ }
298
346
  } else {
299
347
  // Restore proxy availability only for desktop-originating turns (macos)
300
348
  // in case a prior non-interactive drain disabled it. Non-desktop interactive
301
- // interfaces (CLI, Vellum) should not re-enable desktop host proxies.
349
+ // interfaces (CLI, Vellum) should not re-enable desktop host proxies. The
350
+ // chrome-extension interface only supports host_browser, not the desktop
351
+ // proxies or computer-use, so it is excluded by the no-arg form of
352
+ // supportsHostProxy (which returns false for chrome-extension).
302
353
  const interfaceCtx =
303
354
  queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
304
355
  const sourceInterface = interfaceCtx?.userMessageInterface;
305
- if (sourceInterface === "macos") {
356
+ if (sourceInterface && supportsHostProxy(sourceInterface)) {
306
357
  conversation.restoreProxyAvailability();
307
358
  conversation.addPreactivatedSkillId("computer-use");
308
359
  }
360
+ // Tear down a stale hostBrowserProxy inherited from a prior turn on a
361
+ // different interface (e.g. chrome-extension installed one, then a
362
+ // macos turn drains). Without this, restoreProxyAvailability() above
363
+ // would re-enable the proxy and getCdpClient() would route browser
364
+ // tools through host_browser_request and hang waiting for a client
365
+ // that this turn's interface can't service.
366
+ if (
367
+ sourceInterface &&
368
+ !supportsHostProxy(sourceInterface, "host_browser")
369
+ ) {
370
+ conversation.setHostBrowserProxy(undefined);
371
+ }
309
372
  }
310
373
 
311
374
  // Snapshot persona context at turn start so later tool turns can't pick up
@@ -14,6 +14,7 @@ import type {
14
14
  ServerMessage,
15
15
  UserMessageAttachment,
16
16
  } from "./message-protocol.js";
17
+ import type { ConversationTransportMetadata } from "./message-types/conversations.js";
17
18
 
18
19
  const log = getLogger("conversation-queue");
19
20
 
@@ -29,6 +30,8 @@ export interface QueuedMessage {
29
30
  turnInterfaceContext?: TurnInterfaceContext;
30
31
  /** When false, the turn has no interactive user and should skip clarification prompts. */
31
32
  isInteractive?: boolean;
33
+ /** Transport metadata snapshot captured at enqueue time, applied when this message becomes active. */
34
+ transport?: ConversationTransportMetadata;
32
35
  /** Original user message text to persist to DB when recording intent stripping produced a different `content`. */
33
36
  displayContent?: string;
34
37
  /** Wall-clock time (ms since epoch) when the message was enqueued, used as the display timestamp. */
@@ -155,6 +158,11 @@ function estimateItemBytes(item: QueuedMessage): number {
155
158
  bytes += a.data.length * 2;
156
159
  if (a.extractedText) bytes += a.extractedText.length * 2;
157
160
  }
161
+ // Include transport metadata in the estimate so large transport
162
+ // payloads (e.g. hostHomeDir, hostUsername) count against the budget.
163
+ if (item.transport) {
164
+ bytes += JSON.stringify(item.transport).length * 2;
165
+ }
158
166
  // Small fixed overhead for metadata, pointers, etc. (not worth
159
167
  // measuring precisely — the content/attachment data dominates).
160
168
  bytes += 512;