@vellumai/assistant 0.4.34 → 0.4.36

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 (251) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +44 -49
  3. package/README.md +32 -20
  4. package/docs/architecture/keychain-broker.md +186 -0
  5. package/docs/architecture/security.md +110 -116
  6. package/docs/runbook-trusted-contacts.md +2 -2
  7. package/docs/skills.md +25 -25
  8. package/package.json +4 -1
  9. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +11 -2
  10. package/src/__tests__/actor-token-service.test.ts +1 -0
  11. package/src/__tests__/amazon-cdp-integration.test.ts +74 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +38 -9
  13. package/src/__tests__/assistant-id-boundary-guard.test.ts +91 -43
  14. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  15. package/src/__tests__/bundle-scanner.test.ts +1 -1
  16. package/src/__tests__/channel-guardian.test.ts +102 -102
  17. package/src/__tests__/channel-invite-transport.test.ts +155 -256
  18. package/src/__tests__/channel-readiness-routes.test.ts +336 -0
  19. package/src/__tests__/checker.test.ts +6 -6
  20. package/src/__tests__/chrome-cdp.test.ts +350 -0
  21. package/src/__tests__/computer-use-session-lifecycle.test.ts +3 -3
  22. package/src/__tests__/computer-use-session-working-dir.test.ts +86 -52
  23. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
  24. package/src/__tests__/config-loader-migration.test.ts +85 -0
  25. package/src/__tests__/conversation-pairing.test.ts +370 -5
  26. package/src/__tests__/credential-broker-browser-fill.test.ts +1 -10
  27. package/src/__tests__/credential-broker-server-use.test.ts +1 -10
  28. package/src/__tests__/credential-security-e2e.test.ts +7 -1
  29. package/src/__tests__/credential-security-invariants.test.ts +14 -20
  30. package/src/__tests__/credential-vault-unit.test.ts +1 -11
  31. package/src/__tests__/credential-vault.test.ts +5 -19
  32. package/src/__tests__/credentials-cli.test.ts +806 -0
  33. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +23 -4
  34. package/src/__tests__/email-invite-adapter.test.ts +78 -0
  35. package/src/__tests__/email-service-config-fallback.test.ts +102 -0
  36. package/src/__tests__/encrypted-store.test.ts +6 -6
  37. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  38. package/src/__tests__/gateway-only-enforcement.test.ts +5 -1
  39. package/src/__tests__/guardian-actions-endpoint.test.ts +70 -12
  40. package/src/__tests__/guardian-outbound-http.test.ts +53 -47
  41. package/src/__tests__/handle-user-message-secret-resume.test.ts +23 -0
  42. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +32 -23
  43. package/src/__tests__/handlers-telegram-config.test.ts +8 -2
  44. package/src/__tests__/handlers-twitter-config.test.ts +2 -2
  45. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +108 -7
  46. package/src/__tests__/ingress-reconcile.test.ts +6 -0
  47. package/src/__tests__/intent-routing.test.ts +23 -4
  48. package/src/__tests__/invite-routes-http.test.ts +12 -0
  49. package/src/__tests__/ipc-snapshot.test.ts +8 -2
  50. package/src/__tests__/keychain-broker-client.test.ts +543 -0
  51. package/src/__tests__/llm-usage-store.test.ts +344 -0
  52. package/src/__tests__/mcp-client-auth.test.ts +2 -2
  53. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  54. package/src/__tests__/migration-transport.test.ts +49 -0
  55. package/src/__tests__/notification-broadcaster.test.ts +205 -5
  56. package/src/__tests__/notification-deep-link.test.ts +365 -1
  57. package/src/__tests__/oauth-connect-handler.test.ts +2 -2
  58. package/src/__tests__/onboarding-starter-tasks.test.ts +17 -4
  59. package/src/__tests__/proxy-approval-callback.test.ts +1 -1
  60. package/src/__tests__/recording-handler.test.ts +1 -1
  61. package/src/__tests__/recording-intent-handler.test.ts +6 -1
  62. package/src/__tests__/recording-state-machine.test.ts +1 -1
  63. package/src/__tests__/relay-server.test.ts +9 -1
  64. package/src/__tests__/ride-shotgun-handler.test.ts +499 -0
  65. package/src/__tests__/runtime-attachment-metadata.test.ts +160 -1
  66. package/src/__tests__/script-proxy-injection-runtime.test.ts +299 -2
  67. package/src/__tests__/script-proxy-profile-template-fallback.test.ts +1 -1
  68. package/src/__tests__/secret-onetime-send.test.ts +8 -2
  69. package/src/__tests__/secure-keys.test.ts +175 -216
  70. package/src/__tests__/session-confirmation-signals.test.ts +1 -1
  71. package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -1
  72. package/src/__tests__/session-queue.test.ts +2 -1
  73. package/src/__tests__/session-tool-setup-app-refresh.test.ts +2 -2
  74. package/src/__tests__/skill-feature-flags-integration.test.ts +29 -4
  75. package/src/__tests__/skill-feature-flags.test.ts +12 -9
  76. package/src/__tests__/skill-load-feature-flag.test.ts +26 -5
  77. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  78. package/src/__tests__/skills.test.ts +34 -4
  79. package/src/__tests__/slack-channel-config.test.ts +2 -2
  80. package/src/__tests__/system-prompt.test.ts +26 -4
  81. package/src/__tests__/telegram-bot-username-resolution.test.ts +212 -0
  82. package/src/__tests__/telegram-invite-adapter.test.ts +164 -0
  83. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  84. package/src/__tests__/tool-permission-simulate-handler.test.ts +8 -2
  85. package/src/__tests__/trusted-contact-approval-notifier.test.ts +9 -1
  86. package/src/__tests__/twitter-auth-handler.test.ts +2 -2
  87. package/src/__tests__/twitter-oauth-client.test.ts +1 -1
  88. package/src/__tests__/usage-routes.test.ts +339 -0
  89. package/src/__tests__/whatsapp-invite-adapter.test.ts +94 -0
  90. package/src/agent/loop.ts +3 -0
  91. package/src/amazon/checkout.ts +0 -1
  92. package/src/approvals/guardian-request-resolvers.ts +9 -1
  93. package/src/bundler/app-bundler.ts +28 -12
  94. package/src/bundler/bundle-scanner.ts +1 -1
  95. package/src/bundler/bundle-signer.ts +3 -3
  96. package/src/bundler/manifest.ts +1 -1
  97. package/src/bundler/signature-verifier.ts +3 -3
  98. package/src/channels/config.ts +1 -1
  99. package/src/cli/AGENTS.md +63 -0
  100. package/src/cli/__tests__/notifications.test.ts +470 -0
  101. package/src/cli/amazon.ts +344 -167
  102. package/src/cli/audit.ts +85 -0
  103. package/src/cli/autonomy.ts +369 -0
  104. package/src/cli/channels.ts +51 -0
  105. package/src/cli/completions.ts +208 -0
  106. package/src/cli/config.ts +220 -0
  107. package/src/cli/contacts.ts +471 -0
  108. package/src/cli/credentials.ts +564 -0
  109. package/src/cli/default-action.ts +14 -0
  110. package/src/cli/dev.ts +131 -0
  111. package/src/cli/doctor.ts +398 -0
  112. package/src/cli/email.ts +491 -0
  113. package/src/cli/influencer.ts +72 -0
  114. package/src/cli/integrations.ts +248 -57
  115. package/src/cli/keys.ts +114 -0
  116. package/src/cli/map.ts +46 -54
  117. package/src/cli/mcp.ts +111 -3
  118. package/src/cli/{config-commands.ts → memory.ts} +133 -242
  119. package/src/cli/notifications.ts +407 -0
  120. package/src/cli/program.ts +65 -0
  121. package/src/cli/reference.ts +48 -0
  122. package/src/cli/sequence.ts +154 -0
  123. package/src/cli/sessions.ts +262 -0
  124. package/src/cli/trust.ts +177 -0
  125. package/src/cli/twitter.ts +323 -106
  126. package/src/config/__tests__/build-cli-reference-section.test.ts +49 -0
  127. package/src/config/bundled-skills/amazon/SKILL.md +2 -2
  128. package/src/config/bundled-skills/app-builder/TOOLS.json +26 -0
  129. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +13 -0
  130. package/src/config/bundled-skills/contacts/SKILL.md +178 -10
  131. package/src/config/bundled-skills/doordash/doordash-cli.ts +23 -168
  132. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +175 -145
  133. package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
  134. package/src/config/bundled-skills/twilio-setup/SKILL.md +70 -17
  135. package/src/config/bundled-tool-registry.ts +2 -0
  136. package/src/config/core-schema.ts +7 -0
  137. package/src/config/feature-flag-registry.json +16 -0
  138. package/src/config/loader.ts +26 -0
  139. package/src/config/schema.ts +4 -0
  140. package/src/config/skill-state.ts +0 -13
  141. package/src/config/system-prompt.ts +27 -0
  142. package/src/contacts/contact-store.ts +25 -0
  143. package/src/daemon/computer-use-session.ts +1 -1
  144. package/src/daemon/handlers/apps.ts +1 -0
  145. package/src/daemon/handlers/config-channels.ts +3 -3
  146. package/src/daemon/handlers/config-dispatch.ts +29 -0
  147. package/src/daemon/handlers/config-inbox.ts +4 -3
  148. package/src/daemon/handlers/config.ts +3 -43
  149. package/src/daemon/handlers/contacts.ts +34 -0
  150. package/src/daemon/handlers/index.ts +17 -3
  151. package/src/daemon/handlers/session-user-message.ts +7 -0
  152. package/src/daemon/handlers/sessions.ts +21 -2
  153. package/src/daemon/handlers/shared.ts +17 -0
  154. package/src/daemon/ipc-contract/apps.ts +2 -0
  155. package/src/daemon/ipc-contract/computer-use.ts +9 -0
  156. package/src/daemon/ipc-contract/contacts.ts +3 -3
  157. package/src/daemon/ipc-contract/inbox.ts +2 -0
  158. package/src/daemon/ipc-contract/messages.ts +4 -0
  159. package/src/daemon/ipc-contract/sessions.ts +8 -0
  160. package/src/daemon/ipc-contract-inventory.json +1 -0
  161. package/src/daemon/lifecycle.ts +0 -5
  162. package/src/daemon/ride-shotgun-handler.ts +139 -25
  163. package/src/daemon/session-agent-loop-handlers.ts +100 -0
  164. package/src/daemon/session-agent-loop.ts +72 -0
  165. package/src/daemon/session-tool-setup.ts +7 -0
  166. package/src/daemon/session.ts +23 -1
  167. package/src/daemon/tool-side-effects.ts +39 -1
  168. package/src/email/service.ts +59 -2
  169. package/src/index.ts +2 -60
  170. package/src/mcp/mcp-oauth-provider.ts +90 -8
  171. package/src/media/app-icon-generator.ts +86 -0
  172. package/src/memory/db-init.ts +12 -1
  173. package/src/memory/llm-usage-store.ts +186 -0
  174. package/src/memory/migrations/026-guardian-verification-sessions.ts +28 -9
  175. package/src/memory/migrations/027a-guardian-bootstrap-token.ts +16 -3
  176. package/src/memory/migrations/038-actor-token-records.ts +8 -1
  177. package/src/memory/migrations/039-actor-refresh-token-records.ts +11 -2
  178. package/src/memory/migrations/110-channel-guardian.ts +27 -6
  179. package/src/memory/migrations/112-assistant-inbox.ts +39 -15
  180. package/src/memory/migrations/114-notifications.ts +37 -15
  181. package/src/memory/migrations/117-conversation-attention.ts +33 -9
  182. package/src/memory/migrations/137-usage-dashboard-indexes.ts +26 -0
  183. package/src/memory/migrations/139-drop-usage-composite-indexes.ts +30 -0
  184. package/src/memory/migrations/index.ts +2 -0
  185. package/src/memory/migrations/schema-introspection.ts +18 -0
  186. package/src/memory/schema-migration.ts +1 -0
  187. package/src/memory/shared-app-links-store.ts +1 -1
  188. package/src/messaging/registry.ts +27 -0
  189. package/src/notifications/README.md +79 -70
  190. package/src/notifications/broadcaster.ts +2 -1
  191. package/src/notifications/conversation-pairing.ts +147 -13
  192. package/src/notifications/copy-composer.ts +7 -3
  193. package/src/notifications/destination-resolver.ts +14 -1
  194. package/src/notifications/emit-signal.ts +3 -2
  195. package/src/notifications/signal.ts +105 -1
  196. package/src/notifications/types.ts +16 -0
  197. package/src/permissions/checker.ts +29 -3
  198. package/src/permissions/prompter.ts +11 -3
  199. package/src/runtime/access-request-helper.ts +2 -1
  200. package/src/runtime/auth/route-policy.ts +7 -1
  201. package/src/runtime/channel-invite-transport.ts +40 -63
  202. package/src/runtime/channel-invite-transports/email.ts +13 -39
  203. package/src/runtime/channel-invite-transports/slack.ts +5 -34
  204. package/src/runtime/channel-invite-transports/sms.ts +8 -29
  205. package/src/runtime/channel-invite-transports/telegram.ts +69 -28
  206. package/src/runtime/channel-invite-transports/voice.ts +0 -7
  207. package/src/runtime/channel-invite-transports/whatsapp.ts +43 -0
  208. package/src/runtime/channel-readiness-service.ts +202 -45
  209. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -1
  210. package/src/runtime/guardian-outbound-actions.ts +8 -5
  211. package/src/runtime/http-server.ts +5 -9
  212. package/src/runtime/http-types.ts +13 -1
  213. package/src/runtime/invite-instruction-generator.ts +178 -0
  214. package/src/runtime/invite-service.ts +22 -25
  215. package/src/runtime/migrations/migration-transport.ts +13 -0
  216. package/src/runtime/routes/app-routes.ts +1 -1
  217. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +8 -7
  218. package/src/runtime/routes/channel-readiness-routes.ts +30 -11
  219. package/src/runtime/routes/contact-routes.ts +54 -26
  220. package/src/runtime/routes/guardian-bootstrap-routes.ts +1 -1
  221. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -1
  222. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -1
  223. package/src/runtime/routes/inbound-stages/verification-intercept.ts +2 -1
  224. package/src/runtime/routes/integration-routes.ts +1 -1
  225. package/src/runtime/routes/invite-routes.ts +1 -1
  226. package/src/runtime/routes/secret-routes.ts +31 -7
  227. package/src/runtime/routes/surface-content-routes.ts +104 -0
  228. package/src/runtime/routes/twilio-routes.ts +32 -1
  229. package/src/runtime/routes/usage-routes.ts +114 -0
  230. package/src/runtime/tool-grant-request-helper.ts +2 -1
  231. package/src/security/encrypted-store.ts +9 -5
  232. package/src/security/keychain-broker-client.ts +393 -0
  233. package/src/security/secure-keys.ts +106 -321
  234. package/src/tools/apps/executors.ts +73 -0
  235. package/src/tools/browser/auto-navigate.ts +15 -6
  236. package/src/tools/browser/chrome-cdp.ts +211 -0
  237. package/src/tools/browser/network-recorder.test.ts +83 -0
  238. package/src/tools/browser/network-recorder.ts +8 -7
  239. package/src/tools/browser/x-auto-navigate.ts +12 -6
  240. package/src/tools/credentials/policy-types.ts +24 -0
  241. package/src/tools/credentials/vault.ts +22 -27
  242. package/src/tools/network/script-proxy/session-manager.ts +47 -3
  243. package/src/tools/permission-checker.ts +1 -0
  244. package/src/tools/types.ts +2 -0
  245. package/src/tools/ui-surface/definitions.ts +1 -2
  246. package/src/tools/watch/watch-state.ts +2 -0
  247. package/src/__tests__/key-migration.test.ts +0 -240
  248. package/src/__tests__/keychain.test.ts +0 -286
  249. package/src/cli/core-commands.ts +0 -899
  250. package/src/security/keychain-to-encrypted-migration.ts +0 -66
  251. package/src/security/keychain.ts +0 -490
@@ -1,20 +1,20 @@
1
1
  ---
2
2
  name: "Google OAuth Setup"
3
- description: "Set up Google Cloud OAuth credentials for Gmail and Calendar using browser automation"
3
+ description: "Set up Google Cloud OAuth credentials for Gmail and Calendar"
4
4
  user-invocable: true
5
5
  credential-setup-for: "gmail"
6
- includes: ["browser", "public-ingress"]
7
- metadata: {"vellum": {"emoji": "\ud83d\udd11"}}
6
+ includes: ["public-ingress", "browser"]
7
+ metadata: { "vellum": { "emoji": "\ud83d\udd11" } }
8
8
  ---
9
9
 
10
10
  You are helping your user set up Google Cloud OAuth credentials so Gmail and Google Calendar integrations can connect.
11
11
 
12
12
  ## Client Check
13
13
 
14
- Determine whether the user has browser automation available (macOS desktop app) or is on a non-interactive channel (Telegram, SMS, etc.).
14
+ Determine which setup path to use based on the user's client:
15
15
 
16
- - **macOS desktop app**: Follow the **Automated Setup** path below.
17
- - **Telegram or other channel** (no browser automation): Follow the **Manual Setup for Channels** path below.
16
+ - **macOS desktop app**: Follow **Path B: CLI Setup** below.
17
+ - **Telegram or other channel** (no browser automation): Follow **Path A: Manual Setup for Channels** below.
18
18
 
19
19
  ---
20
20
 
@@ -29,6 +29,7 @@ Tell the user:
29
29
  > **Setting up Gmail & Calendar from Telegram**
30
30
  >
31
31
  > Since I can't automate the browser from here, I'll walk you through each step with direct links. You'll need:
32
+ >
32
33
  > 1. A Google account with access to Google Cloud Console
33
34
  > 2. About 5 minutes
34
35
  >
@@ -87,6 +88,7 @@ Tell the user:
87
88
  > - `https://www.googleapis.com/auth/calendar.readonly`
88
89
  > - `https://www.googleapis.com/auth/calendar.events`
89
90
  > - `https://www.googleapis.com/auth/userinfo.email`
91
+ > - `https://www.googleapis.com/auth/contacts.readonly`
90
92
  > - Click **Update**, then **Save and Continue**
91
93
  > 5. On the Test users page, add **your email**, click **Save and Continue**
92
94
  > 6. On the Summary page, click **Back to Dashboard**
@@ -96,6 +98,7 @@ Tell the user:
96
98
  ### Channel Step 5: Create OAuth Credentials (Web Application)
97
99
 
98
100
  Before sending Step 4 to the user, resolve the concrete callback URL:
101
+
99
102
  - Read the configured public gateway URL (`ingress.publicBaseUrl`). If it is missing, run the `public-ingress` skill first.
100
103
  - Build `oauthCallbackUrl` as `<public gateway URL>/webhooks/oauth/callback`.
101
104
  - When you send the instructions below, replace `OAUTH_CALLBACK_URL` with that concrete value. Never send placeholders literally.
@@ -140,7 +143,7 @@ credential_store store:
140
143
 
141
144
  **Step 6b: Client Secret (requires split entry to avoid security filters)**
142
145
 
143
- The Client Secret starts with `GOCSPX-` which triggers the ingress secret scanner on channel messages. To work around this, ask the user to send only the portion *after* the prefix.
146
+ The Client Secret starts with `GOCSPX-` which triggers the ingress secret scanner on channel messages. To work around this, ask the user to send only the portion _after_ the prefix.
144
147
 
145
148
  Tell the user:
146
149
 
@@ -192,229 +195,265 @@ After the user authorizes (they'll come back and say so, or you can suggest they
192
195
 
193
196
  ---
194
197
 
195
- # Path B: Automated Setup (macOS Desktop App)
198
+ # Path B: CLI Setup (macOS Desktop App)
196
199
 
197
- You will automate the entire GCP setup via the browser while the user watches in the Chrome window on the side. The user's only manual actions are: signing in to their Google account, and copy-pasting credentials from the Chrome window into secure prompts.
200
+ **IMPORTANT: Always use `host_bash` (not `bash`) for all commands in this path.** The `gcloud` and `gws` CLIs need host access for Homebrew/npm installation, browser-based authentication, and interactive terminal prompts none of which are available inside the sandbox.
201
+
202
+ You will set up Google Cloud OAuth credentials using the `gcloud` and `gws` command-line tools plus browser automation. The user signs in once via the browser, the CLI handles project setup, and the browser automates credential creation — the user only needs to copy-paste the Client Secret.
198
203
 
199
204
  ## Browser Interaction Principles
200
205
 
201
- Google Cloud Console's UI changes frequently. Do NOT memorize or depend on specific element IDs, CSS selectors, or DOM structures. Instead:
206
+ Google Cloud Console's UI may change over time. Do NOT memorize or depend on specific element IDs, CSS selectors, or DOM structures. Instead:
202
207
 
203
- 1. **Snapshot first, act second.** Before every interaction, use `browser_snapshot` to discover interactive elements and their IDs. This is your primary navigation tool; it gives you the accessibility tree with clickable/typeable element IDs. Use `browser_screenshot` for visual context when the snapshot alone isn't enough.
204
- 2. **Adapt to what you see.** If an element's label or position differs from what you expect, use the snapshot to find the correct element. GCP may rename buttons, reorganize menus, or change form layouts at any time.
205
- 3. **Verify after every action.** After clicking, typing, or navigating, take a new snapshot to confirm the action succeeded. If it didn't, try an alternative interaction (e.g., if a dropdown didn't open on click, try pressing Space or Enter on the element).
206
- 4. **Never assume DOM structure.** Dropdowns may be `<select>`, `<mat-select>`, `<div role="listbox">`, or something else entirely. Use the snapshot to identify element types and interact accordingly.
207
- 5. **When stuck after 2 attempts, describe and ask.** Take a screenshot, describe what you see to the user, and ask for guidance.
208
+ 1. **Screenshot first, act second.** Before every interaction, take a `browser_screenshot` to see the current visual state. Use `browser_snapshot` to find interactive elements.
209
+ 2. **Adapt to what you see.** If a button's label or position differs from what you expect, use the screenshot to find the correct element.
210
+ 3. **Verify after every action.** After clicking, typing, or navigating, take a new screenshot to confirm the action succeeded.
211
+ 4. **Never assume DOM structure.** Use the snapshot to identify what's on the page and interact accordingly.
212
+ 5. **When stuck, screenshot and describe.** If you cannot find an expected element after 2 attempts, take a screenshot, describe what you see to the user, and ask for guidance.
208
213
 
209
214
  ## Anti-Loop Guardrails
210
215
 
211
216
  Each step has a **retry budget of 3 attempts**. An attempt is one try at the step's primary action (e.g., clicking a button, filling a form). If a step fails after 3 attempts:
212
217
 
213
218
  1. **Stop trying.** Do not continue retrying the same approach.
214
- 2. **Fall back to manual.** Tell the user what you were trying to do and ask them to complete that step manually in the Chrome window (which they can see on the side). Give them the direct URL and clear text instructions.
219
+ 2. **Fall back to manual.** Tell the user what you were trying to do and ask them to complete that step manually in the browser. Give them the direct URL and clear text instructions.
215
220
  3. **Resume automation** at the next step once the user confirms the manual step is done.
216
221
 
217
- If **two or more steps** require manual fallback, abandon the automated flow entirely and switch to giving the user the remaining steps as clear text instructions with links, using "Desktop app" as the OAuth application type.
222
+ If **two or more steps** require manual fallback, abandon the automated flow entirely and switch to giving the user the remaining steps as clear text instructions with links.
218
223
 
219
- ## Things That Do Not Work: Do Not Attempt
224
+ ## Things That Do Not Work Do Not Attempt
220
225
 
221
- These actions are technically impossible in the browser automation environment. Attempting them wastes time and leads to loops:
226
+ These actions are technically impossible in the browser automation environment:
222
227
 
223
- - **Downloading files.** `browser_click` on a Download button does not save files to disk. There is NO JSON file to find at `~/Downloads` or anywhere else. Never click Download buttons.
224
- - **Clipboard operations.** You cannot copy/paste via browser automation. The user must manually copy values from the Chrome window.
225
- - **Deleting and recreating OAuth clients** to get a fresh secret. This orphans the stored client_id and causes `invalid_client` errors.
226
- - **Navigating away from the credential dialog** before both credentials are stored. You will lose the Client Secret display and cannot get it back without creating a new client.
228
+ - **Downloading files.** `browser_click` on a Download button does not save files to disk. Do NOT click "Download JSON" in the OAuth client creation dialog.
229
+ - **Reading the Client Secret from a screenshot.** The secret IS visible in the creation dialog, but you MUST NOT attempt to read it from a screenshot — it is too easy to misread characters, and the value must be exact. Always use the `credential_store prompt` approach to let the user copy-paste it accurately.
230
+ - **Clipboard operations.** You cannot copy/paste via browser automation.
227
231
 
228
- ## Step 1: Single Upfront Confirmation
232
+ ## Error Handling
233
+
234
+ - **Page load failures:** Retry navigation once. If it still fails, tell the user and ask them to check their internet connection.
235
+ - **Element not found:** Take a fresh screenshot to re-assess. The GCP Console UI may have changed. Describe what you see and try alternative approaches. If stuck after 2 attempts, ask the user for guidance.
236
+ - **OAuth client already exists with same name:** This is fine — GCP allows multiple clients with the same name. Proceed with creation.
237
+ - **Any unexpected state:** Take a `browser_screenshot`, describe what you see, and ask the user for guidance.
229
238
 
230
- Use `ui_show` with `surface_type: "confirmation"`. Set `message` to just the title, and `detail` to the body:
239
+ ## CLI Step 1: Confirm
240
+
241
+ Use `ui_show` with `surface_type: "confirmation"`:
231
242
 
232
243
  - **message:** `Set up Google Cloud for Gmail & Calendar`
233
244
  - **detail:**
234
245
  > Here's what will happen:
235
- > 1. **A browser opens on the side** so you can watch everything I do
236
- > 2. **You sign in** to your Google account in the browser
237
- > 3. **I automate everything** including project creation, APIs, OAuth config, and credentials
238
- > 4. **One copy-paste** where I'll ask you to copy the Client Secret from the browser into a secure prompt
239
- > 5. **You authorize Vellum** with one click
240
246
  >
241
- > The whole thing takes 2-3 minutes. Ready?
247
+ > 1. **Install CLI tools** (`gcloud` and `gws`) if not already installed
248
+ > 2. **You sign in** to your Google account once via the browser
249
+ > 3. **CLI automates everything** — project creation, APIs, and consent screen
250
+ > 4. **I create OAuth credentials** in the browser — you just watch
251
+ > 5. **One quick copy-paste** — you copy the Client Secret into a secure prompt
252
+ > 6. **You authorize Vellum** with one click
253
+ >
254
+ > Takes about a minute after first-time setup. Ready?
242
255
 
243
- If the user declines, acknowledge and stop. No further confirmations are needed after this point.
256
+ If the user declines, acknowledge and stop.
244
257
 
245
- ## Step 2: Open Google Cloud Console and Sign In
258
+ ## CLI Step 2: Install Prerequisites
246
259
 
247
- **Goal:** The user is signed in and the Google Cloud Console dashboard is loaded.
260
+ Check for and install each prerequisite. If any installation fails (e.g., Homebrew not available, corporate restrictions), tell the user what went wrong and provide manual installation instructions.
248
261
 
249
- Navigate to `https://console.cloud.google.com/`.
262
+ ### gcloud
250
263
 
251
- Take a screenshot to check the page state:
264
+ ```bash
265
+ which gcloud
266
+ ```
252
267
 
253
- - **Sign-in page:** Tell the user: "Please sign in to your Google account in the Chrome window on the right side of your screen." Then auto-detect sign-in completion by polling with `browser_screenshot` every 5-10 seconds to check if the URL has moved away from `accounts.google.com` to `console.cloud.google.com`. Do NOT ask the user to "let me know when you're done"; detect it automatically. Once sign-in is detected, tell the user: "Signed in! Starting the automated setup now..."
254
- - **Already signed in:** Tell the user: "Already signed in, starting setup now..." and continue immediately.
255
- - **CAPTCHA:** The browser automation's built-in handoff will handle this. If it persists, tell the user: "There's a CAPTCHA in the browser, please complete it and I'll continue automatically."
268
+ If missing:
256
269
 
257
- **What you should see when done:** URL contains `console.cloud.google.com` and no sign-in overlay is visible.
270
+ ```bash
271
+ brew install google-cloud-sdk
272
+ ```
258
273
 
259
- ## Step 3: Create or Select a Project
274
+ After installation, verify it works:
260
275
 
261
- **Goal:** A GCP project named "Vellum Assistant" exists and is selected.
276
+ ```bash
277
+ gcloud --version
278
+ ```
262
279
 
263
- Tell the user: "Creating Google Cloud project..."
280
+ ### gws
264
281
 
265
- Navigate to `https://console.cloud.google.com/projectcreate`.
282
+ ```bash
283
+ which gws
284
+ ```
266
285
 
267
- Take a `browser_snapshot`. Find the project name input field (look for an element with label containing "Project name" or a text input near the top of the form). Type "Vellum Assistant" into it.
286
+ If missing:
268
287
 
269
- Look for a "Create" button in the snapshot and click it. Wait 10-15 seconds for project creation, then take a screenshot to check for:
270
- - **Success message** or redirect to the new project dashboard. Note the project ID from the URL or page content.
271
- - **"Project name already in use" error**: that's fine. Navigate to `https://console.cloud.google.com/cloud-resource-manager` to find and select the existing "Vellum Assistant" project. Use `browser_extract` to read the project ID from the page.
272
- - **Organization restriction or quota error**: tell the user what happened and ask them to resolve it.
288
+ ```bash
289
+ npm install -g @googleworkspace/cli
290
+ ```
273
291
 
274
- **What you should see when done:** The project selector in the top bar shows the project name, and you have the project ID (something like `vellum-assistant-12345`).
292
+ After installation, verify it works:
275
293
 
276
- Tell the user: "Project created!"
294
+ ```bash
295
+ gws --version
296
+ ```
277
297
 
278
- ## Step 4: Enable Gmail and Calendar APIs
298
+ ## CLI Step 3: Sign In to Google
279
299
 
280
- **Goal:** Both the Gmail API and Google Calendar API are enabled for the project.
300
+ Tell the user: "Opening your browser so you can sign in to Google..."
281
301
 
282
- Tell the user: "Enabling Gmail and Calendar APIs..."
302
+ ```bash
303
+ gcloud auth login
304
+ ```
283
305
 
284
- Navigate to each API's library page and enable it if not already enabled:
285
- 1. `https://console.cloud.google.com/apis/library/gmail.googleapis.com?project=PROJECT_ID`
286
- 2. `https://console.cloud.google.com/apis/library/calendar-json.googleapis.com?project=PROJECT_ID`
306
+ This opens the browser for Google sign-in. Wait for the command to complete — it prints the authenticated account email on success.
287
307
 
288
- For each page: take a `browser_snapshot`. Look for:
289
- - **"Enable" button**: click it, wait a few seconds, take another snapshot to confirm.
290
- - **"Manage" button or "API enabled" text**: the API is already enabled. Skip it.
308
+ If the user is already authenticated (`gcloud auth list` shows an active account), skip this step and tell the user: "Already signed in, continuing setup..."
291
309
 
292
- **What you should see when done:** Both API pages show "Manage" or "API enabled" status.
310
+ ## CLI Step 4: GCP Project Setup
293
311
 
294
- Tell the user: "APIs enabled!"
312
+ Tell the user: "Setting up your Google Cloud project, APIs, and credentials..."
295
313
 
296
- ## Step 5: Configure OAuth Consent Screen
314
+ ### Primary: `gws auth setup`
297
315
 
298
- **Goal:** An OAuth consent screen is configured with External user type, the required scopes, and the user added as a test user.
316
+ ```bash
317
+ gws auth setup
318
+ ```
299
319
 
300
- Tell the user: "Setting up OAuth consent screen. This is the longest step but it's fully automated..."
320
+ This command automates:
301
321
 
302
- Navigate to `https://console.cloud.google.com/apis/credentials/consent?project=PROJECT_ID`.
322
+ - GCP project creation (or selection of an existing one)
323
+ - OAuth consent screen configuration
324
+ - OAuth credential creation
303
325
 
304
- Take a `browser_snapshot` and `browser_screenshot`. Check the page state:
326
+ Wait for the command to complete. It may have interactive prompts — let them run in the terminal and the user can respond if needed.
305
327
 
306
- ### If the consent screen is already configured
328
+ If `gws auth setup` **succeeds**, note the **project ID** from the output and continue to **CLI Step 5**.
307
329
 
308
- You'll see a dashboard showing the app name ("Vellum Assistant" or similar) with an "Edit App" button. **Skip to Step 6.**
330
+ ### Fallback: `gcloud` CLI + browser automation
309
331
 
310
- ### If you see a user type selection (External / Internal)
332
+ If `gws auth setup` **fails** (common with personal Google accounts due to workspace-admin scope errors), use `gcloud` CLI and browser automation instead.
311
333
 
312
- Select **"External"** and click **Create** or **Get Started**.
334
+ **Step 4f-1: Create GCP project**
313
335
 
314
- ### Consent screen form (wizard or single-page)
336
+ Generate a unique suffix (4-6 random alphanumeric characters):
315
337
 
316
- Google Cloud uses either a multi-page wizard or a single-page form. Adapt to what you see:
338
+ ```bash
339
+ gcloud projects create vellum-assistant-SUFFIX --name="Vellum Assistant"
340
+ ```
317
341
 
318
- **App information section:**
319
- - **App name**: Type "Vellum Assistant" in the app name field.
320
- - **User support email**: This is typically a dropdown showing the signed-in user's email. Use `browser_snapshot` to find a `<select>` or clickable dropdown element near "User support email". Select the user's email.
321
- - **Developer contact email**: Type the user's email into this field. (Use the same email visible in the support email dropdown if you can read it, or use `browser_extract` to find the email shown on the page.)
322
- - Click **Save and Continue** if on a multi-page wizard.
342
+ If the project already exists, use it. Note the **project ID**.
323
343
 
324
- **Scopes section:**
325
- - Click **"Add or Remove Scopes"** (or similar button).
326
- - In the scope picker dialog, look for a text input labeled **"Manually add scopes"** or **"Filter"** at the bottom or top of the dialog.
327
- - Paste all 6 scopes at once as a comma-separated string into that input:
328
- ```
329
- https://www.googleapis.com/auth/gmail.readonly,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/gmail.send,https://www.googleapis.com/auth/calendar.readonly,https://www.googleapis.com/auth/calendar.events,https://www.googleapis.com/auth/userinfo.email
330
- ```
331
- - Click **"Add to Table"** or **"Update"** to confirm the scopes.
332
- - If no manual input is available, you'll need to search for and check each scope individually using the scope tree. Search for each scope URL in the filter box and check its checkbox.
333
- - Click **Save and Continue** (or **Update** then **Save and Continue**).
344
+ **Step 4f-2: Enable APIs**
334
345
 
335
- **Test users section:**
336
- - Click **"Add Users"** or similar.
337
- - Enter the user's email address.
338
- - Click **Add** then **Save and Continue**.
346
+ ```bash
347
+ gcloud services enable gmail.googleapis.com --project=PROJECT_ID
348
+ gcloud services enable calendar-json.googleapis.com --project=PROJECT_ID
349
+ gcloud services enable people.googleapis.com --project=PROJECT_ID
350
+ ```
339
351
 
340
- **Summary section:**
341
- - Click **"Back to Dashboard"** or **"Submit"**.
352
+ **Step 4f-3: Configure OAuth consent screen via browser**
342
353
 
343
- **What you should see when done:** A consent screen dashboard showing "Vellum Assistant" as the app name.
354
+ Navigate to `https://console.cloud.google.com/apis/credentials/consent?project=PROJECT_ID`.
344
355
 
345
- Tell the user: "Consent screen configured!"
356
+ Take a screenshot and snapshot, then:
346
357
 
347
- ## Step 6: Create OAuth Credentials and Capture Them
358
+ 1. Select **"External"** user type, click **Create**
359
+ 2. Fill in the app registration form:
360
+ - App name: **"Vellum Assistant"**
361
+ - User support email: select the authenticated email from the dropdown
362
+ - Developer contact email: type the same email
363
+ - Click **Save and Continue**
364
+ 3. On the Scopes page, click **Save and Continue** (scopes are not needed for test-mode apps)
365
+ 4. On the Test users page:
366
+ - Click **+ Add Users**
367
+ - Enter the authenticated email address
368
+ - Click **Add**, then **Save and Continue**
369
+ 5. On the Summary page, click **Back to Dashboard**
348
370
 
349
- **Goal:** A "Desktop app" OAuth client exists, and both its Client ID and Client Secret are stored in the vault.
371
+ **Verify:** Take a screenshot. The consent screen should show "Testing" publishing status.
350
372
 
351
- Tell the user: "Creating OAuth credentials..."
373
+ After the fallback completes, skip CLI Step 5 (APIs already enabled above) and CLI Step 5c (test user already added above) — continue directly to **CLI Step 6**.
352
374
 
353
- ### 6a: Create the credential
375
+ ## CLI Step 5: Enable Additional APIs
354
376
 
355
- Navigate to `https://console.cloud.google.com/apis/credentials?project=PROJECT_ID`.
377
+ `gws auth setup` enables the APIs it needs, but Vellum also requires the Calendar and People APIs. Enable them explicitly using the project ID from step 4:
356
378
 
357
- Take a `browser_snapshot`. Find and click a button labeled **"Create Credentials"** or **"+ Create Credentials"**. A dropdown menu should appear. Take another snapshot and click **"OAuth client ID"**.
379
+ ```bash
380
+ gcloud services enable calendar-json.googleapis.com --project=PROJECT_ID
381
+ gcloud services enable people.googleapis.com --project=PROJECT_ID
382
+ ```
358
383
 
359
- On the creation form (take a snapshot to see the fields):
360
- - **Application type**: Find the dropdown and select **"Desktop app"**. This may be a `<select>` element or a custom dropdown. Use the snapshot to identify it. You might need to click the dropdown first, then take another snapshot to see the options, then click "Desktop app".
361
- - **Name**: Type "Vellum Assistant" in the name field.
362
- - Do NOT add any redirect URIs. The desktop app flow doesn't need them.
384
+ If either command reports the API is already enabled, that's fine continue.
363
385
 
364
- Click **"Create"** to submit the form.
386
+ ## CLI Step 5c: Add Test User
365
387
 
366
- ### 6b: Capture credentials from the dialog
388
+ `gws auth setup` does not add test users to the consent screen, and there is no CLI/API for it. Use browser automation to add the authenticated email as a test user.
367
389
 
368
- After creation, a dialog will display the **Client ID** and **Client Secret**. This is the critical step.
390
+ Navigate to `https://console.cloud.google.com/apis/credentials/consent?project=PROJECT_ID`.
369
391
 
370
- **First**, try to auto-read the **Client ID** using `browser_extract`. The Client ID matches the pattern `*.apps.googleusercontent.com`. Search the extracted text for this pattern. If found, store it:
392
+ Take a screenshot and snapshot. Find the **Test users** section (you may need to click **Edit App** or navigate to the consent screen edit flow):
371
393
 
372
- ```
373
- credential_store store:
374
- service: "integration:gmail"
375
- field: "client_id"
376
- value: "<the Client ID extracted from the page>"
377
- ```
394
+ 1. Find and click the option to add test users (e.g., **+ Add Users** button)
395
+ 2. Enter the authenticated email address (from `gcloud auth list`)
396
+ 3. Click **Add** or **Save**
397
+
398
+ **Verify:** Take a screenshot confirming the email appears in the test users list.
399
+
400
+ If the user is already listed as a test user, skip this step.
401
+
402
+ ## CLI Step 6: Create OAuth Credentials via Browser
403
+
404
+ **Goal:** Create a Desktop OAuth client in GCP Console and capture both credentials.
405
+
406
+ Navigate to `https://console.cloud.google.com/apis/credentials?project=PROJECT_ID` (substitute the actual project ID from step 4).
407
+
408
+ Take a screenshot and snapshot to check the page state:
409
+
410
+ - **Sign-in page:** Tell the user: "Please sign in to your Google account in the browser." Then auto-detect sign-in completion by polling screenshots every 5-10 seconds. Once signed in, continue.
411
+ - **Already signed in / Credentials page loaded:** Continue immediately.
412
+
413
+ ### Step 6a: Create the OAuth Client
414
+
415
+ 1. Take a screenshot and snapshot. Find and click **+ Create Credentials**, then select **OAuth client ID**.
416
+ 2. On the creation form:
417
+ - Application type: Select **"Desktop app"**
418
+ - Name: **"Vellum Assistant"**
419
+ - Click **Create**
420
+ 3. **Verify:** Take a screenshot. A dialog should appear showing both the **Client ID** and **Client Secret**.
378
421
 
379
- If `browser_extract` fails to find the Client ID, prompt the user instead:
422
+ ### Step 6b: Extract Client ID
423
+
424
+ Use `browser_extract` to read the Client ID from the creation dialog. It looks like `123456789-xxxxx.apps.googleusercontent.com`.
425
+
426
+ Store it immediately:
380
427
 
381
428
  ```
382
- credential_store prompt:
429
+ credential_store store:
383
430
  service: "integration:gmail"
384
431
  field: "client_id"
385
- label: "Google OAuth Client ID"
386
- description: "Copy the Client ID from the dialog in the Chrome window and paste it here. It looks like 123456789-xxxxx.apps.googleusercontent.com"
387
- placeholder: "xxxxx.apps.googleusercontent.com"
432
+ value: "<the extracted Client ID>"
388
433
  ```
389
434
 
390
- **Then**, whether the Client ID was auto-read or prompted, tell the user:
435
+ ### Step 6c: Capture Client Secret via Secure Prompt
391
436
 
392
- > "Got the Client ID! Now I need the Client Secret. You can see it in the dialog in the Chrome window. It starts with `GOCSPX-`. Please copy it and paste it into the secure prompt below."
437
+ The Client Secret is visible in the same dialog. Do NOT attempt to read it from the screenshot use a secure prompt so the user copies it accurately.
393
438
 
394
- And present the secure prompt:
439
+ Tell the user: "Your OAuth credentials have been created! Please copy the **Client Secret** shown in the dialog and paste it into the secure prompt below."
395
440
 
396
441
  ```
397
442
  credential_store prompt:
398
443
  service: "integration:gmail"
399
444
  field: "client_secret"
400
445
  label: "Google OAuth Client Secret"
401
- description: "Copy the Client Secret from the Google Cloud Console dialog and paste it here."
446
+ description: "Copy the Client Secret from the dialog on screen. It starts with GOCSPX-"
402
447
  placeholder: "GOCSPX-..."
403
448
  ```
404
449
 
405
- Wait for the user to complete the prompt. **Do not take any other browser actions until the user has pasted the secret.** The dialog must stay open so they can see and copy the value.
406
-
407
- If the user has trouble locating the secret, take a `browser_screenshot` and describe where the secret field is on the screen, but do NOT attempt to read the secret value yourself. It must come from the user for accuracy.
408
-
409
- **What you should see when done:** `credential_store list` shows both `client_id` and `client_secret` for `integration:gmail`.
450
+ **CRITICAL do NOT dismiss the creation dialog before the user has copied the secret.** Wait for the secure prompt to be completed before clicking OK or navigating away.
410
451
 
411
- Tell the user: "Credentials stored securely!"
452
+ After the secret is stored, you may close the dialog.
412
453
 
413
- ## Step 7: OAuth2 Authorization
454
+ ## CLI Step 7: Authorize
414
455
 
415
- **Goal:** The user authorizes Vellum to access their Gmail and Calendar via OAuth.
416
-
417
- Tell the user: "Starting the authorization flow — a Google sign-in page will open in a few seconds. Just click 'Allow' when it appears."
456
+ Tell the user: "Starting the authorization flow a Google sign-in page will open. Just click 'Allow' when it appears."
418
457
 
419
458
  Use `credential_store` with:
420
459
 
@@ -429,15 +468,6 @@ This auto-reads client_id and client_secret from the secure store and auto-fills
429
468
 
430
469
  **Verify:** The `oauth2_connect` call returns a success message with the connected account email.
431
470
 
432
- ## Step 8: Done!
471
+ ## CLI Step 8: Done!
433
472
 
434
473
  Tell the user: "**Gmail and Calendar are connected!** You can now read, search, and send emails, plus view and manage your calendar. Try asking me to check your inbox or show your upcoming events!"
435
-
436
- ## Error Handling
437
-
438
- - **Page load failures:** Retry navigation once. If it still fails, tell the user and ask them to check their internet connection.
439
- - **Permission errors in GCP:** The user may need billing enabled or organization-level permissions. Explain clearly and ask them to resolve it.
440
- - **Consent screen already configured:** Don't overwrite. Skip to credential creation.
441
- - **Element not found:** Take a fresh `browser_snapshot` to re-assess. The GCP UI may have changed. Describe what you see and try alternative approaches. If stuck after 2 attempts, ask the user for guidance. They can see the Chrome window too.
442
- - **OAuth flow timeout or failure:** Offer to retry. The credentials are already stored, so reconnecting only requires re-running the authorization flow.
443
- - **Any unexpected state:** Take a `browser_screenshot`, describe what you see, and ask the user for guidance.
@@ -11,6 +11,7 @@ import type { MessagingProvider } from "../../../../messaging/provider.js";
11
11
  import {
12
12
  getConnectedProviders,
13
13
  getMessagingProvider,
14
+ isPlatformEnabled,
14
15
  } from "../../../../messaging/registry.js";
15
16
  import { withValidToken } from "../../../../security/token-manager.js";
16
17
  import type { ToolExecutionResult } from "../../../../tools/types.js";
@@ -32,7 +33,9 @@ export function err(message: string): ToolExecutionResult {
32
33
  export function resolveProvider(platformInput?: string): MessagingProvider {
33
34
  if (platformInput) return getMessagingProvider(platformInput);
34
35
 
35
- const connected = getConnectedProviders();
36
+ const connected = getConnectedProviders().filter((p) =>
37
+ isPlatformEnabled(p.id),
38
+ );
36
39
  if (connected.length === 1) return connected[0];
37
40
  if (connected.length === 0) {
38
41
  throw new Error(