@vellumai/assistant 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docs/architecture/memory.md +1 -1
  4. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  5. package/openapi.yaml +184 -69
  6. package/package.json +41 -41
  7. package/scripts/generate-openapi.ts +1 -2
  8. package/src/__tests__/acp-session.test.ts +43 -0
  9. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  10. package/src/__tests__/app-executors.test.ts +1 -0
  11. package/src/__tests__/app-source-watcher.test.ts +37 -11
  12. package/src/__tests__/approval-routes-http.test.ts +178 -1
  13. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  14. package/src/__tests__/browser-manager.test.ts +40 -27
  15. package/src/__tests__/catalog-files.test.ts +862 -0
  16. package/src/__tests__/channel-approvals.test.ts +53 -0
  17. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  18. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  19. package/src/__tests__/config-schema.test.ts +125 -48
  20. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  21. package/src/__tests__/context-overflow-approval.test.ts +16 -1
  22. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  23. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  24. package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
  25. package/src/__tests__/conversation-attachments.test.ts +80 -4
  26. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  27. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  28. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  29. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  30. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  31. package/src/__tests__/conversation-queue.test.ts +45 -2
  32. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  33. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  34. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  35. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  36. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  37. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  38. package/src/__tests__/conversation-store.test.ts +195 -0
  39. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  40. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
  41. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  42. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  43. package/src/__tests__/credential-vault.test.ts +152 -13
  44. package/src/__tests__/credentials-cli.test.ts +2 -2
  45. package/src/__tests__/date-context.test.ts +4 -4
  46. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  47. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  48. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  49. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  50. package/src/__tests__/gemini-provider.test.ts +2 -2
  51. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  52. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  53. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  54. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  55. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  56. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  57. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  58. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  59. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  60. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  61. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  62. package/src/__tests__/host-browser-routes.test.ts +198 -0
  63. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  64. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  65. package/src/__tests__/host-file-proxy.test.ts +185 -1
  66. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  67. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  68. package/src/__tests__/host-shell-tool.test.ts +1 -11
  69. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  70. package/src/__tests__/integration-status.test.ts +6 -7
  71. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  72. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  73. package/src/__tests__/mcp-health-check.test.ts +10 -3
  74. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  75. package/src/__tests__/migration-export-http.test.ts +61 -2
  76. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  77. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  78. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  79. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  80. package/src/__tests__/oauth-cli.test.ts +707 -60
  81. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  82. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  83. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  84. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  85. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  86. package/src/__tests__/oauth-store.test.ts +1386 -182
  87. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  88. package/src/__tests__/onboarding-template-contract.test.ts +75 -57
  89. package/src/__tests__/openai-provider.test.ts +2 -2
  90. package/src/__tests__/outlook-categories.test.ts +1 -1
  91. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  92. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  93. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  94. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  95. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  96. package/src/__tests__/outlook-trash.test.ts +1 -1
  97. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  98. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  99. package/src/__tests__/permission-mode.test.ts +28 -56
  100. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  101. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  102. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  103. package/src/__tests__/require-fresh-approval.test.ts +40 -1
  104. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  105. package/src/__tests__/schedule-routes.test.ts +162 -0
  106. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  107. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  108. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  109. package/src/__tests__/set-permission-mode.test.ts +13 -250
  110. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  111. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  112. package/src/__tests__/slack-channel-config.test.ts +12 -15
  113. package/src/__tests__/subagent-detail.test.ts +44 -2
  114. package/src/__tests__/subagent-disposal.test.ts +1 -0
  115. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  116. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  117. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  118. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  119. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  120. package/src/__tests__/subagent-tools.test.ts +1 -0
  121. package/src/__tests__/subagent-types.test.ts +1 -0
  122. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  123. package/src/__tests__/system-prompt.test.ts +72 -1
  124. package/src/__tests__/task-scheduler.test.ts +32 -6
  125. package/src/__tests__/telegram-config.test.ts +10 -13
  126. package/src/__tests__/terminal-tools.test.ts +9 -0
  127. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  128. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  129. package/src/__tests__/top-level-renderer.test.ts +73 -1
  130. package/src/__tests__/transport-hints-queue.test.ts +14 -29
  131. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  132. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  133. package/src/acp/client-handler.ts +30 -4
  134. package/src/agent/loop.ts +12 -6
  135. package/src/approvals/guardian-request-resolvers.ts +21 -15
  136. package/src/browser-session/__tests__/manager.test.ts +297 -0
  137. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  138. package/src/browser-session/backends/extension.ts +26 -0
  139. package/src/browser-session/backends/local.ts +24 -0
  140. package/src/browser-session/events.ts +164 -0
  141. package/src/browser-session/index.ts +27 -0
  142. package/src/browser-session/manager.ts +159 -0
  143. package/src/browser-session/types.ts +28 -0
  144. package/src/channels/__tests__/types.test.ts +134 -0
  145. package/src/channels/types.ts +53 -3
  146. package/src/cli/commands/browser-relay.ts +339 -409
  147. package/src/cli/commands/credentials.ts +3 -3
  148. package/src/cli/commands/email.ts +18 -13
  149. package/src/cli/commands/mcp.ts +16 -4
  150. package/src/cli/commands/oauth/__tests__/connect.test.ts +44 -44
  151. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  152. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  153. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  154. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  155. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  156. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  157. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  158. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  159. package/src/cli/commands/oauth/apps.ts +7 -4
  160. package/src/cli/commands/oauth/connect.ts +6 -3
  161. package/src/cli/commands/oauth/disconnect.ts +1 -1
  162. package/src/cli/commands/oauth/providers.ts +200 -36
  163. package/src/cli/commands/oauth/shared.ts +5 -5
  164. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  165. package/src/cli/commands/platform/index.ts +107 -10
  166. package/src/cli/commands/usage.ts +10 -9
  167. package/src/cli/lib/daemon-credential-client.ts +4 -0
  168. package/src/cli/program.ts +1 -1
  169. package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
  170. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  171. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  172. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  173. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  174. package/src/config/bundled-skills/document/SKILL.md +4 -0
  175. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  176. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  177. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  178. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  179. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  180. package/src/config/env-registry.ts +14 -0
  181. package/src/config/env.ts +21 -0
  182. package/src/config/feature-flag-registry.json +44 -5
  183. package/src/config/loader.ts +56 -1
  184. package/src/config/sanitize-for-transfer.ts +47 -0
  185. package/src/config/schema.ts +46 -5
  186. package/src/config/schemas/host-browser.ts +66 -0
  187. package/src/config/schemas/memory-lifecycle.ts +1 -1
  188. package/src/config/schemas/memory-retrieval.ts +103 -0
  189. package/src/config/schemas/security.ts +0 -6
  190. package/src/config/schemas/services.ts +8 -0
  191. package/src/config/types.ts +0 -1
  192. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  193. package/src/context/window-manager.ts +19 -1
  194. package/src/credential-execution/approval-bridge.ts +49 -15
  195. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  196. package/src/daemon/app-source-watcher.ts +35 -0
  197. package/src/daemon/context-overflow-approval.ts +5 -0
  198. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  199. package/src/daemon/conversation-agent-loop.ts +58 -24
  200. package/src/daemon/conversation-attachments.ts +40 -0
  201. package/src/daemon/conversation-process.ts +48 -1
  202. package/src/daemon/conversation-runtime-assembly.ts +118 -36
  203. package/src/daemon/conversation-surfaces.ts +37 -36
  204. package/src/daemon/conversation-tool-setup.ts +74 -8
  205. package/src/daemon/conversation-workspace.ts +12 -0
  206. package/src/daemon/conversation.ts +226 -8
  207. package/src/daemon/date-context.ts +10 -10
  208. package/src/daemon/first-greeting.ts +3 -2
  209. package/src/daemon/handlers/conversations.ts +9 -140
  210. package/src/daemon/handlers/shared.ts +58 -0
  211. package/src/daemon/handlers/skills.ts +232 -37
  212. package/src/daemon/host-bash-proxy.ts +48 -13
  213. package/src/daemon/host-browser-proxy.ts +191 -0
  214. package/src/daemon/host-cu-proxy.ts +36 -11
  215. package/src/daemon/host-file-proxy.ts +57 -9
  216. package/src/daemon/lifecycle.ts +65 -11
  217. package/src/daemon/message-protocol.ts +7 -0
  218. package/src/daemon/message-types/conversations.ts +55 -13
  219. package/src/daemon/message-types/host-browser.ts +100 -0
  220. package/src/daemon/message-types/messages.ts +5 -5
  221. package/src/daemon/message-types/skills.ts +10 -0
  222. package/src/daemon/message-types/subagents.ts +2 -0
  223. package/src/daemon/server.ts +92 -12
  224. package/src/daemon/tool-side-effects.ts +6 -0
  225. package/src/daemon/transport-hints.ts +5 -24
  226. package/src/inbound/platform-callback-registration.ts +18 -17
  227. package/src/mcp/client.ts +59 -24
  228. package/src/memory/app-store.ts +31 -1
  229. package/src/memory/conversation-crud.ts +23 -0
  230. package/src/memory/conversation-starters-cadence.ts +76 -0
  231. package/src/memory/conversation-title-service.ts +5 -2
  232. package/src/memory/db-init.ts +12 -0
  233. package/src/memory/embedding-backend.test.ts +75 -0
  234. package/src/memory/embedding-backend.ts +131 -5
  235. package/src/memory/embedding-gemini.test.ts +54 -0
  236. package/src/memory/embedding-gemini.ts +20 -9
  237. package/src/memory/embedding-local.ts +176 -17
  238. package/src/memory/graph/consolidation.ts +10 -23
  239. package/src/memory/graph/extraction-job.ts +15 -0
  240. package/src/memory/graph/retriever.ts +40 -22
  241. package/src/memory/graph/store.test.ts +7 -3
  242. package/src/memory/graph/store.ts +47 -12
  243. package/src/memory/llm-usage-store.ts +45 -4
  244. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  245. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  246. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  247. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  248. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  249. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  250. package/src/memory/migrations/index.ts +6 -0
  251. package/src/memory/migrations/registry.ts +8 -0
  252. package/src/memory/schema/conversations.ts +1 -0
  253. package/src/memory/schema/oauth.ts +18 -13
  254. package/src/oauth/AGENTS.md +76 -0
  255. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  256. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  257. package/src/oauth/byo-connection.test.ts +8 -8
  258. package/src/oauth/byo-connection.ts +7 -7
  259. package/src/oauth/connect-orchestrator.ts +23 -21
  260. package/src/oauth/connect-types.ts +3 -3
  261. package/src/oauth/connection-resolver.test.ts +17 -4
  262. package/src/oauth/connection-resolver.ts +16 -16
  263. package/src/oauth/connection.ts +1 -1
  264. package/src/oauth/manual-token-connection.ts +13 -13
  265. package/src/oauth/oauth-store.ts +214 -100
  266. package/src/oauth/platform-connection.test.ts +3 -3
  267. package/src/oauth/platform-connection.ts +4 -4
  268. package/src/oauth/provider-serializer.ts +31 -5
  269. package/src/oauth/revoke.ts +76 -0
  270. package/src/oauth/seed-providers.ts +126 -87
  271. package/src/oauth/token-persistence.ts +1 -1
  272. package/src/permissions/permission-mode.ts +4 -11
  273. package/src/permissions/prompter.ts +13 -1
  274. package/src/permissions/v2-consent-policy.ts +87 -0
  275. package/src/prompts/system-prompt.ts +18 -21
  276. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  277. package/src/prompts/templates/BOOTSTRAP.md +59 -105
  278. package/src/providers/anthropic/client.ts +1 -0
  279. package/src/providers/types.ts +1 -1
  280. package/src/runtime/AGENTS.md +23 -0
  281. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  282. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  283. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  284. package/src/runtime/assistant-event-hub.ts +2 -2
  285. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  286. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  287. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  288. package/src/runtime/auth/middleware.ts +98 -0
  289. package/src/runtime/auth/route-policy.ts +6 -7
  290. package/src/runtime/capability-tokens.ts +414 -0
  291. package/src/runtime/channel-approvals.ts +18 -5
  292. package/src/runtime/chrome-extension-registry.ts +332 -0
  293. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  294. package/src/runtime/guardian-decision-types.ts +7 -0
  295. package/src/runtime/http-server.ts +425 -70
  296. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  297. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  298. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  299. package/src/runtime/migrations/migration-transport.ts +6 -0
  300. package/src/runtime/migrations/migration-wizard.ts +22 -2
  301. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  302. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  303. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  304. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  305. package/src/runtime/pending-interactions.ts +29 -13
  306. package/src/runtime/routes/approval-routes.ts +90 -16
  307. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  308. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  309. package/src/runtime/routes/conversation-analysis-routes.ts +2 -1
  310. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  311. package/src/runtime/routes/conversation-routes.ts +301 -27
  312. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  313. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  314. package/src/runtime/routes/host-browser-routes.ts +279 -0
  315. package/src/runtime/routes/host-file-routes.ts +9 -1
  316. package/src/runtime/routes/identity-routes.ts +259 -16
  317. package/src/runtime/routes/log-export-routes.ts +42 -22
  318. package/src/runtime/routes/memory-item-routes.ts +1 -7
  319. package/src/runtime/routes/migration-routes.ts +87 -2
  320. package/src/runtime/routes/oauth-apps.ts +15 -17
  321. package/src/runtime/routes/oauth-providers.ts +4 -0
  322. package/src/runtime/routes/schedule-routes.ts +24 -11
  323. package/src/runtime/routes/settings-routes.ts +9 -97
  324. package/src/runtime/routes/skills-routes.ts +52 -2
  325. package/src/runtime/routes/subagents-routes.ts +14 -10
  326. package/src/runtime/routes/usage-routes.ts +8 -7
  327. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  328. package/src/runtime/routes/workspace-routes.ts +8 -1
  329. package/src/runtime/routes/workspace-utils.ts +2 -0
  330. package/src/schedule/scheduler.ts +7 -5
  331. package/src/security/ces-credential-client.ts +20 -0
  332. package/src/security/ces-rpc-credential-backend.ts +17 -0
  333. package/src/security/credential-backend.ts +5 -0
  334. package/src/security/oauth2.ts +42 -25
  335. package/src/security/secure-keys.ts +118 -25
  336. package/src/security/token-manager.ts +23 -10
  337. package/src/skills/catalog-files.ts +492 -0
  338. package/src/subagent/manager.ts +131 -26
  339. package/src/subagent/types.ts +19 -0
  340. package/src/tools/apps/executors.ts +11 -2
  341. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  342. package/src/tools/browser/auth-detector.ts +43 -12
  343. package/src/tools/browser/browser-execution.ts +645 -340
  344. package/src/tools/browser/browser-manager.ts +36 -12
  345. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  346. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  347. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  348. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  349. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  350. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  351. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  352. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  353. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  354. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  355. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  356. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  357. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  358. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  359. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  360. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  361. package/src/tools/browser/cdp-client/errors.ts +34 -0
  362. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  363. package/src/tools/browser/cdp-client/factory.ts +204 -0
  364. package/src/tools/browser/cdp-client/index.ts +14 -0
  365. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  366. package/src/tools/browser/cdp-client/types.ts +52 -0
  367. package/src/tools/filesystem/edit.ts +1 -1
  368. package/src/tools/filesystem/list.ts +1 -1
  369. package/src/tools/filesystem/read.ts +1 -1
  370. package/src/tools/filesystem/write.ts +2 -1
  371. package/src/tools/host-filesystem/edit.ts +1 -1
  372. package/src/tools/host-filesystem/read.ts +12 -15
  373. package/src/tools/host-filesystem/write.ts +1 -1
  374. package/src/tools/host-terminal/host-shell.ts +21 -16
  375. package/src/tools/permission-checker.ts +77 -82
  376. package/src/tools/registry.ts +0 -2
  377. package/src/tools/secret-detection-handler.ts +34 -0
  378. package/src/tools/shared/filesystem/image-read.ts +61 -40
  379. package/src/tools/subagent/spawn.ts +47 -3
  380. package/src/tools/subagent/status.ts +2 -0
  381. package/src/tools/system/register.ts +2 -16
  382. package/src/tools/terminal/safe-env.ts +7 -0
  383. package/src/tools/terminal/shell.ts +21 -16
  384. package/src/tools/tool-approval-handler.ts +48 -2
  385. package/src/tools/types.ts +2 -0
  386. package/src/util/platform.ts +14 -19
  387. package/src/workspace/top-level-renderer.ts +19 -1
  388. package/src/__tests__/chrome-cdp.test.ts +0 -419
  389. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  390. package/src/__tests__/permission-mode-store.test.ts +0 -277
  391. package/src/browser-extension-relay/protocol.ts +0 -63
  392. package/src/browser-extension-relay/server.ts +0 -203
  393. package/src/config/schemas/sandbox.ts +0 -14
  394. package/src/permissions/permission-mode-store.ts +0 -180
  395. package/src/tools/browser/chrome-cdp.ts +0 -239
  396. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -142,6 +142,14 @@ export class SubagentManager {
142
142
  */
143
143
  broadcastToAllClients?: (msg: ServerMessage) => void;
144
144
 
145
+ /**
146
+ * Resolve a live parent Conversation by conversationId.
147
+ * Wired by DaemonServer at startup — follows the same pattern as
148
+ * `onSubagentFinished`. Used by fork spawn to resolve the parent's
149
+ * system prompt when `config.parentSystemPrompt` is not provided.
150
+ */
151
+ resolveParentConversation?: (conversationId: string) => Conversation | undefined;
152
+
145
153
  // ── Spawn ───────────────────────────────────────────────────────────
146
154
 
147
155
  /**
@@ -165,7 +173,19 @@ export class SubagentManager {
165
173
  }
166
174
 
167
175
  // ── Resolve role ─────────────────────────────────────────────────
168
- const role: SubagentRole = (config.role as SubagentRole) ?? "general";
176
+ const isFork = config.fork === true;
177
+ let role: SubagentRole = (config.role as SubagentRole) ?? "general";
178
+ if (isFork && role !== "general") {
179
+ log.warn(
180
+ {
181
+ requestedRole: role,
182
+ parentConversationId: config.parentConversationId,
183
+ label: config.label,
184
+ },
185
+ "Fork requested with non-general role — forcing general to preserve KV cache alignment",
186
+ );
187
+ role = "general";
188
+ }
169
189
  if (!SUBAGENT_ROLE_REGISTRY[role]) {
170
190
  throw new Error(
171
191
  `Invalid subagent role "${config.role}". Must be one of: ${Object.keys(SUBAGENT_ROLE_REGISTRY).join(", ")}`,
@@ -194,24 +214,58 @@ export class SubagentManager {
194
214
  );
195
215
  }
196
216
 
197
- const systemPrompt =
198
- config.systemPromptOverride ??
199
- buildSubagentSystemPrompt({ ...config, id: subagentId }, role);
217
+ let systemPrompt: string;
218
+ if (isFork) {
219
+ // Forks use the parent's system prompt directly — no subagent preamble.
220
+ if (config.parentSystemPrompt) {
221
+ systemPrompt = config.parentSystemPrompt;
222
+ } else if (this.resolveParentConversation) {
223
+ const parentConv = this.resolveParentConversation(config.parentConversationId);
224
+ const resolved = parentConv?.getCurrentSystemPrompt();
225
+ if (!resolved) {
226
+ throw new Error(
227
+ "Fork spawn requires a parent system prompt but neither config.parentSystemPrompt " +
228
+ "nor resolveParentConversation yielded one.",
229
+ );
230
+ }
231
+ systemPrompt = resolved;
232
+ } else {
233
+ throw new Error(
234
+ "Fork spawn requires a parent system prompt but neither config.parentSystemPrompt " +
235
+ "is set nor resolveParentConversation callback is wired.",
236
+ );
237
+ }
238
+ } else {
239
+ systemPrompt =
240
+ config.systemPromptOverride ??
241
+ buildSubagentSystemPrompt({ ...config, id: subagentId }, role);
242
+ }
200
243
  const maxTokens = appConfig.maxTokens;
201
244
  const workingDir = getSandboxWorkingDir();
202
245
 
203
- const memoryPolicy: ConversationMemoryPolicy = {
204
- scopeId: `subagent:${subagentId}`,
205
- includeDefaultFallback: true,
206
- strictSideEffects: false,
207
- };
246
+ const memoryPolicy: ConversationMemoryPolicy = isFork
247
+ ? {
248
+ scopeId: "default",
249
+ includeDefaultFallback: false,
250
+ strictSideEffects: false,
251
+ }
252
+ : {
253
+ scopeId: `subagent:${subagentId}`,
254
+ includeDefaultFallback: true,
255
+ strictSideEffects: false,
256
+ };
208
257
 
209
258
  // ── Initialise state ────────────────────────────────────────────
210
259
  const now = Date.now();
260
+ // For forks, default sendResultToUser to false (silent) unless explicitly true.
261
+ const resolvedSendResultToUser = isFork
262
+ ? (config.sendResultToUser === true ? true : false)
263
+ : config.sendResultToUser;
211
264
  const state: SubagentState = {
212
- config: { ...config, id: subagentId },
265
+ config: { ...config, id: subagentId, sendResultToUser: resolvedSendResultToUser },
213
266
  status: "pending",
214
267
  conversationId: conversationRecord.id,
268
+ isFork,
215
269
  createdAt: now,
216
270
  usage: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
217
271
  };
@@ -255,8 +309,16 @@ export class SubagentManager {
255
309
  conversation.updateClient(wrappedSendToClient, true);
256
310
  conversation.setIsSubagent(true);
257
311
 
312
+ if (isFork) {
313
+ // Force the fork to use the parent's system prompt as-is without dynamic rebuild.
314
+ // This ensures KV cache alignment with the parent conversation.
315
+ conversation.hasSystemPromptOverride = true;
316
+ }
317
+
258
318
  // Apply role-based tool filter if the role defines one.
259
- if (roleConfig.allowedTools) {
319
+ // Skip for forks — general role has allowedTools: undefined, and forks
320
+ // should have the same tool access as the parent.
321
+ if (!isFork && roleConfig.allowedTools) {
260
322
  conversation.setSubagentAllowedTools(new Set(roleConfig.allowedTools));
261
323
  }
262
324
 
@@ -298,6 +360,7 @@ export class SubagentManager {
298
360
  parentConversationId: config.parentConversationId,
299
361
  label: config.label,
300
362
  objective: config.objective,
363
+ isFork: config.fork ?? false,
301
364
  } as ServerMessage);
302
365
 
303
366
  log.info(
@@ -339,9 +402,37 @@ export class SubagentManager {
339
402
  const onEvent = conversation.sendToClient;
340
403
 
341
404
  try {
405
+ // For forks, inject the parent's message history before the first message.
406
+ // This prepends the inherited context so the fork has full conversational
407
+ // awareness while the objective becomes the latest user turn.
408
+ if (managed.state.isFork && managed.state.config.parentMessages) {
409
+ conversation.injectInheritedContext(managed.state.config.parentMessages);
410
+ // Release the parent message arrays now that they've been injected — holding
411
+ // them in SubagentState.config would retain significant memory until the TTL
412
+ // sweep disposes this entry (up to 30 minutes for terminal subagents).
413
+ managed.state.config.parentMessages = undefined;
414
+ managed.state.config.parentSystemPrompt = undefined;
415
+ }
416
+
342
417
  // Send the objective as the first user message and process it.
343
- const messageId = await conversation.persistUserMessage(objective, []);
344
- await conversation.runAgentLoop(objective, messageId, onEvent);
418
+ // For forks, wrap the objective in directive framing so it overrides
419
+ // conversational momentum from the inherited context. Without this,
420
+ // the fork tends to continue the parent conversation instead of
421
+ // pivoting to the task — the inherited context is louder than a bare
422
+ // objective buried after 100k+ tokens of chat history.
423
+ const message = managed.state.isFork
424
+ ? [
425
+ "⎯⎯⎯ FORK TASK ⎯⎯⎯",
426
+ "You have been forked from the parent conversation to execute a specific task.",
427
+ "The conversation above is context — do NOT continue it. Do NOT spawn sub-agents.",
428
+ "Complete this task directly and return only your findings:",
429
+ "",
430
+ objective,
431
+ "⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯",
432
+ ].join("\n")
433
+ : objective;
434
+ const messageId = await conversation.persistUserMessage(message, []);
435
+ await conversation.runAgentLoop(message, messageId, onEvent);
345
436
 
346
437
  // Agent loop completed successfully.
347
438
  // Copy usage stats from the conversation before sending status (which includes usage).
@@ -431,9 +522,10 @@ export class SubagentManager {
431
522
  // Skip when the parent LLM itself called subagent_abort (it already has the tool result).
432
523
  if (this.onSubagentFinished && !options?.suppressNotification) {
433
524
  const label = managed.state.config.label;
525
+ const prefix = managed.state.isFork ? "Fork" : "Subagent";
434
526
  const message =
435
- `[Subagent "${label}" was explicitly aborted]\n\n` +
436
- `This subagent was cancelled on purpose. Do NOT re-spawn or retry it.`;
527
+ `[${prefix} "${label}" was explicitly aborted]\n\n` +
528
+ `This ${prefix.toLowerCase()} was cancelled on purpose. Do NOT re-spawn or retry it.`;
437
529
  try {
438
530
  // Use the managed subagent's stored parentSendToClient so the
439
531
  // notification routes to the parent conversation's socket, not the
@@ -781,10 +873,11 @@ export class SubagentManager {
781
873
  if (!managed || TERMINAL_STATUSES.has(managed.state.status)) return false;
782
874
  if (!this.onSubagentFinished) return false;
783
875
 
784
- let notificationString = `[Subagent "${info.label}" ${urgency}] ${message}`;
876
+ const prefix = managed.state.isFork ? "Fork" : "Subagent";
877
+ let notificationString = `[${prefix} "${info.label}" — ${urgency}] ${message}`;
785
878
  if (urgency === "blocked") {
786
879
  notificationString +=
787
- "\nUse subagent_message to send guidance to this subagent.";
880
+ `\nUse subagent_message to send guidance to this ${prefix.toLowerCase()}.`;
788
881
  }
789
882
 
790
883
  try {
@@ -820,22 +913,34 @@ export class SubagentManager {
820
913
  if (!this.onSubagentFinished) return;
821
914
 
822
915
  const { config } = managed.state;
916
+ const isFork = managed.state.isFork;
823
917
  let message: string;
824
918
 
825
919
  if (outcome === "completed") {
826
- const silent = config.sendResultToUser === false;
827
- message =
828
- `[Subagent "${config.label}" completed]\n\n` +
829
- `Use subagent_read with subagent_id "${config.id}" to retrieve the full output.\n` +
830
- (silent
831
- ? `This subagent was spawned for internal processing. Read the result for your own use but do NOT share it with the user.\nDo NOT re-spawn this subagent.`
832
- : `Do NOT re-spawn this subagentjust read and share the results.`);
920
+ if (isFork) {
921
+ const silent = config.sendResultToUser !== true;
922
+ message =
923
+ `[Fork "${config.label}" completed]\n\n` +
924
+ `Use subagent_read with subagent_id "${config.id}" and last_n: 1 to retrieve the final synthesis.\n` +
925
+ (silent
926
+ ? `This fork was spawned for internal processing. Process the findings internally do NOT share raw fork output with the user.`
927
+ : `Do NOT re-spawn this fork — just read and share the results.`);
928
+ } else {
929
+ const silent = config.sendResultToUser === false;
930
+ message =
931
+ `[Subagent "${config.label}" completed]\n\n` +
932
+ `Use subagent_read with subagent_id "${config.id}" to retrieve the full output.\n` +
933
+ (silent
934
+ ? `This subagent was spawned for internal processing. Read the result for your own use but do NOT share it with the user.\nDo NOT re-spawn this subagent.`
935
+ : `Do NOT re-spawn this subagent — just read and share the results.`);
936
+ }
833
937
  } else {
834
938
  const error = managed.state.error ?? "Unknown error";
939
+ const prefix = isFork ? "Fork" : "Subagent";
835
940
  message =
836
- `[Subagent "${config.label}" failed]\n\n` +
941
+ `[${prefix} "${config.label}" failed]\n\n` +
837
942
  `Error: ${error}\n` +
838
- `Do NOT re-spawn or retry this subagent unless the user explicitly asks.`;
943
+ `Do NOT re-spawn or retry this ${prefix.toLowerCase()} unless the user explicitly asks.`;
839
944
  }
840
945
 
841
946
  const notification: SubagentNotificationInfo = {
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import type { UsageStats } from "../daemon/message-protocol.js";
10
+ import type { Message } from "../providers/types.js";
10
11
 
11
12
  // ── Status ──────────────────────────────────────────────────────────────
12
13
 
@@ -43,6 +44,22 @@ export interface SubagentConfig {
43
44
  sendResultToUser?: boolean;
44
45
  /** Optional role for the subagent. Defaults handled by consumers. */
45
46
  role?: SubagentRole;
47
+ /**
48
+ * When true, the sub-agent inherits the parent's full context instead of
49
+ * receiving only the objective + context fields.
50
+ */
51
+ fork?: boolean;
52
+ /**
53
+ * The parent conversation's in-memory message history at fork time.
54
+ * Only set when `fork: true`.
55
+ */
56
+ parentMessages?: Message[];
57
+ /**
58
+ * The parent's current resolved system prompt. Only set when `fork: true`.
59
+ * Distinct from `systemPromptOverride` which replaces the subagent-built prompt;
60
+ * for forks, this IS the system prompt (no subagent preamble is built).
61
+ */
62
+ parentSystemPrompt?: string;
46
63
  }
47
64
 
48
65
  // ── State (runtime) ─────────────────────────────────────────────────────
@@ -52,6 +69,8 @@ export interface SubagentState {
52
69
  status: SubagentStatus;
53
70
  /** The subagent's own conversationId (different from parentConversationId). */
54
71
  conversationId: string;
72
+ /** Whether this sub-agent is a fork (inherits parent context). Defaults to `false`. */
73
+ isFork: boolean;
55
74
  /** Error message if status is 'failed'. */
56
75
  error?: string;
57
76
  /** Timestamps (epoch ms). */
@@ -32,6 +32,7 @@ export interface ExecutorResult {
32
32
  export interface AppStoreReader {
33
33
  getApp(id: string): AppDefinition | null;
34
34
  listApps(): AppDefinition[];
35
+ appFileExists(appId: string, path: string): boolean;
35
36
  }
36
37
 
37
38
  export interface AppStoreWriter {
@@ -183,8 +184,16 @@ function App() {
183
184
  render(<App />, document.getElementById('app')!);
184
185
  `;
185
186
 
186
- store.writeAppFile(app.id, "src/index.html", indexHtml);
187
- store.writeAppFile(app.id, "src/main.tsx", mainTsx);
187
+ // Only write scaffold files when they don't already exist on disk.
188
+ // The LLM may have written custom source files via file_write before
189
+ // calling app_create, and overwriting them would destroy the real app
190
+ // content, leaving only the scaffold placeholder.
191
+ if (!store.appFileExists(app.id, "src/index.html")) {
192
+ store.writeAppFile(app.id, "src/index.html", indexHtml);
193
+ }
194
+ if (!store.appFileExists(app.id, "src/main.tsx")) {
195
+ store.writeAppFile(app.id, "src/main.tsx", mainTsx);
196
+ }
188
197
 
189
198
  // Compile src/ → dist/
190
199
  const appDir = getAppDirPath(app.id);