@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
@@ -35,6 +35,13 @@ When the user mentions "email" - sending, reading, checking, decluttering, draft
35
35
 
36
36
  Do not offer AgentMail as an option or mention it unless the user specifically asks. If Outlook is not connected, guide them through Outlook setup - do not suggest AgentMail as an alternative.
37
37
 
38
+ ## Connection Setup
39
+
40
+ ### Outlook
41
+
42
+ 1. **Try connecting directly first.** Run `assistant oauth status outlook`. This will show whether or not the user had previously connected their Outlook/Microsoft account. If so, they are ready to go.
43
+ 2. **If no connections are found:** Call `skill_load` with `skill: "vellum-oauth-integrations"`. The skill will evaluate whether managed or your-own mode is appropriate and guide the user accordingly.
44
+
38
45
  ## Communication Style
39
46
 
40
47
  - **Be action-oriented.** When the user asks to do something ("declutter", "check my email"), start doing it immediately. Don't ask for permission to read their inbox - that's obviously what they want.
@@ -63,6 +63,24 @@ Only the parent conversation that spawned a subagent can interact with it (check
63
63
 
64
64
  Set `send_result_to_user: false` when spawning a subagent whose result is for internal processing only. The parent will still be notified on completion, but the notification will instruct it to read the result without presenting it to the user.
65
65
 
66
+ ## Fork Mode
67
+
68
+ Forks are sub-agents that inherit the parent's full context -- messages, system prompt, and memory -- sharing the KV cache for near-free context inheritance. Use forks when the task benefits from knowing what you've been discussing; use a regular sub-agent when the task is self-contained.
69
+
70
+ **Key behaviors:** Forks always run as `general` role (the `role` parameter is ignored). `send_result_to_user` defaults to `false`. Read fork output with `last_n: 1` to get only the final synthesis.
71
+
72
+ **When to fork vs regular sub-agent:**
73
+
74
+ | Task | Mode |
75
+ |---|---|
76
+ | Single tool call (one search, one file read) | Direct -- don't spawn at all |
77
+ | Multi-page web research needing conversation context | Fork |
78
+ | Exploratory file search informed by prior discussion | Fork |
79
+ | Comparing multiple sources against what was discussed | Parallel forks |
80
+ | Self-contained task with a clear objective | Regular sub-agent |
81
+
82
+ Rule of thumb: "Does this task need to know what we've been talking about?" If yes, fork. If the objective is fully self-describing, use a regular sub-agent with a scoped role.
83
+
66
84
  ## Tips
67
85
 
68
86
  - Do NOT poll `subagent_status` in a loop. You will be notified automatically when a subagent completes.
@@ -71,3 +89,6 @@ Set `send_result_to_user: false` when spawning a subagent whose result is for in
71
89
  - Use `notify_parent` for interim findings instead of waiting for completion. This lets the parent act on partial results early.
72
90
  - Use `subagent_message` to send follow-up instructions to a running subagent.
73
91
  - Use `subagent_abort` to cancel a subagent that is no longer needed.
92
+ - Default to spawning subagents for any task that involves web research, multi-file exploration, or independent coding work. Serial execution should be the exception, not the rule.
93
+ - When a user request has both an information-gathering component and an action component, spawn a researcher immediately rather than doing the research inline yourself.
94
+ - Prefer spawning 2-3 focused subagents over one large general-purpose subagent. Smaller scopes finish faster and fail more gracefully.
@@ -3,7 +3,7 @@
3
3
  "tools": [
4
4
  {
5
5
  "name": "subagent_spawn",
6
- "description": "Spawn an independent subagent to work on a task in parallel. The subagent runs autonomously and its results are reported back when complete.",
6
+ "description": "Spawn an independent subagent to work on a task in parallel. The subagent runs autonomously and its results are reported back when complete.\n\nTwo modes:\n- **Regular sub-agent** (fork: false or omitted): Gets only the objective + context fields. Use for self-contained tasks with clear objectives. Can use scoped roles (researcher, coder, planner).\n- **Fork** (fork: true): Inherits full parent context (messages, system prompt, memory). Shares KV cache for near-free context inheritance. Use when the task benefits from knowing what you've been discussing. Always runs as general role. Results are internal by default (send_result_to_user: false). Read with last_n: 1 to get only the final synthesis.\n\nDecision heuristic: Does the task need to know what we've been talking about? Fork. Is it self-contained? Regular sub-agent.",
7
7
  "category": "orchestration",
8
8
  "risk": "low",
9
9
  "input_schema": {
@@ -19,16 +19,20 @@
19
19
  },
20
20
  "context": {
21
21
  "type": "string",
22
- "description": "Optional additional context to pass to the subagent"
22
+ "description": "Optional additional context to pass to the subagent. Ignored when fork is true — forks inherit the parent's full context."
23
+ },
24
+ "fork": {
25
+ "type": "boolean",
26
+ "description": "When true, the subagent inherits the parent's full context (messages, system prompt, memory) instead of receiving only the objective + context fields. Fork mode always runs as 'general' role (the role parameter is ignored) and defaults send_result_to_user to false. Use for tasks that benefit from the full conversational context."
23
27
  },
24
28
  "send_result_to_user": {
25
29
  "type": "boolean",
26
- "description": "Whether to present the subagent's result to the user when it completes. Defaults to true. Set to false for internal/silent processing."
30
+ "description": "Whether to present the subagent's result to the user when it completes. Defaults to true for regular sub-agents, false for forks. Set explicitly to override."
27
31
  },
28
32
  "role": {
29
33
  "type": "string",
30
34
  "enum": ["general", "researcher", "coder", "planner"],
31
- "description": "Agent specialization that controls tool access. 'researcher': read-only (web, files, memory). 'coder': file and bash access. 'planner': read-only analysis. 'general': full access (default)."
35
+ "description": "Agent specialization that controls tool access. 'researcher': read-only (web, files, memory). 'coder': file and bash access. 'planner': read-only analysis. 'general': full access (default). Ignored when fork: true (forks always use general)."
32
36
  },
33
37
  "activity": {
34
38
  "type": "string",
@@ -6,6 +6,11 @@ metadata:
6
6
  emoji: "✅"
7
7
  vellum:
8
8
  display-name: "Tasks"
9
+ activation-hints:
10
+ - "User wants to add, check, or manage items on their to-do list or task queue"
11
+ - "For one-off action items, not recurring automations (use schedule for those)"
12
+ avoid-when:
13
+ - "User wants recurring/scheduled automation — use the schedule skill instead"
9
14
  ---
10
15
 
11
16
  Two-layer task system: **task templates** (reusable definitions with input placeholders) and **work items** (instances in the Task Queue with priority tiers and status tracking).
@@ -86,6 +86,17 @@ export function getWorkspaceDirOverride(): string | undefined {
86
86
  // profiler mode. The runtime uses them to locate, scope, and budget-limit
87
87
  // profiler output on the workspace volume.
88
88
 
89
+ /**
90
+ * VELLUM_CPU_LIMIT — string (K8s resource format), default: undefined
91
+ * The CPU resource limit for the container (e.g. "2000m", "2").
92
+ * Set by the platform StatefulSet template to the exact K8s CPU limit.
93
+ * Used by the health endpoint to report accurate CPU core count inside
94
+ * gVisor sandboxes where cgroup files may expose the host node's CPUs.
95
+ */
96
+ export function getCpuLimit(): string | undefined {
97
+ return str("VELLUM_CPU_LIMIT");
98
+ }
99
+
89
100
  /**
90
101
  * VELLUM_PROFILER_RUN_ID — string, default: undefined
91
102
  * Unique identifier for the current profiler run. When set, the profiler
@@ -148,6 +159,7 @@ const KNOWN_VELLUM_VARS = new Set([
148
159
  "VELLUM_DATA_DIR",
149
160
  "VELLUM_DESKTOP_APP",
150
161
  "VELLUM_DEV",
162
+ "VELLUM_DOCS_BASE_URL",
151
163
  "VELLUM_ENABLE_INSECURE_LAN_PAIRING",
152
164
  "VELLUM_HATCHED_BY",
153
165
  "VELLUM_HOOK_EVENT",
@@ -164,6 +176,8 @@ const KNOWN_VELLUM_VARS = new Set([
164
176
  "VELLUM_SSH_USER",
165
177
  "VELLUM_UNSAFE_AUTH_BYPASS",
166
178
  "VELLUM_WORKSPACE_DIR",
179
+ "VELLUM_CPU_LIMIT",
180
+ "VELLUM_MEMORY_LIMIT",
167
181
  ]);
168
182
 
169
183
  /**
package/src/config/env.ts CHANGED
@@ -164,6 +164,27 @@ export function getPlatformBaseUrl(): string {
164
164
  );
165
165
  }
166
166
 
167
+ /**
168
+ * Derive the assistant service domain from the platform base URL.
169
+ *
170
+ * - `dev-platform.vellum.ai` → `dev.vellum.me`
171
+ * - `platform.vellum.ai` → `vellum.me`
172
+ * - anything else → `vellum.me` (safe default)
173
+ */
174
+ export function getAssistantDomain(): string {
175
+ try {
176
+ const url = getPlatformBaseUrl();
177
+ const host = new URL(url).hostname;
178
+ const prefix = host.replace(/[-.]?platform\.vellum\.ai$/, "");
179
+ if (prefix) {
180
+ return `${prefix}.vellum.me`;
181
+ }
182
+ } catch {
183
+ // Fall through to default
184
+ }
185
+ return "vellum.me";
186
+ }
187
+
167
188
  let _platformAssistantIdOverride: string | undefined;
168
189
 
169
190
  export function setPlatformAssistantId(value: string | undefined): void {
@@ -178,11 +178,11 @@
178
178
  "defaultEnabled": false
179
179
  },
180
180
  {
181
- "id": "settings-integrations-grid",
181
+ "id": "multi-platform-assistant",
182
182
  "scope": "assistant",
183
- "key": "settings-integrations-grid",
184
- "label": "Integrations Grid",
185
- "description": "Show the Integrations grid in Models & Services settings, replacing individual OAuth provider cards",
183
+ "key": "multi-platform-assistant",
184
+ "label": "Multi-Platform Assistant Switcher",
185
+ "description": "Enable the menu-bar assistant switcher for managing multiple platform-hosted assistants (new/switch/retire)",
186
186
  "defaultEnabled": false
187
187
  },
188
188
  {
@@ -288,7 +288,46 @@
288
288
  "label": "Permission Controls V2",
289
289
  "description": "Replace risk-level permission system with two independent controls: 'Ask before acting' (LLM behavior toggle) and 'Host access' (system-enforced gate)",
290
290
  "defaultEnabled": false
291
+ },
292
+ {
293
+ "id": "apple-container",
294
+ "scope": "macos",
295
+ "key": "apple-container",
296
+ "label": "Apple Container",
297
+ "description": "Enable assistant sandboxing via Apple Containers on macOS 26+, providing a lightweight native sandbox without third-party dependencies",
298
+ "defaultEnabled": false
299
+ },
300
+ {
301
+ "id": "tool-result-truncation",
302
+ "scope": "assistant",
303
+ "key": "tool-result-truncation",
304
+ "label": "Post-Turn Tool Result Truncation",
305
+ "description": "Truncate large tool results after each assistant turn, persisting full content to disk for on-demand re-reads",
306
+ "defaultEnabled": false
307
+ },
308
+ {
309
+ "id": "managed-gemini-embeddings-enabled",
310
+ "scope": "assistant",
311
+ "key": "managed-gemini-embeddings-enabled",
312
+ "label": "Managed Gemini Embeddings Enabled",
313
+ "description": "Route embedding requests through the platform runtime proxy using Vellum-managed Gemini credentials when available",
314
+ "defaultEnabled": false
315
+ },
316
+ {
317
+ "id": "fork-from-message",
318
+ "scope": "macos",
319
+ "key": "fork-from-message",
320
+ "label": "Fork from Message",
321
+ "description": "Show the 'Fork from here' option in message overflow menus",
322
+ "defaultEnabled": false
323
+ },
324
+ {
325
+ "id": "fork-from-message",
326
+ "scope": "macos",
327
+ "key": "fork-from-message",
328
+ "label": "Fork from Message",
329
+ "description": "Show the Fork from here option in message overflow menus",
330
+ "defaultEnabled": false
291
331
  }
292
332
  ]
293
333
  }
294
-
@@ -11,6 +11,7 @@ import { dirname, join } from "node:path";
11
11
  import { ConfigError } from "../util/errors.js";
12
12
  import { getLogger } from "../util/logger.js";
13
13
  import { ensureDataDir, getWorkspaceConfigPath } from "../util/platform.js";
14
+ import { isAssistantFeatureFlagEnabled } from "./assistant-feature-flags.js";
14
15
  import { AssistantConfigSchema } from "./schema.js";
15
16
  import type { AssistantConfig } from "./types.js";
16
17
 
@@ -385,7 +386,46 @@ export function loadConfig(): AssistantConfig {
385
386
  warnAndStripDeprecatedFields(fileConfig, configPath);
386
387
 
387
388
  // Validate and apply defaults via Zod schema
388
- const config = validateWithSchema(fileConfig);
389
+ let config = validateWithSchema(fileConfig);
390
+
391
+ // Managed Gemini embedding defaults migration.
392
+ // When on a managed platform (IS_PLATFORM=true) with the feature flag
393
+ // enabled and no explicit embedding provider chosen (provider=auto),
394
+ // persist Gemini embedding defaults into the raw config file.
395
+ // Idempotent: once provider=gemini is written, subsequent loads skip this.
396
+ if (config.memory.embeddings.provider === "auto") {
397
+ try {
398
+ if (
399
+ (process.env.IS_PLATFORM === "true" ||
400
+ process.env.IS_PLATFORM === "1") &&
401
+ isManagedGeminiFFEnabled(config)
402
+ ) {
403
+ setNestedValue(fileConfig, "memory.embeddings.provider", "gemini");
404
+ setNestedValue(
405
+ fileConfig,
406
+ "memory.embeddings.geminiModel",
407
+ "gemini-embedding-2-preview",
408
+ );
409
+ setNestedValue(
410
+ fileConfig,
411
+ "memory.embeddings.geminiDimensions",
412
+ 3072,
413
+ );
414
+ setNestedValue(fileConfig, "memory.qdrant.vectorSize", 3072);
415
+ writeFileSync(configPath, JSON.stringify(fileConfig, null, 2) + "\n");
416
+ log.info(
417
+ "Applied managed Gemini embedding defaults (provider=gemini, model=gemini-embedding-2-preview, dimensions=3072, vectorSize=3072)",
418
+ );
419
+ // Re-validate so the returned config reflects the migration.
420
+ config = validateWithSchema(fileConfig);
421
+ }
422
+ } catch (err) {
423
+ log.warn(
424
+ { err },
425
+ "Managed Gemini defaults migration failed — continuing with existing config",
426
+ );
427
+ }
428
+ }
389
429
 
390
430
  // If the config file didn't exist, write the full defaults to disk so
391
431
  // users can discover and edit all available options.
@@ -421,6 +461,21 @@ export function loadConfig(): AssistantConfig {
421
461
  }
422
462
  }
423
463
 
464
+ /**
465
+ * Check whether the managed-gemini-embeddings-enabled feature flag is on.
466
+ * Wrapped in a try/catch so a flag-resolver failure never breaks config loading.
467
+ */
468
+ function isManagedGeminiFFEnabled(config: AssistantConfig): boolean {
469
+ try {
470
+ return isAssistantFeatureFlagEnabled(
471
+ "managed-gemini-embeddings-enabled",
472
+ config,
473
+ );
474
+ } catch {
475
+ return false;
476
+ }
477
+ }
478
+
424
479
  export function saveConfig(config: AssistantConfig): void {
425
480
  ensureMigratedDataDir();
426
481
  const configPath = getConfigPath();
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Strips environment-specific fields from config JSON before transferring
3
+ * between local and platform environments (teleport/restore).
4
+ *
5
+ * Fields removed or reset:
6
+ * - `ingress.publicBaseUrl` → set to `""`
7
+ * - `ingress.enabled` → deleted
8
+ * - `daemon` → deleted entirely
9
+ * - `skills.load.extraDirs` → set to `[]`
10
+ */
11
+ export function sanitizeConfigForTransfer(configJson: string): string {
12
+ let config: Record<string, unknown>;
13
+ try {
14
+ const parsed = JSON.parse(configJson);
15
+ if (
16
+ typeof parsed !== "object" ||
17
+ parsed === null ||
18
+ Array.isArray(parsed)
19
+ ) {
20
+ return configJson;
21
+ }
22
+ config = parsed;
23
+ } catch {
24
+ return configJson;
25
+ }
26
+
27
+ // Strip ingress environment-specific fields
28
+ if (config.ingress && typeof config.ingress === "object") {
29
+ const ingress = config.ingress as Record<string, unknown>;
30
+ ingress.publicBaseUrl = "";
31
+ delete ingress.enabled;
32
+ }
33
+
34
+ // Strip daemon entirely
35
+ delete config.daemon;
36
+
37
+ // Strip skills.load.extraDirs
38
+ if (config.skills && typeof config.skills === "object") {
39
+ const skills = config.skills as Record<string, unknown>;
40
+ if (skills.load && typeof skills.load === "object") {
41
+ const load = skills.load as Record<string, unknown>;
42
+ load.extraDirs = [];
43
+ }
44
+ }
45
+
46
+ return JSON.stringify(config, null, 2) + "\n";
47
+ }
@@ -49,6 +49,14 @@ export type { FishAudioConfig } from "./schemas/fish-audio.js";
49
49
  export { FishAudioConfigSchema } from "./schemas/fish-audio.js";
50
50
  export type { HeartbeatConfig } from "./schemas/heartbeat.js";
51
51
  export { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
52
+ export type {
53
+ HostBrowserCdpInspectConfig,
54
+ HostBrowserConfig,
55
+ } from "./schemas/host-browser.js";
56
+ export {
57
+ HostBrowserCdpInspectConfigSchema,
58
+ HostBrowserConfigSchema,
59
+ } from "./schemas/host-browser.js";
52
60
  export type {
53
61
  ContextOverflowRecoveryConfig,
54
62
  ContextWindowConfig,
@@ -115,6 +123,7 @@ export {
115
123
  export type { MemoryRetrievalConfig } from "./schemas/memory-retrieval.js";
116
124
  export {
117
125
  MemoryDynamicBudgetConfigSchema,
126
+ MemoryInjectionConfigSchema,
118
127
  MemoryRetrievalConfigSchema,
119
128
  } from "./schemas/memory-retrieval.js";
120
129
  export type {
@@ -139,8 +148,6 @@ export {
139
148
  PlatformConfigSchema,
140
149
  UiConfigSchema,
141
150
  } from "./schemas/platform.js";
142
- export type { SandboxConfig } from "./schemas/sandbox.js";
143
- export { SandboxConfigSchema } from "./schemas/sandbox.js";
144
151
  export type {
145
152
  PermissionsConfig,
146
153
  SecretDetectionConfig,
@@ -206,6 +213,7 @@ import { ElevenLabsConfigSchema } from "./schemas/elevenlabs.js";
206
213
  import { FilingConfigSchema } from "./schemas/filing.js";
207
214
  import { FishAudioConfigSchema } from "./schemas/fish-audio.js";
208
215
  import { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
216
+ import { HostBrowserConfigSchema } from "./schemas/host-browser.js";
209
217
  import {
210
218
  ContextWindowConfigSchema,
211
219
  EffortSchema,
@@ -227,7 +235,6 @@ import {
227
235
  PlatformConfigSchema,
228
236
  UiConfigSchema,
229
237
  } from "./schemas/platform.js";
230
- import { SandboxConfigSchema } from "./schemas/sandbox.js";
231
238
  import {
232
239
  PermissionsConfigSchema,
233
240
  SecretDetectionConfigSchema,
@@ -247,7 +254,7 @@ export const AssistantConfigSchema = z
247
254
  .number({ error: "maxTokens must be a number" })
248
255
  .int("maxTokens must be an integer")
249
256
  .positive("maxTokens must be a positive integer")
250
- .default(16000)
257
+ .default(64000)
251
258
  .describe("Maximum number of output tokens per LLM response"),
252
259
  effort: EffortSchema,
253
260
  speed: SpeedSchema,
@@ -261,7 +268,6 @@ export const AssistantConfigSchema = z
261
268
  .default(getDataDir())
262
269
  .describe("Directory for storing assistant data (database, logs, etc.)"),
263
270
  timeouts: TimeoutConfigSchema.default(TimeoutConfigSchema.parse({})),
264
- sandbox: SandboxConfigSchema.default(SandboxConfigSchema.parse({})),
265
271
  rateLimit: RateLimitConfigSchema.default(RateLimitConfigSchema.parse({})),
266
272
  secretDetection: SecretDetectionConfigSchema.default(
267
273
  SecretDetectionConfigSchema.parse({}),
@@ -281,6 +287,9 @@ export const AssistantConfigSchema = z
281
287
  ),
282
288
  filing: FilingConfigSchema.default(FilingConfigSchema.parse({})),
283
289
  heartbeat: HeartbeatConfigSchema.default(HeartbeatConfigSchema.parse({})),
290
+ hostBrowser: HostBrowserConfigSchema.default(
291
+ HostBrowserConfigSchema.parse({}),
292
+ ),
284
293
  journal: JournalConfigSchema.default(JournalConfigSchema.parse({})),
285
294
  mcp: McpConfigSchema.default(McpConfigSchema.parse({})),
286
295
  acp: AcpConfigSchema.default(AcpConfigSchema.parse({})),
@@ -321,6 +330,13 @@ export const AssistantConfigSchema = z
321
330
  .max(200, "maxStepsPerSession must be <= 200")
322
331
  .default(50)
323
332
  .describe("Maximum number of computer-use steps per session"),
333
+ systemPromptPrefix: z
334
+ .string({ error: "systemPromptPrefix must be a string" })
335
+ .nullable()
336
+ .default(null)
337
+ .describe(
338
+ "Custom text injected at the very beginning of the system prompt. Defaults to null (no injection).",
339
+ ),
324
340
  })
325
341
  .superRefine((config, ctx) => {
326
342
  if (
@@ -373,6 +389,31 @@ export const AssistantConfigSchema = z
373
389
  "memory.retrieval.dynamicBudget.minInjectTokens must be <= memory.retrieval.dynamicBudget.maxInjectTokens",
374
390
  });
375
391
  }
392
+ const injection = config.memory?.retrieval?.injection;
393
+ const ctxLoad = injection?.contextLoad;
394
+ if (
395
+ ctxLoad &&
396
+ ctxLoad.capabilityReserve + ctxLoad.serendipitySlots >= ctxLoad.maxNodes
397
+ ) {
398
+ ctx.addIssue({
399
+ code: z.ZodIssueCode.custom,
400
+ path: ["memory", "retrieval", "injection", "contextLoad"],
401
+ message:
402
+ "memory.retrieval.injection.contextLoad.capabilityReserve + serendipitySlots must be less than maxNodes",
403
+ });
404
+ }
405
+ const perTurn = injection?.perTurn;
406
+ if (
407
+ perTurn &&
408
+ perTurn.capabilityReserve + perTurn.serendipitySlots >= perTurn.maxNodes
409
+ ) {
410
+ ctx.addIssue({
411
+ code: z.ZodIssueCode.custom,
412
+ path: ["memory", "retrieval", "injection", "perTurn"],
413
+ message:
414
+ "memory.retrieval.injection.perTurn.capabilityReserve + serendipitySlots must be less than maxNodes",
415
+ });
416
+ }
376
417
  });
377
418
 
378
419
  export type AssistantConfig = z.infer<typeof AssistantConfigSchema>;
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Configuration for the `cdp-inspect` browser backend — connects directly
5
+ * to a host Chrome instance that was launched with `--remote-debugging-port`
6
+ * (e.g. `chrome://inspect`-style remote debugging) as an alternative to the
7
+ * extension or local Playwright backend.
8
+ */
9
+ export const HostBrowserCdpInspectConfigSchema = z
10
+ .object({
11
+ enabled: z
12
+ .boolean({ error: "hostBrowser.cdpInspect.enabled must be a boolean" })
13
+ .default(false)
14
+ .describe(
15
+ "Whether the cdp-inspect backend is enabled. When true, the factory will route browser tool calls through the configured host/port instead of the local Playwright backend.",
16
+ ),
17
+ host: z
18
+ .string({ error: "hostBrowser.cdpInspect.host must be a string" })
19
+ .min(1, "hostBrowser.cdpInspect.host must not be empty")
20
+ .default("localhost")
21
+ .describe(
22
+ "Host name or IP address where the host Chrome instance exposes its remote debugging endpoint.",
23
+ ),
24
+ port: z
25
+ .number({ error: "hostBrowser.cdpInspect.port must be a number" })
26
+ .int("hostBrowser.cdpInspect.port must be an integer")
27
+ .min(1, "hostBrowser.cdpInspect.port must be >= 1")
28
+ .max(65535, "hostBrowser.cdpInspect.port must be <= 65535")
29
+ .default(9222)
30
+ .describe(
31
+ "TCP port for the host Chrome remote-debugging endpoint (matches `--remote-debugging-port`).",
32
+ ),
33
+ probeTimeoutMs: z
34
+ .number({
35
+ error: "hostBrowser.cdpInspect.probeTimeoutMs must be a number",
36
+ })
37
+ .int("hostBrowser.cdpInspect.probeTimeoutMs must be an integer")
38
+ .min(50, "hostBrowser.cdpInspect.probeTimeoutMs must be >= 50")
39
+ .max(5000, "hostBrowser.cdpInspect.probeTimeoutMs must be <= 5000")
40
+ .default(500)
41
+ .describe(
42
+ "Timeout (in milliseconds) for the backend availability probe. Kept small so browser tool calls fail fast when the endpoint is unreachable.",
43
+ ),
44
+ })
45
+ .describe(
46
+ "Settings for the cdp-inspect backend that connects to a host Chrome instance via its remote-debugging endpoint.",
47
+ );
48
+
49
+ export type HostBrowserCdpInspectConfig = z.infer<
50
+ typeof HostBrowserCdpInspectConfigSchema
51
+ >;
52
+
53
+ /**
54
+ * Top-level configuration for host-browser backends. Currently only exposes
55
+ * `cdpInspect`, but the shape leaves room for additional host-browser knobs
56
+ * (e.g. extension-specific settings) without another namespace churn.
57
+ */
58
+ export const HostBrowserConfigSchema = z
59
+ .object({
60
+ cdpInspect: HostBrowserCdpInspectConfigSchema.default(
61
+ HostBrowserCdpInspectConfigSchema.parse({}),
62
+ ),
63
+ })
64
+ .describe("Host-browser backend configuration (cdp-inspect, etc.)");
65
+
66
+ export type HostBrowserConfig = z.infer<typeof HostBrowserConfigSchema>;
@@ -80,7 +80,7 @@ export const MemoryCleanupConfigSchema = z
80
80
  .nonnegative(
81
81
  "memory.cleanup.llmRequestLogRetentionMs must be non-negative",
82
82
  )
83
- .default(7 * 24 * 60 * 60 * 1000)
83
+ .default(1 * 24 * 60 * 60 * 1000)
84
84
  .describe(
85
85
  "Retention period for LLM request/response logs in milliseconds (0 disables pruning)",
86
86
  ),
@@ -184,6 +184,106 @@ const MemoryFreshnessConfigSchema = z
184
184
  "Freshness-based ranking for memory retrieval — down-ranks old items unless recently reinforced",
185
185
  );
186
186
 
187
+ const MemoryContextLoadInjectionSchema = z
188
+ .object({
189
+ maxNodes: z
190
+ .number({
191
+ error:
192
+ "memory.retrieval.injection.contextLoad.maxNodes must be a number",
193
+ })
194
+ .int("memory.retrieval.injection.contextLoad.maxNodes must be an integer")
195
+ .positive(
196
+ "memory.retrieval.injection.contextLoad.maxNodes must be a positive integer",
197
+ )
198
+ .default(25)
199
+ .describe("Maximum number of memory nodes to load at conversation start"),
200
+ serendipitySlots: z
201
+ .number({
202
+ error:
203
+ "memory.retrieval.injection.contextLoad.serendipitySlots must be a number",
204
+ })
205
+ .int(
206
+ "memory.retrieval.injection.contextLoad.serendipitySlots must be an integer",
207
+ )
208
+ .nonnegative(
209
+ "memory.retrieval.injection.contextLoad.serendipitySlots must be non-negative",
210
+ )
211
+ .default(5)
212
+ .describe("Number of random wildcard memory picks at conversation start"),
213
+ capabilityReserve: z
214
+ .number({
215
+ error:
216
+ "memory.retrieval.injection.contextLoad.capabilityReserve must be a number",
217
+ })
218
+ .int(
219
+ "memory.retrieval.injection.contextLoad.capabilityReserve must be an integer",
220
+ )
221
+ .nonnegative(
222
+ "memory.retrieval.injection.contextLoad.capabilityReserve must be non-negative",
223
+ )
224
+ .default(5)
225
+ .describe(
226
+ "Reserved slots for skill/CLI capability nodes at conversation start",
227
+ ),
228
+ })
229
+ .describe("Memory injection limits at conversation start");
230
+
231
+ const MemoryPerTurnInjectionSchema = z
232
+ .object({
233
+ maxNodes: z
234
+ .number({
235
+ error: "memory.retrieval.injection.perTurn.maxNodes must be a number",
236
+ })
237
+ .int("memory.retrieval.injection.perTurn.maxNodes must be an integer")
238
+ .positive(
239
+ "memory.retrieval.injection.perTurn.maxNodes must be a positive integer",
240
+ )
241
+ .default(6)
242
+ .describe(
243
+ "Maximum total memory nodes injected per turn (general + capability + serendipity)",
244
+ ),
245
+ serendipitySlots: z
246
+ .number({
247
+ error:
248
+ "memory.retrieval.injection.perTurn.serendipitySlots must be a number",
249
+ })
250
+ .int(
251
+ "memory.retrieval.injection.perTurn.serendipitySlots must be an integer",
252
+ )
253
+ .nonnegative(
254
+ "memory.retrieval.injection.perTurn.serendipitySlots must be non-negative",
255
+ )
256
+ .default(1)
257
+ .describe("Number of random wildcard memory picks per turn"),
258
+ capabilityReserve: z
259
+ .number({
260
+ error:
261
+ "memory.retrieval.injection.perTurn.capabilityReserve must be a number",
262
+ })
263
+ .int(
264
+ "memory.retrieval.injection.perTurn.capabilityReserve must be an integer",
265
+ )
266
+ .nonnegative(
267
+ "memory.retrieval.injection.perTurn.capabilityReserve must be non-negative",
268
+ )
269
+ .default(2)
270
+ .describe("Reserved slots for skill/CLI capability nodes per turn"),
271
+ })
272
+ .describe("Memory injection limits for mid-conversation turns");
273
+
274
+ export const MemoryInjectionConfigSchema = z
275
+ .object({
276
+ contextLoad: MemoryContextLoadInjectionSchema.default(
277
+ MemoryContextLoadInjectionSchema.parse({}),
278
+ ),
279
+ perTurn: MemoryPerTurnInjectionSchema.default(
280
+ MemoryPerTurnInjectionSchema.parse({}),
281
+ ),
282
+ })
283
+ .describe(
284
+ "Controls how many memory items are injected at conversation start and per turn",
285
+ );
286
+
187
287
  export const MemoryRetrievalConfigSchema = z
188
288
  .object({
189
289
  maxInjectTokens: z
@@ -209,6 +309,9 @@ export const MemoryRetrievalConfigSchema = z
209
309
  dynamicBudget: MemoryDynamicBudgetConfigSchema.default(
210
310
  MemoryDynamicBudgetConfigSchema.parse({}),
211
311
  ),
312
+ injection: MemoryInjectionConfigSchema.default(
313
+ MemoryInjectionConfigSchema.parse({}),
314
+ ),
212
315
  })
213
316
  .describe(
214
317
  "Controls how memories are retrieved and injected into conversations",