@vellumai/assistant 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/bun.lock +40 -40
  2. package/bunfig.toml +3 -0
  3. package/docker-entrypoint.sh +12 -2
  4. package/docs/architecture/memory.md +1 -1
  5. package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
  6. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
  7. package/openapi.yaml +184 -69
  8. package/package.json +41 -41
  9. package/scripts/generate-openapi.ts +1 -2
  10. package/src/__tests__/acp-session.test.ts +43 -0
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  12. package/src/__tests__/app-executors.test.ts +1 -0
  13. package/src/__tests__/app-source-watcher.test.ts +37 -11
  14. package/src/__tests__/approval-routes-http.test.ts +178 -1
  15. package/src/__tests__/assistant-event-hub.test.ts +30 -0
  16. package/src/__tests__/browser-fill-credential.test.ts +229 -94
  17. package/src/__tests__/browser-manager.test.ts +40 -27
  18. package/src/__tests__/catalog-files.test.ts +862 -0
  19. package/src/__tests__/channel-approvals.test.ts +53 -0
  20. package/src/__tests__/checker.test.ts +104 -170
  21. package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
  22. package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
  23. package/src/__tests__/config-schema-cmd.test.ts +2 -2
  24. package/src/__tests__/config-schema.test.ts +125 -48
  25. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
  26. package/src/__tests__/context-overflow-approval.test.ts +21 -6
  27. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  28. package/src/__tests__/conversation-agent-loop.test.ts +1 -1
  29. package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
  30. package/src/__tests__/conversation-attachments.test.ts +80 -4
  31. package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
  32. package/src/__tests__/conversation-directories-parse.test.ts +105 -0
  33. package/src/__tests__/conversation-fork-crud.test.ts +17 -0
  34. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  35. package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
  36. package/src/__tests__/conversation-inject-context.test.ts +103 -0
  37. package/src/__tests__/conversation-queue.test.ts +45 -2
  38. package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
  39. package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
  40. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
  42. package/src/__tests__/conversation-starter-routes.test.ts +126 -0
  43. package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
  44. package/src/__tests__/conversation-store.test.ts +195 -0
  45. package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
  46. package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -3
  47. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  48. package/src/__tests__/credential-vault-unit.test.ts +4 -4
  49. package/src/__tests__/credential-vault.test.ts +152 -13
  50. package/src/__tests__/credentials-cli.test.ts +2 -2
  51. package/src/__tests__/date-context.test.ts +4 -4
  52. package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
  53. package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
  54. package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
  55. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  56. package/src/__tests__/gemini-provider.test.ts +2 -2
  57. package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
  58. package/src/__tests__/headless-browser-interactions.test.ts +707 -371
  59. package/src/__tests__/headless-browser-navigate.test.ts +389 -47
  60. package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
  61. package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
  62. package/src/__tests__/host-bash-proxy.test.ts +150 -1
  63. package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
  64. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
  65. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
  66. package/src/__tests__/host-browser-event-routes.test.ts +350 -0
  67. package/src/__tests__/host-browser-proxy.test.ts +444 -0
  68. package/src/__tests__/host-browser-routes.test.ts +198 -0
  69. package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
  70. package/src/__tests__/host-cu-proxy.test.ts +171 -1
  71. package/src/__tests__/host-file-proxy.test.ts +185 -1
  72. package/src/__tests__/host-file-read-tool.test.ts +52 -0
  73. package/src/__tests__/host-proxy-interface.test.ts +165 -0
  74. package/src/__tests__/host-shell-tool.test.ts +1 -11
  75. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  76. package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
  77. package/src/__tests__/inline-command-runner.test.ts +7 -5
  78. package/src/__tests__/integration-status.test.ts +6 -7
  79. package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
  80. package/src/__tests__/log-export-workspace.test.ts +190 -0
  81. package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
  82. package/src/__tests__/mcp-client-auth.test.ts +40 -4
  83. package/src/__tests__/mcp-health-check.test.ts +10 -3
  84. package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
  85. package/src/__tests__/migration-export-http.test.ts +61 -2
  86. package/src/__tests__/migration-export-streaming.test.ts +66 -0
  87. package/src/__tests__/migration-import-commit-http.test.ts +101 -1
  88. package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
  89. package/src/__tests__/navigate-settings-tab.test.ts +14 -1
  90. package/src/__tests__/notification-broadcaster.test.ts +65 -0
  91. package/src/__tests__/oauth-apps-routes.test.ts +17 -12
  92. package/src/__tests__/oauth-cli.test.ts +707 -60
  93. package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
  94. package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
  95. package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
  96. package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
  97. package/src/__tests__/oauth-providers-routes.test.ts +50 -14
  98. package/src/__tests__/oauth-store.test.ts +1386 -182
  99. package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
  100. package/src/__tests__/onboarding-template-contract.test.ts +74 -55
  101. package/src/__tests__/openai-provider.test.ts +2 -2
  102. package/src/__tests__/outlook-categories.test.ts +1 -1
  103. package/src/__tests__/outlook-client-automation.test.ts +1 -1
  104. package/src/__tests__/outlook-compose-tools.test.ts +1 -1
  105. package/src/__tests__/outlook-email-watcher.test.ts +1 -1
  106. package/src/__tests__/outlook-follow-up.test.ts +1 -1
  107. package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
  108. package/src/__tests__/outlook-trash.test.ts +1 -1
  109. package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
  110. package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
  111. package/src/__tests__/permission-mode.test.ts +28 -56
  112. package/src/__tests__/pkb-autoinject.test.ts +96 -0
  113. package/src/__tests__/platform-callback-registration.test.ts +19 -0
  114. package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
  115. package/src/__tests__/proxy-approval-callback.test.ts +18 -0
  116. package/src/__tests__/require-fresh-approval.test.ts +40 -3
  117. package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
  118. package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
  119. package/src/__tests__/schedule-routes.test.ts +162 -0
  120. package/src/__tests__/secret-detection-handler.test.ts +84 -0
  121. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  123. package/src/__tests__/set-permission-mode.test.ts +13 -250
  124. package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
  125. package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
  126. package/src/__tests__/slack-channel-config.test.ts +12 -15
  127. package/src/__tests__/subagent-detail.test.ts +44 -2
  128. package/src/__tests__/subagent-disposal.test.ts +1 -0
  129. package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
  130. package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
  131. package/src/__tests__/subagent-manager-notify.test.ts +1 -0
  132. package/src/__tests__/subagent-notify-parent.test.ts +1 -0
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
  134. package/src/__tests__/subagent-tools.test.ts +1 -0
  135. package/src/__tests__/subagent-types.test.ts +1 -0
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
  137. package/src/__tests__/system-prompt.test.ts +72 -1
  138. package/src/__tests__/task-scheduler.test.ts +32 -6
  139. package/src/__tests__/telegram-config.test.ts +10 -13
  140. package/src/__tests__/terminal-sandbox.test.ts +1 -1
  141. package/src/__tests__/terminal-tools.test.ts +11 -5
  142. package/src/__tests__/test-preload.ts +14 -0
  143. package/src/__tests__/tool-approval-handler.test.ts +73 -0
  144. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
  145. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
  146. package/src/__tests__/tool-executor.test.ts +0 -1
  147. package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
  148. package/src/__tests__/top-level-renderer.test.ts +73 -1
  149. package/src/__tests__/transport-hints-queue.test.ts +62 -0
  150. package/src/__tests__/trust-store.test.ts +4 -4
  151. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
  152. package/src/__tests__/v2-consent-policy.test.ts +103 -0
  153. package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
  154. package/src/__tests__/workspace-policy.test.ts +2 -7
  155. package/src/acp/client-handler.ts +30 -4
  156. package/src/agent/loop.ts +12 -35
  157. package/src/approvals/guardian-request-resolvers.ts +21 -15
  158. package/src/browser-session/__tests__/manager.test.ts +297 -0
  159. package/src/browser-session/backends/cdp-inspect.ts +30 -0
  160. package/src/browser-session/backends/extension.ts +26 -0
  161. package/src/browser-session/backends/local.ts +24 -0
  162. package/src/browser-session/events.ts +164 -0
  163. package/src/browser-session/index.ts +27 -0
  164. package/src/browser-session/manager.ts +159 -0
  165. package/src/browser-session/types.ts +28 -0
  166. package/src/channels/__tests__/types.test.ts +134 -0
  167. package/src/channels/types.ts +55 -0
  168. package/src/cli/__tests__/run-assistant-command.ts +34 -7
  169. package/src/cli/__tests__/unknown-command.test.ts +33 -0
  170. package/src/cli/commands/browser-relay.ts +339 -409
  171. package/src/cli/commands/credentials.ts +3 -3
  172. package/src/cli/commands/default-action.ts +68 -1
  173. package/src/cli/commands/email.ts +18 -13
  174. package/src/cli/commands/mcp.ts +16 -4
  175. package/src/cli/commands/oauth/__tests__/connect.test.ts +68 -41
  176. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
  177. package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
  178. package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
  179. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
  180. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
  181. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
  182. package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
  183. package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
  184. package/src/cli/commands/oauth/apps.ts +7 -4
  185. package/src/cli/commands/oauth/connect.ts +16 -2
  186. package/src/cli/commands/oauth/disconnect.ts +1 -1
  187. package/src/cli/commands/oauth/providers.ts +200 -36
  188. package/src/cli/commands/oauth/shared.ts +5 -5
  189. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
  190. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  191. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  192. package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
  193. package/src/cli/commands/platform/index.ts +107 -10
  194. package/src/cli/commands/usage.ts +10 -9
  195. package/src/cli/lib/daemon-credential-client.ts +4 -0
  196. package/src/cli/program.ts +10 -3
  197. package/src/config/assistant-feature-flags.ts +59 -55
  198. package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
  199. package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
  200. package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
  201. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
  202. package/src/config/bundled-skills/contacts/SKILL.md +3 -0
  203. package/src/config/bundled-skills/document/SKILL.md +4 -0
  204. package/src/config/bundled-skills/gmail/SKILL.md +12 -7
  205. package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
  206. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
  207. package/src/config/bundled-skills/outlook/SKILL.md +7 -0
  208. package/src/config/bundled-skills/settings/TOOLS.json +1 -1
  209. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
  210. package/src/config/bundled-skills/subagent/SKILL.md +21 -0
  211. package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
  212. package/src/config/bundled-skills/tasks/SKILL.md +5 -0
  213. package/src/config/env-registry.ts +14 -0
  214. package/src/config/env.ts +21 -0
  215. package/src/config/feature-flag-registry.json +46 -7
  216. package/src/config/loader.ts +56 -1
  217. package/src/config/sanitize-for-transfer.ts +47 -0
  218. package/src/config/schema.ts +46 -5
  219. package/src/config/schemas/host-browser.ts +66 -0
  220. package/src/config/schemas/memory-lifecycle.ts +1 -1
  221. package/src/config/schemas/memory-retrieval.ts +103 -0
  222. package/src/config/schemas/security.ts +0 -6
  223. package/src/config/schemas/services.ts +16 -0
  224. package/src/config/types.ts +0 -1
  225. package/src/context/post-turn-tool-result-truncation.ts +176 -0
  226. package/src/context/window-manager.ts +19 -1
  227. package/src/credential-execution/approval-bridge.ts +49 -16
  228. package/src/credential-execution/managed-catalog.ts +3 -7
  229. package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
  230. package/src/daemon/app-source-watcher.ts +35 -0
  231. package/src/daemon/config-watcher.ts +6 -2
  232. package/src/daemon/context-overflow-approval.ts +5 -1
  233. package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
  234. package/src/daemon/conversation-agent-loop.ts +74 -19
  235. package/src/daemon/conversation-attachments.ts +40 -1
  236. package/src/daemon/conversation-messaging.ts +3 -0
  237. package/src/daemon/conversation-process.ts +66 -3
  238. package/src/daemon/conversation-queue-manager.ts +8 -0
  239. package/src/daemon/conversation-runtime-assembly.ts +159 -20
  240. package/src/daemon/conversation-surfaces.ts +78 -12
  241. package/src/daemon/conversation-tool-setup.ts +74 -11
  242. package/src/daemon/conversation-workspace.ts +12 -0
  243. package/src/daemon/conversation.ts +227 -11
  244. package/src/daemon/date-context.ts +10 -10
  245. package/src/daemon/first-greeting.ts +3 -2
  246. package/src/daemon/handlers/conversations.ts +9 -139
  247. package/src/daemon/handlers/shared.ts +65 -0
  248. package/src/daemon/handlers/skills.ts +232 -37
  249. package/src/daemon/host-bash-proxy.ts +48 -13
  250. package/src/daemon/host-browser-proxy.ts +191 -0
  251. package/src/daemon/host-cu-proxy.ts +36 -11
  252. package/src/daemon/host-file-proxy.ts +57 -9
  253. package/src/daemon/lifecycle.ts +86 -12
  254. package/src/daemon/message-protocol.ts +7 -0
  255. package/src/daemon/message-types/conversations.ts +59 -13
  256. package/src/daemon/message-types/host-browser.ts +100 -0
  257. package/src/daemon/message-types/messages.ts +5 -6
  258. package/src/daemon/message-types/notifications.ts +12 -0
  259. package/src/daemon/message-types/settings.ts +12 -0
  260. package/src/daemon/message-types/skills.ts +10 -0
  261. package/src/daemon/message-types/subagents.ts +2 -0
  262. package/src/daemon/server.ts +112 -35
  263. package/src/daemon/tool-side-effects.ts +6 -0
  264. package/src/daemon/transport-hints.ts +14 -0
  265. package/src/inbound/platform-callback-registration.ts +18 -17
  266. package/src/index.ts +1 -1
  267. package/src/mcp/client.ts +59 -24
  268. package/src/memory/app-store.ts +31 -1
  269. package/src/memory/conversation-crud.ts +38 -10
  270. package/src/memory/conversation-directories.ts +39 -0
  271. package/src/memory/conversation-group-migration.ts +65 -5
  272. package/src/memory/conversation-starters-cadence.ts +76 -0
  273. package/src/memory/conversation-title-service.ts +5 -2
  274. package/src/memory/db-init.ts +12 -0
  275. package/src/memory/embedding-backend.test.ts +75 -0
  276. package/src/memory/embedding-backend.ts +131 -5
  277. package/src/memory/embedding-gemini.test.ts +54 -0
  278. package/src/memory/embedding-gemini.ts +20 -9
  279. package/src/memory/embedding-local.ts +177 -18
  280. package/src/memory/graph/capability-seed.ts +3 -5
  281. package/src/memory/graph/consolidation.ts +10 -23
  282. package/src/memory/graph/extraction-job.ts +15 -0
  283. package/src/memory/graph/retriever.ts +40 -22
  284. package/src/memory/graph/store.test.ts +7 -3
  285. package/src/memory/graph/store.ts +47 -12
  286. package/src/memory/group-crud.ts +25 -9
  287. package/src/memory/llm-usage-store.ts +45 -4
  288. package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
  289. package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
  290. package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
  291. package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
  292. package/src/memory/migrations/217-conversation-host-access.ts +40 -0
  293. package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
  294. package/src/memory/migrations/index.ts +6 -0
  295. package/src/memory/migrations/registry.ts +8 -0
  296. package/src/memory/schema/conversations.ts +1 -0
  297. package/src/memory/schema/oauth.ts +18 -13
  298. package/src/messaging/provider.ts +1 -1
  299. package/src/notifications/broadcaster.ts +6 -0
  300. package/src/notifications/conversation-pairing.ts +12 -4
  301. package/src/notifications/emit-signal.ts +14 -0
  302. package/src/notifications/signal.ts +11 -0
  303. package/src/oauth/AGENTS.md +76 -0
  304. package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
  305. package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
  306. package/src/oauth/byo-connection.test.ts +8 -8
  307. package/src/oauth/byo-connection.ts +7 -7
  308. package/src/oauth/connect-orchestrator.ts +23 -21
  309. package/src/oauth/connect-types.ts +3 -3
  310. package/src/oauth/connection-resolver.test.ts +17 -4
  311. package/src/oauth/connection-resolver.ts +16 -16
  312. package/src/oauth/connection.ts +1 -1
  313. package/src/oauth/manual-token-connection.ts +13 -13
  314. package/src/oauth/oauth-store.ts +214 -100
  315. package/src/oauth/platform-connection.test.ts +5 -5
  316. package/src/oauth/platform-connection.ts +4 -4
  317. package/src/oauth/provider-serializer.ts +31 -5
  318. package/src/oauth/revoke.ts +76 -0
  319. package/src/oauth/seed-providers.ts +127 -87
  320. package/src/oauth/token-persistence.ts +1 -1
  321. package/src/permissions/checker.ts +3 -3
  322. package/src/permissions/defaults.ts +7 -8
  323. package/src/permissions/permission-mode.ts +4 -11
  324. package/src/permissions/prompter.ts +13 -3
  325. package/src/permissions/v2-consent-policy.ts +87 -0
  326. package/src/platform/client.ts +1 -1
  327. package/src/prompts/system-prompt.ts +18 -21
  328. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
  329. package/src/prompts/templates/BOOTSTRAP.md +59 -96
  330. package/src/prompts/templates/SOUL.md +11 -11
  331. package/src/providers/anthropic/client.ts +1 -0
  332. package/src/providers/types.ts +1 -1
  333. package/src/runtime/AGENTS.md +23 -0
  334. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
  335. package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
  336. package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
  337. package/src/runtime/assistant-event-hub.ts +24 -2
  338. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  339. package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
  340. package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
  341. package/src/runtime/auth/middleware.ts +98 -0
  342. package/src/runtime/auth/route-policy.ts +6 -7
  343. package/src/runtime/auth/token-service.ts +8 -0
  344. package/src/runtime/capability-tokens.ts +414 -0
  345. package/src/runtime/channel-approvals.ts +18 -5
  346. package/src/runtime/chrome-extension-registry.ts +332 -0
  347. package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
  348. package/src/runtime/guardian-decision-types.ts +7 -0
  349. package/src/runtime/http-server.ts +425 -70
  350. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
  351. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
  352. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
  353. package/src/runtime/migrations/migration-transport.ts +6 -0
  354. package/src/runtime/migrations/migration-wizard.ts +22 -2
  355. package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
  356. package/src/runtime/migrations/vbundle-builder.ts +145 -38
  357. package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
  358. package/src/runtime/migrations/vbundle-importer.ts +55 -5
  359. package/src/runtime/pending-interactions.ts +29 -13
  360. package/src/runtime/routes/approval-routes.ts +90 -16
  361. package/src/runtime/routes/browser-cdp-routes.ts +229 -0
  362. package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
  363. package/src/runtime/routes/conversation-analysis-routes.ts +18 -5
  364. package/src/runtime/routes/conversation-management-routes.ts +108 -0
  365. package/src/runtime/routes/conversation-routes.ts +308 -28
  366. package/src/runtime/routes/conversation-starter-routes.ts +78 -16
  367. package/src/runtime/routes/group-routes.ts +22 -8
  368. package/src/runtime/routes/guardian-action-routes.ts +24 -13
  369. package/src/runtime/routes/host-browser-routes.ts +279 -0
  370. package/src/runtime/routes/host-file-routes.ts +9 -1
  371. package/src/runtime/routes/identity-routes.ts +259 -16
  372. package/src/runtime/routes/log-export/AGENTS.md +104 -0
  373. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
  374. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
  375. package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
  376. package/src/runtime/routes/log-export-routes.ts +60 -25
  377. package/src/runtime/routes/memory-item-routes.ts +1 -7
  378. package/src/runtime/routes/migration-routes.ts +87 -2
  379. package/src/runtime/routes/oauth-apps.ts +15 -17
  380. package/src/runtime/routes/oauth-providers.ts +4 -0
  381. package/src/runtime/routes/schedule-routes.ts +24 -11
  382. package/src/runtime/routes/settings-routes.ts +9 -97
  383. package/src/runtime/routes/skills-routes.ts +52 -2
  384. package/src/runtime/routes/subagents-routes.ts +14 -10
  385. package/src/runtime/routes/usage-routes.ts +8 -7
  386. package/src/runtime/routes/workspace-routes.test.ts +22 -0
  387. package/src/runtime/routes/workspace-routes.ts +8 -1
  388. package/src/runtime/routes/workspace-utils.ts +2 -0
  389. package/src/schedule/scheduler.ts +7 -5
  390. package/src/security/ces-credential-client.ts +20 -0
  391. package/src/security/ces-rpc-credential-backend.ts +17 -0
  392. package/src/security/credential-backend.ts +5 -0
  393. package/src/security/oauth2.ts +42 -25
  394. package/src/security/secure-keys.ts +118 -25
  395. package/src/security/token-manager.ts +23 -10
  396. package/src/skills/catalog-files.ts +492 -0
  397. package/src/skills/inline-command-runner.ts +12 -14
  398. package/src/subagent/manager.ts +131 -26
  399. package/src/subagent/types.ts +19 -0
  400. package/src/tools/apps/executors.ts +11 -2
  401. package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
  402. package/src/tools/browser/auth-detector.ts +43 -12
  403. package/src/tools/browser/browser-execution.ts +645 -340
  404. package/src/tools/browser/browser-manager.ts +36 -12
  405. package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
  406. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
  407. package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
  408. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
  409. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
  410. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
  411. package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
  412. package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
  413. package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
  414. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
  415. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
  416. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
  417. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
  418. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
  419. package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
  420. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
  421. package/src/tools/browser/cdp-client/errors.ts +34 -0
  422. package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
  423. package/src/tools/browser/cdp-client/factory.ts +204 -0
  424. package/src/tools/browser/cdp-client/index.ts +14 -0
  425. package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
  426. package/src/tools/browser/cdp-client/types.ts +52 -0
  427. package/src/tools/filesystem/edit.ts +1 -1
  428. package/src/tools/filesystem/list.ts +1 -1
  429. package/src/tools/filesystem/read.ts +1 -1
  430. package/src/tools/filesystem/write.ts +2 -1
  431. package/src/tools/host-filesystem/edit.ts +1 -1
  432. package/src/tools/host-filesystem/read.ts +12 -15
  433. package/src/tools/host-filesystem/write.ts +1 -1
  434. package/src/tools/host-terminal/host-shell.ts +21 -16
  435. package/src/tools/permission-checker.ts +77 -100
  436. package/src/tools/registry.ts +0 -2
  437. package/src/tools/secret-detection-handler.ts +34 -1
  438. package/src/tools/shared/filesystem/image-read.ts +61 -40
  439. package/src/tools/skills/sandbox-runner.ts +3 -6
  440. package/src/tools/subagent/spawn.ts +47 -3
  441. package/src/tools/subagent/status.ts +2 -0
  442. package/src/tools/system/register.ts +2 -16
  443. package/src/tools/terminal/safe-env.ts +7 -0
  444. package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
  445. package/src/tools/terminal/sandbox.ts +4 -1
  446. package/src/tools/terminal/shell.ts +24 -21
  447. package/src/tools/tool-approval-handler.ts +48 -2
  448. package/src/tools/types.ts +2 -3
  449. package/src/util/platform.ts +14 -19
  450. package/src/watcher/provider-types.ts +1 -1
  451. package/src/workspace/migrations/029-seed-pkb.ts +1 -0
  452. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
  453. package/src/workspace/migrations/registry.ts +2 -0
  454. package/src/workspace/top-level-renderer.ts +19 -1
  455. package/src/__tests__/chrome-cdp.test.ts +0 -419
  456. package/src/__tests__/permission-mode-sse.test.ts +0 -418
  457. package/src/__tests__/permission-mode-store.test.ts +0 -277
  458. package/src/browser-extension-relay/protocol.ts +0 -63
  459. package/src/browser-extension-relay/server.ts +0 -203
  460. package/src/config/schemas/sandbox.ts +0 -14
  461. package/src/permissions/permission-mode-store.ts +0 -180
  462. package/src/tools/browser/chrome-cdp.ts +0 -239
  463. package/src/tools/system/set-permission-mode.ts +0 -103
@@ -0,0 +1,125 @@
1
+ # Widget Component Library
2
+
3
+ A CSS/JS widget library is auto-injected alongside the design system. Use these for standard UI patterns - skip them when custom HTML serves the user better.
4
+
5
+ ## Layout widgets
6
+
7
+ | Widget | Purpose |
8
+ | ------------------------------------------------------------ | -------------------------------------------------------------- |
9
+ | `.v-metric-card` (`.v-metric-grid`) | Big number with emoji icon, label, trend |
10
+ | `.v-data-table` | Sortable table with sticky header, `th[data-sortable]` |
11
+ | `.v-tabs` / `.v-tab-bar` / `.v-tab-panel` | Tab navigation with keyboard support |
12
+ | `.v-accordion` / `.v-accordion-item` | Collapsible sections |
13
+ | `.v-search-bar` | Search input with clear button |
14
+ | `.v-empty-state` | No-data placeholder with CTA |
15
+ | `.v-timeline` / `.v-timeline-entry` | Vertical timeline (`.active`/`.success`/`.error`) |
16
+ | `.v-action-list` / `.v-action-list-item` | Rows with per-item actions |
17
+ | `.v-card-grid` | Responsive card grid |
18
+ | `.v-progress-bar` / `.v-progress-track` / `.v-progress-fill` | Horizontal progress |
19
+ | `.v-status-badge` | Colored pill with dot (`.success`/`.error`/`.warning`/`.info`) |
20
+ | `.v-stat-row` / `.v-stat` | Horizontal label-value pairs |
21
+ | `.v-toast` | Notification banner - prefer `vellum.widgets.toast()` |
22
+ | `.v-avatar-row` | Contact/team display |
23
+ | `.v-tag-group` | Wrapping tag row |
24
+
25
+ ## Domain-specific widgets
26
+
27
+ | Widget | Purpose |
28
+ | ------------------ | ---------------------- |
29
+ | `.v-weather-card` | Temperature + forecast |
30
+ | `.v-stock-ticker` | Price display + chart |
31
+ | `.v-flight-card` | Flight info with route |
32
+ | `.v-billing-chart` | Usage/billing display |
33
+ | `.v-boarding-pass` | Pass-styled layout |
34
+ | `.v-itinerary` | Day-by-day travel plan |
35
+ | `.v-receipt` | Receipt layout |
36
+ | `.v-invoice` | Formal invoice |
37
+
38
+ ## Content & landing page components
39
+
40
+ | Widget | Purpose |
41
+ | ------------------------------------------------ | --------------------------------------------------- |
42
+ | `.v-hero` / `.v-hero-badge` / `.v-hero-subtitle` | Hero banner with gradient, trust badge, accent word |
43
+ | `.v-section-header` / `.v-section-label` | Section intro with label |
44
+ | `.v-feature-grid` / `.v-feature-card` | Feature showcase with hover lift |
45
+ | `.v-pullquote` | Blockquote with gradient accent border |
46
+ | `.v-comparison` | Before/after cards (`.before`/`.after`) |
47
+ | `.v-page` | Centered container (max-width 600px) |
48
+ | `.v-gradient-text` | Accent-colored gradient text |
49
+ | `.v-animate-in` | Staggered fade-in for children |
50
+
51
+ ## Widget JavaScript utilities
52
+
53
+ Interactive utilities at `window.vellum.widgets.*`:
54
+
55
+ ### Charts
56
+
57
+ Always use these instead of hand-coding SVG/CSS charts:
58
+
59
+ ```javascript
60
+ vellum.widgets.sparkline("container-id", [10, 25, 15, 30], {
61
+ width: 200,
62
+ height: 40,
63
+ color: "var(--v-success)",
64
+ strokeWidth: 2,
65
+ fill: true,
66
+ });
67
+ vellum.widgets.barChart(
68
+ "container-id",
69
+ [
70
+ { label: "Jan", value: 120 },
71
+ { label: "Feb", value: 180, color: "var(--v-success)" },
72
+ ],
73
+ {
74
+ width: 400,
75
+ height: 200,
76
+ showLabels: true,
77
+ showValues: true,
78
+ horizontal: false,
79
+ },
80
+ );
81
+ vellum.widgets.lineChart(
82
+ "container-id",
83
+ [
84
+ { label: "Mon", value: 42 },
85
+ { label: "Tue", value: 58 },
86
+ ],
87
+ { width: 400, height: 200, showDots: true, showGrid: true, gridLines: 4 },
88
+ );
89
+ vellum.widgets.progressRing("container-id", 75, {
90
+ size: 100,
91
+ strokeWidth: 8,
92
+ color: "var(--v-success)",
93
+ label: "75%",
94
+ });
95
+ ```
96
+
97
+ ### Data Formatting
98
+
99
+ ```javascript
100
+ vellum.widgets.formatCurrency(1234.56, "USD"); // "$1,234.56"
101
+ vellum.widgets.formatDate("2025-01-15", "relative"); // "3d ago"
102
+ vellum.widgets.formatDate("2025-01-15", "short"); // "1/15/25"
103
+ vellum.widgets.formatNumber(1234567, { compact: true }); // "1.2M"
104
+ ```
105
+
106
+ ### Interactive Behaviors
107
+
108
+ ```javascript
109
+ vellum.widgets.sortTable("table-id"); // Wire th[data-sortable] click-to-sort
110
+ vellum.widgets.filterTable("table-id", "input-id"); // Live text search
111
+ vellum.widgets.tabs("tabs-id"); // Tab switching + keyboard nav
112
+ vellum.widgets.accordion("accordion-id", { allowMultiple: true });
113
+ vellum.widgets.multiSelect("table-id"); // Checkboxes + select-all
114
+ vellum.widgets.toast("Saved!", "success", 4000); // Auto-dismiss notification
115
+ vellum.widgets.countdown("timer-el", "2025-12-31T00:00:00Z", {
116
+ onComplete: () => {},
117
+ });
118
+ ```
119
+
120
+ ## When to use widgets vs custom HTML
121
+
122
+ - **Use widgets** for standard patterns - tables, metrics, timelines, notifications
123
+ - **Use custom HTML** for novel or creative UIs - games, art tools, unique dashboards
124
+ - **Mix freely** - widgets compose well together and with custom elements
125
+ - **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts. They handle overflow clipping, bounds, scaling, and dark mode. Hand-coded charts break layouts.
@@ -6,6 +6,9 @@ metadata:
6
6
  emoji: "👥"
7
7
  vellum:
8
8
  display-name: "Contacts"
9
+ activation-hints:
10
+ - "Look up contact info before asking the user for email addresses or phone numbers"
11
+ - "User wants to manage who can message the assistant, or create/revoke invite links"
9
12
  ---
10
13
 
11
14
  Manage the user's contacts, relationship graph, access control (trusted contacts), and invite links. This skill covers contact CRUD with multi-channel tracking, controlling who can message the assistant through external channels (Telegram, phone), and creating/managing invite links that grant access.
@@ -6,6 +6,10 @@ metadata:
6
6
  emoji: "📄"
7
7
  vellum:
8
8
  display-name: "Document"
9
+ activation-hints:
10
+ - "User asks to write, draft, or collaborate on long-form content — use the document editor for a better editing experience"
11
+ - "When content will be iterated on, reviewed, or exported, prefer the document editor over inline markdown"
12
+ - "When a file attachment contains a draft or document the user wants to iterate on, open it in the editor"
9
13
  ---
10
14
 
11
15
  Create and edit long-form documents using the built-in rich text editor. Documents open in workspace mode with chat docked to the side.
@@ -110,22 +110,27 @@ When a user asks to declutter, clean up, or organize their email - start scannin
110
110
 
111
111
  ### Workflow
112
112
 
113
- 1. **Scan**: Call `gmail_sender_digest`. Default query targets promotions from the last 90 days.
113
+ 1. **Scan**: Call `gmail_sender_digest`. Default query targets promotions currently in the inbox from the last 90 days (`in:inbox category:promotions newer_than:90d`). Counts shown in the table reflect only what is currently in the inbox — these are the emails that will be archived.
114
114
  2. **Present**: Show results as a `ui_show` table with `selectionMode: "multiple"`:
115
115
  - **Columns (exactly 3)**: Sender, Emails Found, Unsub?
116
116
  - **Unsub? cell values**: Use rich cell format: `{ "text": "Yes", "icon": "checkmark.circle.fill", "iconColor": "success" }` when `has_unsubscribe` is true, `{ "text": "No", "icon": "minus.circle", "iconColor": "muted" }` when false.
117
117
  - **Pre-select all rows** (`selected: true`) - users deselect what they want to keep
118
118
  - **Caption**: Include two parts separated by a newline: (1) data scope, e.g. "Newsletters, notifications, and outreach from last 90 days. Deselect anything you want to keep." (adjusted to match the query used), and (2) the Unsub? column legend: "Unsub? - \"Yes\" means these emails contain an unsubscribe link, so I can opt you out automatically. \"No\" means no unsubscribe link was found - these will be archived but you may continue receiving them."
119
119
  - **Action buttons (exactly 2)**: "Archive & Unsubscribe" (primary), "Archive Only" (secondary). **NEVER offer Delete, Trash, or any destructive action.**
120
- 3. **Wait for user action**: Stop and wait. Do NOT proceed to archiving or unsubscribing until the user clicks one of the action buttons on the table. When the user clicks an action button:
120
+ 3. **Embed scan_id in button data**: When constructing the action buttons in `ui_show`, include the `scan_id` from the `gmail_sender_digest` result in each button's `data` field. This ensures `scan_id` is forwarded automatically when the user clicks the LLM does not need to recall it from earlier context:
121
+ ```json
122
+ { "id": "archive_unsubscribe", "label": "Archive & Unsubscribe", "style": "primary", "data": { "scan_id": "<scan_id value here>" } }
123
+ ```
124
+ 4. **Wait for user action**: Stop and wait. Do NOT proceed to archiving or unsubscribing until the user clicks one of the action buttons on the table. When the user clicks an action button you will receive a surface action message containing `action data: { scan_id, selectedIds }`:
125
+ - `selectedIds` are **sender IDs** (the `id` values from the scan result rows, base64-encoded email addresses) — NOT Gmail message IDs. Always use them as `sender_ids` with `scan_id`, never as `message_ids`.
121
126
  - **Dismiss the table immediately** with `ui_dismiss` - it collapses to a completion chip
122
127
  - **Show a `task_progress` card** with steps for each phase (e.g., "Archiving 89 senders (2,400 emails)", "Unsubscribing from 72 senders"). Update each step from `in_progress` → `completed` as each phase finishes.
123
128
  - When all senders are processed, set the progress card's `status: "completed"`.
124
- 4. **Act on selection** - batch, don't loop:
125
- - **Archive all at once**: Call `gmail_archive` **once** with `scan_id` + **all** selected senders' `id` values in the `sender_ids` array. The tool resolves message IDs server-side and batches the Gmail API calls internally - never loop sender-by-sender.
129
+ 5. **Act on selection** - batch, don't loop:
130
+ - **Archive all at once**: Call `gmail_archive` **once** with `scan_id` (from action data) + `sender_ids` set to all `selectedIds` from the action data. The tool resolves message IDs server-side and batches the Gmail API calls internally - never loop sender-by-sender. **Never** pass `selectedIds` as `message_ids` — they are sender IDs, not Gmail message IDs.
126
131
  - **Unsubscribe in bulk**: If the action is "Archive & Unsubscribe", call `gmail_unsubscribe` for each sender that has `has_unsubscribe: true` - but emit **all** unsubscribe tool calls in a **single assistant response** (parallel tool use) rather than one-at-a-time across separate turns.
127
- 5. **Accurate summary**: The scan counts are exact - the `message_count` shown in the table matches the number of messages archived. Format: "Cleaned up [total_archived] emails from [sender_count] senders. Unsubscribed from [unsub_count]."
128
- 6. **Ongoing protection offer**: After reporting results, offer auto-archive filters:
132
+ 6. **Accurate summary**: The scan counts are exact - the `message_count` shown in the table matches the number of messages archived. Format: "Cleaned up [total_archived] emails from [sender_count] senders. Unsubscribed from [unsub_count]."
133
+ 7. **Ongoing protection offer**: After reporting results, offer auto-archive filters:
129
134
  - "Want me to set up auto-archive filters so future emails from these senders skip your inbox?"
130
135
  - If yes, call `gmail_filters` with `action: "create"` for each sender with `from` set to the sender's email and `remove_label_ids: ["INBOX"]`.
131
136
  - Then offer a recurring declutter schedule: "Want me to scan for new clutter monthly?" If yes, use `schedule_create` to set up a monthly declutter check.
@@ -156,7 +161,7 @@ Scan tools (`gmail_sender_digest`, `gmail_outreach_scan`) return a `scan_id` tha
156
161
 
157
162
  Before composing any email that references a date or time:
158
163
 
159
- 1. Check the `timestamp:` field in the `<turn_context>` block for today's date and timezone
164
+ 1. Check the `current_time:` field in the `<turn_context>` block for today's date and timezone
160
165
  2. Verify that "tomorrow" means the day after today's date, "next week" means the upcoming Monday–Friday, etc.
161
166
  3. If the email references a date from another message, cross-check it against the turn context to ensure it's in the future
162
167
 
@@ -490,7 +490,7 @@
490
490
  "properties": {
491
491
  "query": {
492
492
  "type": "string",
493
- "description": "Gmail search query (default 'category:promotions newer_than:90d')"
493
+ "description": "Gmail search query (default 'in:inbox category:promotions newer_than:90d')"
494
494
  },
495
495
  "max_messages": {
496
496
  "type": "number",
@@ -49,7 +49,8 @@ export async function run(
49
49
  _context: ToolContext,
50
50
  ): Promise<ToolExecutionResult> {
51
51
  const account = input.account as string | undefined;
52
- const query = (input.query as string) ?? "category:promotions newer_than:90d";
52
+ const query =
53
+ (input.query as string) ?? "in:inbox category:promotions newer_than:90d";
53
54
  const maxMessages = Math.min(
54
55
  (input.max_messages as number) ?? 5000,
55
56
  MAX_MESSAGES_CAP,
@@ -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.
@@ -72,7 +72,7 @@
72
72
  "Sounds",
73
73
  "Permissions & Privacy",
74
74
  "Billing",
75
- "Archived Conversations",
75
+ "Archive",
76
76
  "Schedules",
77
77
  "Developer"
78
78
  ],
@@ -10,21 +10,26 @@ const SETTINGS_TABS = [
10
10
  "Sounds",
11
11
  "Permissions & Privacy",
12
12
  "Billing",
13
- "Archived Conversations",
13
+ "Archive",
14
14
  "Schedules",
15
15
  "Developer",
16
16
  ] as const;
17
17
 
18
18
  type SettingsTab = (typeof SETTINGS_TABS)[number];
19
19
 
20
+ const LEGACY_TAB_ALIASES: Record<string, SettingsTab> = {
21
+ "Archived Conversations": "Archive",
22
+ };
23
+
20
24
  export async function run(
21
25
  input: Record<string, unknown>,
22
26
  context: ToolContext,
23
27
  ): Promise<ToolExecutionResult> {
24
- const tab = input.tab as string;
28
+ const rawTab = input.tab as string;
29
+ const tab = LEGACY_TAB_ALIASES[rawTab] ?? rawTab;
25
30
  if (!SETTINGS_TABS.includes(tab as SettingsTab)) {
26
31
  return {
27
- content: `Error: unknown tab "${tab}". Valid tabs: ${SETTINGS_TABS.join(
32
+ content: `Error: unknown tab "${rawTab}". Valid tabs: ${SETTINGS_TABS.join(
28
33
  ", ",
29
34
  )}`,
30
35
  isError: true,
@@ -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 {
@@ -126,8 +126,8 @@
126
126
  "scope": "macos",
127
127
  "key": "referral-codes",
128
128
  "label": "Referral Codes",
129
- "description": "Show the referral invite link and stats panel on the Billing tab in Settings",
130
- "defaultEnabled": false
129
+ "description": "Surface the Earn Credits referral entry points (sidebar drawer row and Billing tab button) that open the referral modal",
130
+ "defaultEnabled": true
131
131
  },
132
132
  {
133
133
  "id": "managed-sign-in",
@@ -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
+ }