@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
@@ -21,6 +21,7 @@ import type {
21
21
 
22
22
  import type { PermissionPrompter } from "../permissions/prompter.js";
23
23
  import type { UserDecision } from "../permissions/types.js";
24
+ import { isPermissionControlsV2Enabled } from "../permissions/v2-consent-policy.js";
24
25
  import { getLogger } from "../util/logger.js";
25
26
  import type { CesClient } from "./client.js";
26
27
 
@@ -173,13 +174,7 @@ export async function bridgeCesApproval(
173
174
  signal?: AbortSignal;
174
175
  },
175
176
  ): Promise<CesApprovalBridgeResult> {
176
- const {
177
- proposal,
178
- renderedProposal,
179
- proposalHash,
180
- sessionId,
181
- conversationId,
182
- } = approval;
177
+ const { proposal, renderedProposal, proposalHash, sessionId } = approval;
183
178
 
184
179
  // Non-interactive sessions have no client to respond — fail closed.
185
180
  if (options?.isInteractive === false) {
@@ -194,6 +189,24 @@ export async function bridgeCesApproval(
194
189
  return { outcome: "denied", userDecision: "deny" };
195
190
  }
196
191
 
192
+ if (isPermissionControlsV2Enabled()) {
193
+ log.info(
194
+ {
195
+ event: "ces_approval_bridge_v2_suppressed",
196
+ proposalHash,
197
+ sessionId,
198
+ },
199
+ "CES approval request auto-approved without deterministic prompt under v2",
200
+ );
201
+ const v2Decision = mapUserDecisionToCesDecision("allow");
202
+ return recordCesGrant({
203
+ approval,
204
+ cesClient,
205
+ decision: v2Decision,
206
+ reason: "permission_controls_v2_auto_allow",
207
+ });
208
+ }
209
+
197
210
  // Build the tool name and input for the confirmation prompt. The tool
198
211
  // name uses a `ces:` prefix so the client can distinguish CES approval
199
212
  // requests from regular tool confirmation prompts.
@@ -220,7 +233,6 @@ export async function bridgeCesApproval(
220
233
  [], // No allowlist options — CES manages its own grant patterns
221
234
  [], // No scope options — CES manages scope internally
222
235
  undefined, // No file diff
223
- undefined, // Not sandboxed
224
236
  options?.conversationId,
225
237
  "host", // CES operations target the host
226
238
  false, // Persistent decisions are managed by CES, not trust.json
@@ -263,8 +275,29 @@ export async function bridgeCesApproval(
263
275
  `CES approval bridge: guardian decision is "${cesDecision.grantDecision}"`,
264
276
  );
265
277
 
266
- if (cesDecision.grantDecision === "denied") {
267
- return { outcome: "denied", userDecision: response.decision };
278
+ return recordCesGrant({
279
+ approval,
280
+ cesClient,
281
+ decision: cesDecision,
282
+ reason: response.decisionContext,
283
+ });
284
+ }
285
+
286
+ async function recordCesGrant({
287
+ approval,
288
+ cesClient,
289
+ decision,
290
+ reason,
291
+ }: {
292
+ approval: ApprovalRequired;
293
+ cesClient: CesClient;
294
+ decision: CesApprovalDecision;
295
+ reason?: string;
296
+ }): Promise<CesApprovalBridgeResult> {
297
+ const { proposal, proposalHash, sessionId, conversationId } = approval;
298
+
299
+ if (decision.grantDecision === "denied") {
300
+ return { outcome: "denied", userDecision: decision.userDecision };
268
301
  }
269
302
 
270
303
  // Commit the approved grant to CES via record_grant RPC.
@@ -275,12 +308,12 @@ export async function bridgeCesApproval(
275
308
  decision: {
276
309
  proposal,
277
310
  proposalHash,
278
- decision: cesDecision.grantDecision,
311
+ decision: decision.grantDecision,
279
312
  decidedBy: "guardian",
280
313
  decidedAt: new Date().toISOString(),
281
- reason: response.decisionContext,
282
- ttl: cesDecision.ttl,
283
- grantType: cesDecision.grantType,
314
+ reason,
315
+ ttl: decision.ttl,
316
+ grantType: decision.grantType,
284
317
  },
285
318
  sessionId,
286
319
  conversationId,
@@ -324,7 +357,7 @@ export async function bridgeCesApproval(
324
357
  proposalHash,
325
358
  sessionId,
326
359
  grantId,
327
- userDecision: response.decision,
360
+ userDecision: decision.userDecision,
328
361
  },
329
362
  "CES approval bridge: grant recorded successfully",
330
363
  );
@@ -332,7 +365,7 @@ export async function bridgeCesApproval(
332
365
  return {
333
366
  outcome: "approved",
334
367
  grantId,
335
- userDecision: response.decision,
368
+ userDecision: decision.userDecision,
336
369
  };
337
370
  } catch (err) {
338
371
  const msg = err instanceof Error ? err.message : String(err);
@@ -130,16 +130,12 @@ export async function fetchManagedCatalog(): Promise<FetchManagedCatalogResult>
130
130
 
131
131
  return { ok: true, descriptors };
132
132
  } catch (err) {
133
- const message = err instanceof Error ? err.message : String(err);
134
- const safeMessage = message.replace(
135
- /Api-Key\s+\S+/gi,
136
- "Api-Key [REDACTED]",
137
- );
138
- log.warn(`Failed to fetch managed CES catalog: ${safeMessage}`);
133
+ const errorName = err instanceof Error ? err.constructor.name : "Unknown";
134
+ log.warn(`Failed to fetch managed CES catalog (${errorName})`);
139
135
  return {
140
136
  ok: false,
141
137
  descriptors: [],
142
- error: `Failed to fetch managed CES catalog: ${safeMessage}`,
138
+ error: `Failed to fetch managed CES catalog (${errorName})`,
143
139
  };
144
140
  }
145
141
  }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Tests for `isToolActiveForContext` host-tool capability gating.
3
+ *
4
+ * Two scenarios are verified:
5
+ * - chrome-extension is its own executor and is exempt from the hasNoClient
6
+ * gate (the extension's own popup UI gates commands; there is no SSE
7
+ * interactive approval channel, and chrome-extension turns intentionally
8
+ * run with `hasNoClient: true` because chrome-extension is not in
9
+ * `INTERACTIVE_INTERFACES`).
10
+ * - macos still requires a connected SSE client for interactive approval, so
11
+ * `hasNoClient: true` continues to deny all host tools on macos.
12
+ *
13
+ * The per-capability check (`supportsHostProxy(transport, capability)`) runs
14
+ * first and is authoritative for structural support, so host_bash and
15
+ * host_file_* are filtered out for chrome-extension regardless of the
16
+ * hasNoClient flag.
17
+ */
18
+
19
+ import { describe, expect, test } from "bun:test";
20
+
21
+ import type { SkillProjectionCache } from "../conversation-skill-tools.js";
22
+ import {
23
+ HOST_TOOL_NAMES,
24
+ HOST_TOOL_TO_CAPABILITY,
25
+ isToolActiveForContext,
26
+ type SkillProjectionContext,
27
+ } from "../conversation-tool-setup.js";
28
+
29
+ function makeCtx(
30
+ overrides: Partial<SkillProjectionContext> = {},
31
+ ): SkillProjectionContext {
32
+ return {
33
+ skillProjectionState: new Map(),
34
+ skillProjectionCache: {} as SkillProjectionCache,
35
+ coreToolNames: new Set<string>(),
36
+ toolsDisabledDepth: 0,
37
+ ...overrides,
38
+ };
39
+ }
40
+
41
+ describe("isToolActiveForContext — host tool capability gating", () => {
42
+ // macOS transport: SSE-based interactive approval required.
43
+ test("host_bash is active for macOS with a connected client", () => {
44
+ expect(
45
+ isToolActiveForContext(
46
+ "host_bash",
47
+ makeCtx({ hasNoClient: false, transportInterface: "macos" }),
48
+ ),
49
+ ).toBe(true);
50
+ });
51
+
52
+ test("host_bash is NOT active for macOS when hasNoClient is true (security invariant)", () => {
53
+ // macOS uses an SSE-based interactive approval channel. Without a
54
+ // connected client the guardian auto-approve path could execute host
55
+ // commands unattended, so host tools must be denied.
56
+ expect(
57
+ isToolActiveForContext(
58
+ "host_bash",
59
+ makeCtx({ hasNoClient: true, transportInterface: "macos" }),
60
+ ),
61
+ ).toBe(false);
62
+ });
63
+
64
+ test("host_file_read is NOT active for macOS when hasNoClient is true", () => {
65
+ expect(
66
+ isToolActiveForContext(
67
+ "host_file_read",
68
+ makeCtx({ hasNoClient: true, transportInterface: "macos" }),
69
+ ),
70
+ ).toBe(false);
71
+ });
72
+
73
+ test("host_browser is active for macOS with a connected client", () => {
74
+ expect(
75
+ isToolActiveForContext(
76
+ "host_browser",
77
+ makeCtx({ hasNoClient: false, transportInterface: "macos" }),
78
+ ),
79
+ ).toBe(true);
80
+ });
81
+
82
+ test("host_browser is NOT active for macOS when hasNoClient is true", () => {
83
+ // macOS requires a client for any host tool — the SSE interactive
84
+ // approval channel must be available regardless of capability.
85
+ expect(
86
+ isToolActiveForContext(
87
+ "host_browser",
88
+ makeCtx({ hasNoClient: true, transportInterface: "macos" }),
89
+ ),
90
+ ).toBe(false);
91
+ });
92
+
93
+ // chrome-extension transport: the extension is its own executor.
94
+ test("host_browser is active for chrome-extension even when hasNoClient is true", () => {
95
+ // chrome-extension turns run with `hasNoClient: true` by design because
96
+ // chrome-extension is not in `INTERACTIVE_INTERFACES` — it is not an
97
+ // SSE interactive channel. The extension gates host_browser commands
98
+ // via its own popup UI, so the hasNoClient gate must not filter
99
+ // host_browser out for chrome-extension transports.
100
+ expect(
101
+ isToolActiveForContext(
102
+ "host_browser",
103
+ makeCtx({
104
+ hasNoClient: true,
105
+ transportInterface: "chrome-extension",
106
+ }),
107
+ ),
108
+ ).toBe(true);
109
+ });
110
+
111
+ test("host_browser is active for chrome-extension when hasNoClient is false", () => {
112
+ expect(
113
+ isToolActiveForContext(
114
+ "host_browser",
115
+ makeCtx({
116
+ hasNoClient: false,
117
+ transportInterface: "chrome-extension",
118
+ }),
119
+ ),
120
+ ).toBe(true);
121
+ });
122
+
123
+ test("host_bash is NOT active for chrome-extension even when hasNoClient is true", () => {
124
+ // The per-capability check runs first and is authoritative: chrome-extension
125
+ // only supports `host_browser`, so `host_bash` must be filtered out.
126
+ expect(
127
+ isToolActiveForContext(
128
+ "host_bash",
129
+ makeCtx({
130
+ hasNoClient: true,
131
+ transportInterface: "chrome-extension",
132
+ }),
133
+ ),
134
+ ).toBe(false);
135
+ });
136
+
137
+ test("host_file_read is NOT active for chrome-extension when hasNoClient is true", () => {
138
+ expect(
139
+ isToolActiveForContext(
140
+ "host_file_read",
141
+ makeCtx({
142
+ hasNoClient: true,
143
+ transportInterface: "chrome-extension",
144
+ }),
145
+ ),
146
+ ).toBe(false);
147
+ });
148
+
149
+ // Backwards-compat fallback: no transport plumbed through.
150
+ test("host_bash falls back to hasNoClient gate when transport is undefined (client connected)", () => {
151
+ // Without a transport interface we cannot run the per-capability check,
152
+ // so we fall back to the coarse-grained `hasNoClient` behavior.
153
+ expect(
154
+ isToolActiveForContext(
155
+ "host_bash",
156
+ makeCtx({ hasNoClient: false, transportInterface: undefined }),
157
+ ),
158
+ ).toBe(true);
159
+ });
160
+
161
+ test("host_bash falls back to hasNoClient gate when transport is undefined (no client)", () => {
162
+ expect(
163
+ isToolActiveForContext(
164
+ "host_bash",
165
+ makeCtx({ hasNoClient: true, transportInterface: undefined }),
166
+ ),
167
+ ).toBe(false);
168
+ });
169
+ });
170
+
171
+ describe("HOST_TOOL_NAMES derivation", () => {
172
+ test("HOST_TOOL_NAMES is derived from HOST_TOOL_TO_CAPABILITY", () => {
173
+ // Sanity check: every tool in the names set has a capability mapping.
174
+ // This is structurally enforced by the code (HOST_TOOL_NAMES is built
175
+ // from HOST_TOOL_TO_CAPABILITY.keys()), but we test it to make the
176
+ // invariant visible to readers and to catch any regression that
177
+ // splits the two collections back apart.
178
+ for (const name of HOST_TOOL_NAMES) {
179
+ expect(HOST_TOOL_TO_CAPABILITY.has(name)).toBe(true);
180
+ }
181
+ // Cardinality check: the two collections must have the same size so a
182
+ // future addition to HOST_TOOL_NAMES without a matching capability entry
183
+ // (or vice versa) would fail.
184
+ expect(HOST_TOOL_NAMES.size).toBe(HOST_TOOL_TO_CAPABILITY.size);
185
+ });
186
+ });
@@ -24,6 +24,20 @@ const APP_REFRESH_DEBOUNCE_MS = 500;
24
24
 
25
25
  export type AppSourceChangeCallback = (appId: string) => void;
26
26
 
27
+ /**
28
+ * Module-level callback so tool-side-effects can ensure the watcher starts
29
+ * after the apps directory is created (e.g. on first app_create).
30
+ */
31
+ let ensureWatcherStarted: (() => void) | null = null;
32
+
33
+ export function setEnsureAppSourceWatcher(fn: () => void): void {
34
+ ensureWatcherStarted = fn;
35
+ }
36
+
37
+ export function ensureAppSourceWatcher(): void {
38
+ ensureWatcherStarted?.();
39
+ }
40
+
27
41
  /**
28
42
  * Resolve app ID from a relative path within the apps directory.
29
43
  * Returns null if the path is not an app source file (e.g. dist/, records/).
@@ -48,12 +62,29 @@ function resolveAppIdFromRelPath(relPath: string): string | null {
48
62
 
49
63
  export class AppSourceWatcher {
50
64
  private watcher: FSWatcher | null = null;
65
+ private onChange: AppSourceChangeCallback | null = null;
51
66
  private debouncer = new DebouncerMap({
52
67
  defaultDelayMs: APP_REFRESH_DEBOUNCE_MS,
53
68
  maxEntries: 50,
54
69
  });
55
70
 
56
71
  start(onChange: AppSourceChangeCallback): void {
72
+ this.onChange = onChange;
73
+ this.tryWatch();
74
+ }
75
+
76
+ /**
77
+ * Ensure the watcher is running. Call after app creation so the watcher
78
+ * starts if the apps directory was created after daemon startup.
79
+ */
80
+ ensureStarted(): void {
81
+ if (this.watcher || !this.onChange) return;
82
+ this.tryWatch();
83
+ }
84
+
85
+ private tryWatch(): void {
86
+ if (this.watcher) return;
87
+
57
88
  let appsDir: string;
58
89
  try {
59
90
  appsDir = getAppsDir();
@@ -67,6 +98,9 @@ export class AppSourceWatcher {
67
98
  return;
68
99
  }
69
100
 
101
+ const onChange = this.onChange;
102
+ if (!onChange) return;
103
+
70
104
  try {
71
105
  this.watcher = watch(appsDir, { recursive: true }, (_eventType, filename) => {
72
106
  if (!filename) return;
@@ -78,6 +112,7 @@ export class AppSourceWatcher {
78
112
  onChange(appId);
79
113
  });
80
114
  });
115
+ log.info("App source watcher started");
81
116
  } catch (err) {
82
117
  log.warn({ err }, "Failed to watch apps directory; source watching disabled");
83
118
  }
@@ -118,6 +118,8 @@ export class ConfigWatcher {
118
118
  onIdentityChanged?: () => void,
119
119
  onSoundsConfigChanged?: () => void,
120
120
  onAvatarChanged?: () => void,
121
+ onConfigChanged?: () => void,
122
+ onFeatureFlagsChanged?: () => void,
121
123
  ): void {
122
124
  const workspaceDir = getWorkspaceDir();
123
125
 
@@ -130,6 +132,7 @@ export class ConfigWatcher {
130
132
  const changed = await this.refreshConfigFromSources();
131
133
  if (changed) {
132
134
  onConversationEvict();
135
+ onConfigChanged?.();
133
136
  const newConfig = getConfig();
134
137
  const newMcpFingerprint = JSON.stringify(newConfig.mcp ?? {});
135
138
  if (newMcpFingerprint !== prevMcpFingerprint) {
@@ -190,7 +193,7 @@ export class ConfigWatcher {
190
193
  this.startAvatarWatcher(onAvatarChanged);
191
194
  }
192
195
 
193
- this.startFeatureFlagsWatcher();
196
+ this.startFeatureFlagsWatcher(onFeatureFlagsChanged);
194
197
  this.startSignalsWatcher();
195
198
  this.startSkillsWatchers(onConversationEvict);
196
199
  }
@@ -266,7 +269,7 @@ export class ConfigWatcher {
266
269
  }
267
270
  }
268
271
 
269
- private startFeatureFlagsWatcher(): void {
272
+ private startFeatureFlagsWatcher(onFeatureFlagsChanged?: () => void): void {
270
273
  const protectedDir = process.env.GATEWAY_SECURITY_DIR
271
274
  ? process.env.GATEWAY_SECURITY_DIR
272
275
  : join(homedir(), ".vellum", "protected");
@@ -297,6 +300,7 @@ export class ConfigWatcher {
297
300
  "Feature flags file changed, invalidating cache",
298
301
  );
299
302
  clearFeatureFlagOverridesCache();
303
+ onFeatureFlagsChanged?.();
300
304
  },
301
305
  500,
302
306
  );
@@ -1,5 +1,6 @@
1
1
  import type { PermissionPrompter } from "../permissions/prompter.js";
2
2
  import { isAllowDecision } from "../permissions/types.js";
3
+ import { isPermissionControlsV2Enabled } from "../permissions/v2-consent-policy.js";
3
4
 
4
5
  /**
5
6
  * Reserved pseudo tool name used for context overflow compression approval
@@ -26,6 +27,10 @@ export async function requestCompressionApproval(
26
27
  prompter: PermissionPrompter,
27
28
  opts?: { signal?: AbortSignal },
28
29
  ): Promise<CompressionApprovalResult> {
30
+ if (isPermissionControlsV2Enabled()) {
31
+ return { approved: true };
32
+ }
33
+
29
34
  const result = await prompter.prompt(
30
35
  CONTEXT_OVERFLOW_TOOL_NAME,
31
36
  {
@@ -39,7 +44,6 @@ export async function requestCompressionApproval(
39
44
  undefined,
40
45
  undefined,
41
46
  undefined,
42
- undefined,
43
47
  false,
44
48
  opts?.signal,
45
49
  );
@@ -932,10 +932,25 @@ export async function dispatchAgentEvent(
932
932
  "assistant_turn",
933
933
  deps.reqId,
934
934
  );
935
+
936
+ // Format web search results into a human-readable string for the client.
937
+ let resultText = "";
938
+ if (Array.isArray(event.content) && event.content.length > 0) {
939
+ resultText = (event.content as unknown[])
940
+ .filter(
941
+ (r): r is { type: string; title: string; url: string } =>
942
+ typeof r === "object" &&
943
+ r != null &&
944
+ (r as { type?: string }).type === "web_search_result",
945
+ )
946
+ .map((r) => `${r.title}\n${r.url}`)
947
+ .join("\n\n");
948
+ }
949
+
935
950
  deps.onEvent({
936
951
  type: "tool_result",
937
- toolName: "",
938
- result: "",
952
+ toolName: "web_search",
953
+ result: resultText,
939
954
  isError: event.isError,
940
955
  conversationId: deps.ctx.conversationId,
941
956
  toolUseId: event.toolUseId,