@vellumai/assistant 0.4.46 → 0.4.49

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 (382) hide show
  1. package/ARCHITECTURE.md +7 -7
  2. package/README.md +2 -23
  3. package/docs/architecture/integrations.md +45 -41
  4. package/docs/architecture/keychain-broker.md +3 -3
  5. package/docs/architecture/security.md +5 -5
  6. package/docs/runbook-trusted-contacts.md +3 -8
  7. package/hook-templates/debug-prompt-logger/hook.json +1 -1
  8. package/hook-templates/debug-prompt-logger/run.sh +1 -3
  9. package/package.json +1 -1
  10. package/src/__tests__/actor-token-service.test.ts +0 -1
  11. package/src/__tests__/anthropic-provider.test.ts +156 -0
  12. package/src/__tests__/approval-cascade.test.ts +810 -0
  13. package/src/__tests__/approval-primitive.test.ts +0 -1
  14. package/src/__tests__/approval-routes-http.test.ts +2 -0
  15. package/src/__tests__/assistant-attachments.test.ts +12 -34
  16. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
  17. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
  18. package/src/__tests__/browser-fill-credential.test.ts +5 -2
  19. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  20. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
  21. package/src/__tests__/channel-guardian.test.ts +0 -2
  22. package/src/__tests__/channel-readiness-routes.test.ts +35 -25
  23. package/src/__tests__/channel-readiness-service.test.ts +10 -9
  24. package/src/__tests__/checker.test.ts +9 -29
  25. package/src/__tests__/cli.test.ts +23 -0
  26. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  27. package/src/__tests__/computer-use-tools.test.ts +2 -19
  28. package/src/__tests__/config-watcher.test.ts +0 -1
  29. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  30. package/src/__tests__/context-image-dimensions.test.ts +332 -0
  31. package/src/__tests__/context-token-estimator.test.ts +196 -13
  32. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  33. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  34. package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  36. package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
  37. package/src/__tests__/credential-broker-server-use.test.ts +22 -21
  38. package/src/__tests__/credential-broker.test.ts +2 -1
  39. package/src/__tests__/credential-metadata-store.test.ts +239 -26
  40. package/src/__tests__/credential-resolve.test.ts +5 -4
  41. package/src/__tests__/credential-security-e2e.test.ts +8 -8
  42. package/src/__tests__/credential-security-invariants.test.ts +111 -7
  43. package/src/__tests__/credential-vault-unit.test.ts +287 -54
  44. package/src/__tests__/credential-vault.test.ts +406 -12
  45. package/src/__tests__/credentials-cli.test.ts +82 -6
  46. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  47. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  48. package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
  49. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  50. package/src/__tests__/gemini-image-service.test.ts +75 -45
  51. package/src/__tests__/gemini-provider.test.ts +9 -6
  52. package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
  53. package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
  54. package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
  55. package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
  56. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  57. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  58. package/src/__tests__/guardian-grant-minting.test.ts +35 -0
  59. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  60. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  61. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
  62. package/src/__tests__/heartbeat-service.test.ts +0 -1
  63. package/src/__tests__/host-cu-proxy.test.ts +629 -0
  64. package/src/__tests__/host-shell-tool.test.ts +27 -15
  65. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  66. package/src/__tests__/ingress-url-consistency.test.ts +14 -21
  67. package/src/__tests__/integration-status.test.ts +38 -25
  68. package/src/__tests__/intent-routing.test.ts +0 -1
  69. package/src/__tests__/invite-routes-http.test.ts +10 -9
  70. package/src/__tests__/keychain-broker-client.test.ts +11 -43
  71. package/src/__tests__/managed-proxy-context.test.ts +5 -3
  72. package/src/__tests__/media-generate-image.test.ts +63 -2
  73. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
  74. package/src/__tests__/messaging-send-tool.test.ts +4 -6
  75. package/src/__tests__/notification-routing-intent.test.ts +0 -1
  76. package/src/__tests__/oauth-cli.test.ts +373 -14
  77. package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
  78. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  79. package/src/__tests__/oauth-store.test.ts +756 -0
  80. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  81. package/src/__tests__/provider-error-scenarios.test.ts +0 -1
  82. package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
  83. package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
  84. package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
  85. package/src/__tests__/public-ingress-urls.test.ts +15 -21
  86. package/src/__tests__/recording-handler.test.ts +3 -4
  87. package/src/__tests__/registry.test.ts +2 -2
  88. package/src/__tests__/runtime-events-sse.test.ts +55 -7
  89. package/src/__tests__/schedule-store.test.ts +0 -1
  90. package/src/__tests__/scheduler-recurrence.test.ts +0 -1
  91. package/src/__tests__/schema-transforms.test.ts +226 -0
  92. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  93. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  94. package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
  95. package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
  96. package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
  97. package/src/__tests__/secret-ingress-handler.test.ts +0 -1
  98. package/src/__tests__/secret-onetime-send.test.ts +5 -3
  99. package/src/__tests__/send-endpoint-busy.test.ts +21 -6
  100. package/src/__tests__/sequence-store.test.ts +0 -1
  101. package/src/__tests__/session-init.benchmark.test.ts +4 -5
  102. package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
  103. package/src/__tests__/skill-include-graph.test.ts +66 -0
  104. package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
  105. package/src/__tests__/skill-load-tool.test.ts +149 -1
  106. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  107. package/src/__tests__/skills-uninstall.test.ts +3 -3
  108. package/src/__tests__/skills.test.ts +3 -12
  109. package/src/__tests__/slack-channel-config.test.ts +76 -11
  110. package/src/__tests__/slack-share-routes.test.ts +17 -14
  111. package/src/__tests__/system-prompt.test.ts +0 -1
  112. package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
  113. package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
  114. package/src/__tests__/terminal-tools.test.ts +4 -3
  115. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  116. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  117. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  118. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  119. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
  120. package/src/__tests__/tool-executor.test.ts +0 -1
  121. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  122. package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
  123. package/src/__tests__/trust-store.test.ts +1 -22
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  126. package/src/__tests__/twilio-config.test.ts +2 -1
  127. package/src/__tests__/twilio-provider.test.ts +4 -2
  128. package/src/__tests__/twilio-routes.test.ts +5 -20
  129. package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
  130. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  131. package/src/agent/ax-tree-compaction.test.ts +235 -0
  132. package/src/agent/loop.ts +76 -130
  133. package/src/calls/call-domain.ts +8 -10
  134. package/src/calls/relay-server.ts +9 -13
  135. package/src/calls/twilio-config.ts +4 -8
  136. package/src/calls/twilio-provider.ts +2 -1
  137. package/src/calls/twilio-rest.ts +2 -1
  138. package/src/calls/twilio-routes.ts +1 -2
  139. package/src/calls/voice-ingress-preflight.ts +1 -1
  140. package/src/cli/commands/browser-relay.ts +46 -15
  141. package/src/cli/commands/completions.ts +0 -3
  142. package/src/cli/commands/credentials.ts +110 -23
  143. package/src/cli/commands/oauth/apps.ts +255 -0
  144. package/src/cli/commands/oauth/connections.ts +299 -0
  145. package/src/cli/commands/oauth/index.ts +52 -0
  146. package/src/cli/commands/oauth/providers.ts +242 -0
  147. package/src/cli/commands/skills.ts +4 -338
  148. package/src/cli/program.ts +1 -5
  149. package/src/cli/reference.ts +1 -3
  150. package/src/cli.ts +3 -2
  151. package/src/config/assistant-feature-flags.ts +0 -3
  152. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  153. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
  154. package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
  155. package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
  156. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
  157. package/src/config/bundled-skills/gmail/SKILL.md +4 -4
  158. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
  159. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
  160. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
  161. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
  162. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
  163. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
  164. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
  165. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
  166. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
  167. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
  168. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
  169. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
  170. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
  171. package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
  172. package/src/config/bundled-skills/google-calendar/calendar-client.ts +90 -44
  173. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
  174. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
  175. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
  176. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
  177. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
  178. package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
  179. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
  180. package/src/config/bundled-skills/messaging/SKILL.md +6 -6
  181. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
  182. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
  183. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
  184. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
  185. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
  186. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
  187. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
  188. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
  189. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
  190. package/src/config/bundled-skills/messaging/tools/shared.ts +12 -15
  191. package/src/config/bundled-skills/settings/SKILL.md +1 -1
  192. package/src/config/bundled-skills/settings/TOOLS.json +2 -8
  193. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
  194. package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
  195. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
  196. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
  197. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
  198. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
  199. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
  200. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
  201. package/src/config/env-registry.ts +14 -83
  202. package/src/config/env.ts +11 -50
  203. package/src/config/feature-flag-registry.json +16 -16
  204. package/src/config/schema.ts +3 -1
  205. package/src/config/skills.ts +21 -2
  206. package/src/context/image-dimensions.ts +229 -0
  207. package/src/context/token-estimator.ts +75 -12
  208. package/src/context/window-manager.ts +49 -10
  209. package/src/daemon/assistant-attachments.ts +1 -13
  210. package/src/daemon/guardian-action-generators.ts +4 -5
  211. package/src/daemon/handlers/config-ingress.ts +8 -33
  212. package/src/daemon/handlers/config-slack-channel.ts +76 -56
  213. package/src/daemon/handlers/config-telegram.ts +53 -24
  214. package/src/daemon/handlers/sessions.ts +10 -24
  215. package/src/daemon/handlers/shared.ts +0 -130
  216. package/src/daemon/host-cu-proxy.ts +401 -0
  217. package/src/daemon/lifecycle.ts +39 -63
  218. package/src/daemon/message-protocol.ts +3 -0
  219. package/src/daemon/message-types/computer-use.ts +2 -119
  220. package/src/daemon/message-types/host-cu.ts +19 -0
  221. package/src/daemon/message-types/integrations.ts +1 -0
  222. package/src/daemon/message-types/messages.ts +3 -0
  223. package/src/daemon/server.ts +14 -21
  224. package/src/daemon/session-agent-loop-handlers.ts +2 -0
  225. package/src/daemon/session-attachments.ts +1 -2
  226. package/src/daemon/session-messaging.ts +3 -1
  227. package/src/daemon/session-slash.ts +1 -1
  228. package/src/daemon/session-surfaces.ts +40 -28
  229. package/src/daemon/session-tool-setup.ts +20 -11
  230. package/src/daemon/session.ts +139 -16
  231. package/src/daemon/tool-side-effects.ts +2 -8
  232. package/src/daemon/watch-handler.ts +2 -2
  233. package/src/email/providers/index.ts +2 -1
  234. package/src/events/tool-metrics-listener.ts +2 -2
  235. package/src/hooks/manager.ts +1 -4
  236. package/src/inbound/public-ingress-urls.ts +7 -7
  237. package/src/instrument.ts +15 -1
  238. package/src/logfire.ts +16 -5
  239. package/src/media/app-icon-generator.ts +30 -4
  240. package/src/media/avatar-router.ts +26 -3
  241. package/src/media/gemini-image-service.ts +28 -2
  242. package/src/memory/conversation-key-store.ts +21 -0
  243. package/src/memory/db-init.ts +4 -0
  244. package/src/memory/guardian-action-store.ts +1 -1
  245. package/src/memory/migrations/149-oauth-tables.ts +60 -0
  246. package/src/memory/migrations/index.ts +1 -0
  247. package/src/memory/schema/guardian.ts +1 -1
  248. package/src/memory/schema/index.ts +1 -0
  249. package/src/memory/schema/oauth.ts +65 -0
  250. package/src/messaging/provider.ts +19 -13
  251. package/src/messaging/providers/gmail/adapter.ts +40 -23
  252. package/src/messaging/providers/gmail/client.ts +283 -122
  253. package/src/messaging/providers/gmail/people-client.ts +32 -24
  254. package/src/messaging/providers/slack/adapter.ts +29 -19
  255. package/src/messaging/providers/slack/client.ts +265 -78
  256. package/src/messaging/providers/telegram-bot/adapter.ts +19 -18
  257. package/src/messaging/providers/whatsapp/adapter.ts +17 -11
  258. package/src/messaging/registry.ts +2 -31
  259. package/src/notifications/copy-composer.ts +0 -5
  260. package/src/notifications/signal.ts +4 -5
  261. package/src/oauth/byo-connection.test.ts +537 -0
  262. package/src/oauth/byo-connection.ts +128 -0
  263. package/src/oauth/connect-orchestrator.ts +139 -56
  264. package/src/oauth/connect-types.ts +17 -23
  265. package/src/oauth/connection-resolver.ts +58 -0
  266. package/src/oauth/connection.ts +38 -0
  267. package/src/oauth/manual-token-connection.ts +104 -0
  268. package/src/oauth/oauth-store.ts +496 -0
  269. package/src/oauth/platform-connection.test.ts +192 -0
  270. package/src/oauth/platform-connection.ts +111 -0
  271. package/src/oauth/provider-behaviors.ts +124 -0
  272. package/src/oauth/scope-policy.ts +9 -2
  273. package/src/oauth/seed-providers.ts +161 -0
  274. package/src/oauth/token-persistence.ts +74 -78
  275. package/src/permissions/checker.ts +8 -4
  276. package/src/permissions/defaults.ts +0 -1
  277. package/src/permissions/prompter.ts +10 -1
  278. package/src/permissions/trust-store.ts +13 -0
  279. package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
  280. package/src/prompts/system-prompt.ts +70 -45
  281. package/src/providers/anthropic/client.ts +133 -24
  282. package/src/providers/gemini/client.ts +15 -6
  283. package/src/providers/managed-proxy/constants.ts +2 -2
  284. package/src/providers/managed-proxy/context.ts +5 -1
  285. package/src/providers/ratelimit.ts +17 -0
  286. package/src/providers/registry.ts +2 -2
  287. package/src/providers/retry.ts +1 -27
  288. package/src/runtime/AGENTS.md +17 -0
  289. package/src/runtime/auth/route-policy.ts +0 -3
  290. package/src/runtime/channel-invite-transports/telegram.ts +2 -1
  291. package/src/runtime/channel-readiness-service.ts +168 -195
  292. package/src/runtime/channel-readiness-types.ts +4 -0
  293. package/src/runtime/channel-reply-delivery.ts +0 -40
  294. package/src/runtime/gateway-client.ts +0 -7
  295. package/src/runtime/guardian-action-conversation-turn.ts +1 -3
  296. package/src/runtime/guardian-action-followup-executor.ts +1 -1
  297. package/src/runtime/guardian-action-message-composer.ts +3 -23
  298. package/src/runtime/http-server.ts +17 -10
  299. package/src/runtime/http-types.ts +2 -3
  300. package/src/runtime/middleware/rate-limiter.ts +74 -20
  301. package/src/runtime/middleware/twilio-validation.ts +1 -11
  302. package/src/runtime/pending-interactions.ts +14 -12
  303. package/src/runtime/routes/channel-delivery-routes.ts +0 -1
  304. package/src/runtime/routes/channel-readiness-routes.ts +2 -0
  305. package/src/runtime/routes/conversation-routes.ts +73 -19
  306. package/src/runtime/routes/diagnostics-routes.ts +11 -9
  307. package/src/runtime/routes/events-routes.ts +21 -11
  308. package/src/runtime/routes/guardian-approval-interception.ts +20 -5
  309. package/src/runtime/routes/host-cu-routes.ts +97 -0
  310. package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
  311. package/src/runtime/routes/integrations/slack/share.ts +6 -6
  312. package/src/runtime/routes/integrations/twilio.ts +6 -5
  313. package/src/runtime/routes/log-export-routes.ts +126 -8
  314. package/src/runtime/routes/secret-routes.ts +3 -2
  315. package/src/runtime/routes/settings-routes.ts +113 -48
  316. package/src/runtime/routes/surface-action-routes.ts +1 -1
  317. package/src/runtime/routes/watch-routes.ts +128 -0
  318. package/src/schedule/integration-status.ts +10 -8
  319. package/src/security/credential-key.ts +14 -0
  320. package/src/security/keychain-broker-client.ts +5 -6
  321. package/src/security/oauth2.ts +1 -1
  322. package/src/security/token-manager.ts +145 -43
  323. package/src/skills/catalog-install.ts +358 -0
  324. package/src/skills/include-graph.ts +32 -0
  325. package/src/telegram/bot-username.ts +2 -3
  326. package/src/tools/apps/definitions.ts +0 -5
  327. package/src/tools/assets/materialize.ts +0 -5
  328. package/src/tools/assets/search.ts +0 -5
  329. package/src/tools/browser/headless-browser.ts +1 -67
  330. package/src/tools/browser/network-recorder.ts +1 -1
  331. package/src/tools/browser/network-recording-types.ts +1 -1
  332. package/src/tools/claude-code/claude-code.ts +0 -5
  333. package/src/tools/computer-use/definitions.ts +46 -11
  334. package/src/tools/computer-use/registry.ts +4 -5
  335. package/src/tools/credentials/broker.ts +5 -4
  336. package/src/tools/credentials/metadata-store.ts +22 -74
  337. package/src/tools/credentials/resolve.ts +2 -1
  338. package/src/tools/credentials/vault.ts +139 -151
  339. package/src/tools/filesystem/edit.ts +1 -6
  340. package/src/tools/filesystem/read.ts +0 -5
  341. package/src/tools/filesystem/write.ts +1 -6
  342. package/src/tools/host-filesystem/edit.ts +1 -6
  343. package/src/tools/host-filesystem/read.ts +1 -6
  344. package/src/tools/host-filesystem/write.ts +1 -6
  345. package/src/tools/mcp/mcp-tool-factory.ts +18 -1
  346. package/src/tools/memory/definitions.ts +0 -5
  347. package/src/tools/network/web-fetch.ts +0 -5
  348. package/src/tools/network/web-search.ts +0 -5
  349. package/src/tools/registry.ts +2 -7
  350. package/src/tools/schema-transforms.ts +99 -0
  351. package/src/tools/skills/load.ts +62 -8
  352. package/src/tools/swarm/delegate.ts +0 -5
  353. package/src/tools/system/avatar-generator.ts +0 -5
  354. package/src/tools/ui-surface/definitions.ts +0 -15
  355. package/src/tools/watch/screen-watch.ts +0 -5
  356. package/src/tools/watch/watch-state.ts +0 -12
  357. package/src/util/logger.ts +7 -41
  358. package/src/util/platform.ts +9 -28
  359. package/src/version.ts +10 -0
  360. package/src/watcher/providers/github.ts +51 -52
  361. package/src/watcher/providers/gmail.ts +88 -80
  362. package/src/watcher/providers/google-calendar.ts +94 -86
  363. package/src/watcher/providers/linear.ts +87 -93
  364. package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
  365. package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
  366. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
  367. package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
  368. package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
  369. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
  370. package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
  371. package/src/cli/commands/dev.ts +0 -129
  372. package/src/cli/commands/map.ts +0 -391
  373. package/src/cli/commands/oauth.ts +0 -77
  374. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
  375. package/src/daemon/computer-use-session.ts +0 -1020
  376. package/src/daemon/ride-shotgun-handler.ts +0 -567
  377. package/src/oauth/provider-profiles.ts +0 -192
  378. package/src/prompts/computer-use-prompt.ts +0 -98
  379. package/src/runtime/routes/computer-use-routes.ts +0 -641
  380. package/src/runtime/telegram-streaming-delivery.test.ts +0 -597
  381. package/src/runtime/telegram-streaming-delivery.ts +0 -383
  382. package/src/tools/computer-use/request-computer-control.ts +0 -61
@@ -1,3 +1,7 @@
1
+ import type {
2
+ OAuthConnection,
3
+ OAuthConnectionResponse,
4
+ } from "../../../oauth/connection.js";
1
5
  import type {
2
6
  GmailAttachment,
3
7
  GmailDraft,
@@ -15,7 +19,6 @@ import type {
15
19
  GmailVacationSettings,
16
20
  } from "./types.js";
17
21
 
18
- const GMAIL_API_BASE = "https://gmail.googleapis.com/gmail/v1/users/me";
19
22
  const GMAIL_BATCH_URL = "https://www.googleapis.com/batch/gmail/v1";
20
23
 
21
24
  /** Max sub-requests per batch HTTP call (Gmail API limit) */
@@ -36,6 +39,7 @@ export class GmailApiError extends Error {
36
39
 
37
40
  const MAX_RETRIES = 3;
38
41
  const INITIAL_BACKOFF_MS = 1000;
42
+ /** Timeout for batch API calls that bypass OAuthConnection.request() (which has its own 30s timeout). */
39
43
  const REQUEST_TIMEOUT_MS = 30_000;
40
44
 
41
45
  function isRetryable(status: number): boolean {
@@ -54,53 +58,115 @@ interface GmailRequestOptions extends RequestInit {
54
58
  retryable?: boolean;
55
59
  }
56
60
 
61
+ /**
62
+ * Extract non-Authorization headers from request options for use with OAuthConnection.
63
+ */
64
+ function extractNonAuthHeaders(
65
+ options?: GmailRequestOptions,
66
+ ): Record<string, string> | undefined {
67
+ if (!options?.headers) return undefined;
68
+ const raw = options.headers;
69
+ const result: Record<string, string> = {};
70
+ if (raw instanceof Headers) {
71
+ raw.forEach((v, k) => {
72
+ if (k.toLowerCase() !== "authorization") result[k] = v;
73
+ });
74
+ } else if (Array.isArray(raw)) {
75
+ for (const [k, v] of raw) {
76
+ if (k.toLowerCase() !== "authorization") result[k] = v;
77
+ }
78
+ } else {
79
+ for (const [k, v] of Object.entries(raw)) {
80
+ if (k.toLowerCase() !== "authorization" && v !== undefined) result[k] = v;
81
+ }
82
+ }
83
+ return Object.keys(result).length > 0 ? result : undefined;
84
+ }
85
+
86
+ /**
87
+ * Convert URLSearchParams to a query record, collapsing multi-valued keys into arrays.
88
+ */
89
+ function paramsToQuery(
90
+ params: URLSearchParams,
91
+ ): Record<string, string | string[]> {
92
+ const result: Record<string, string | string[]> = {};
93
+ for (const key of new Set(params.keys())) {
94
+ const values = params.getAll(key);
95
+ result[key] = values.length === 1 ? values[0] : values;
96
+ }
97
+ return result;
98
+ }
99
+
100
+ /**
101
+ * Extract the JSON body from request options for use with OAuthConnection.
102
+ */
103
+ function extractBody(options?: GmailRequestOptions): unknown | undefined {
104
+ if (!options?.body) return undefined;
105
+ if (typeof options.body === "string") {
106
+ try {
107
+ return JSON.parse(options.body);
108
+ } catch {
109
+ return options.body;
110
+ }
111
+ }
112
+ return options.body;
113
+ }
114
+
57
115
  async function request<T>(
58
- token: string,
116
+ connection: OAuthConnection,
59
117
  path: string,
60
118
  options?: GmailRequestOptions,
119
+ query?: Record<string, string | string[]>,
61
120
  ): Promise<T> {
62
- const url = `${GMAIL_API_BASE}${path}`;
63
121
  const canRetry = options?.retryable ?? isIdempotent(options);
122
+ const method = (options?.method ?? "GET").toUpperCase();
64
123
 
65
124
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
66
- const resp = await fetch(url, {
67
- ...options,
68
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
69
- headers: {
70
- Authorization: `Bearer ${token}`,
71
- "Content-Type": "application/json",
72
- ...options?.headers,
73
- },
74
- });
125
+ let resp: OAuthConnectionResponse;
126
+ try {
127
+ resp = await connection.request({
128
+ method,
129
+ path,
130
+ query,
131
+ headers: {
132
+ "Content-Type": "application/json",
133
+ ...extractNonAuthHeaders(options),
134
+ },
135
+ body: extractBody(options),
136
+ });
137
+ } catch (err) {
138
+ // Network-level errors from connection.request() are not retryable
139
+ throw err;
140
+ }
75
141
 
76
- if (!resp.ok) {
142
+ if (resp.status < 200 || resp.status >= 300) {
77
143
  if (canRetry && isRetryable(resp.status) && attempt < MAX_RETRIES) {
78
- const retryAfter = resp.headers.get("retry-after");
144
+ const retryAfter =
145
+ resp.headers["retry-after"] ?? resp.headers["Retry-After"];
79
146
  const delayMs = retryAfter
80
147
  ? parseInt(retryAfter, 10) * 1000
81
148
  : INITIAL_BACKOFF_MS * Math.pow(2, attempt);
82
149
  await new Promise((resolve) => setTimeout(resolve, delayMs));
83
150
  continue;
84
151
  }
85
- const body = await resp.text().catch(() => "");
152
+ const bodyStr =
153
+ typeof resp.body === "string"
154
+ ? resp.body
155
+ : JSON.stringify(resp.body ?? "");
86
156
  throw new GmailApiError(
87
157
  resp.status,
88
- resp.statusText,
89
- `Gmail API ${resp.status}: ${body}`,
158
+ "",
159
+ `Gmail API ${resp.status}: ${bodyStr}`,
90
160
  );
91
161
  }
92
162
 
93
- // Some endpoints (e.g. batchModify) return empty success responses
94
- const contentLength = resp.headers.get("content-length");
95
- if (resp.status === 204 || contentLength === "0") {
163
+ // Success body is already parsed by connection.request()
164
+ if (resp.status === 204 || resp.body === undefined) {
96
165
  return undefined as T;
97
166
  }
98
- const text = await resp.text();
99
- if (!text) return undefined as T;
100
- return JSON.parse(text) as T;
167
+ return resp.body as T;
101
168
  }
102
169
 
103
- // Unreachable — the loop always returns or throws — but TypeScript needs this
104
170
  throw new Error(
105
171
  "Unreachable: retry loop exited without returning or throwing",
106
172
  );
@@ -108,7 +174,7 @@ async function request<T>(
108
174
 
109
175
  /** List messages matching a query. */
110
176
  export async function listMessages(
111
- token: string,
177
+ connection: OAuthConnection,
112
178
  query?: string,
113
179
  maxResults = 20,
114
180
  pageToken?: string,
@@ -121,12 +187,17 @@ export async function listMessages(
121
187
  if (labelIds) {
122
188
  for (const id of labelIds) params.append("labelIds", id);
123
189
  }
124
- return request<GmailMessageListResponse>(token, `/messages?${params}`);
190
+ return request<GmailMessageListResponse>(
191
+ connection,
192
+ "/messages",
193
+ undefined,
194
+ paramsToQuery(params),
195
+ );
125
196
  }
126
197
 
127
198
  /** Get a single message by ID. */
128
199
  export async function getMessage(
129
- token: string,
200
+ connection: OAuthConnection,
130
201
  messageId: string,
131
202
  format: GmailMessageFormat = "full",
132
203
  metadataHeaders?: string[],
@@ -137,7 +208,12 @@ export async function getMessage(
137
208
  for (const h of metadataHeaders) params.append("metadataHeaders", h);
138
209
  }
139
210
  if (fields) params.set("fields", fields);
140
- return request<GmailMessage>(token, `/messages/${messageId}?${params}`);
211
+ return request<GmailMessage>(
212
+ connection,
213
+ `/messages/${messageId}`,
214
+ undefined,
215
+ paramsToQuery(params),
216
+ );
141
217
  }
142
218
 
143
219
  /**
@@ -175,7 +251,7 @@ function parseSubResponse(
175
251
  * Returns successfully parsed messages and a list of IDs that failed (for individual retry).
176
252
  */
177
253
  async function executeBatchCall(
178
- token: string,
254
+ connection: OAuthConnection,
179
255
  messageIds: string[],
180
256
  format: GmailMessageFormat,
181
257
  metadataHeaders: string[] | undefined,
@@ -203,79 +279,126 @@ async function executeBatchCall(
203
279
  );
204
280
  const body = parts.join("") + `--${boundary}--\r\n`;
205
281
 
206
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
207
- const resp = await fetch(GMAIL_BATCH_URL, {
208
- method: "POST",
209
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS * 2),
210
- headers: {
211
- Authorization: `Bearer ${token}`,
212
- "Content-Type": `multipart/mixed; boundary=${boundary}`,
213
- },
214
- body,
215
- });
216
-
217
- if (!resp.ok) {
218
- if (isRetryable(resp.status) && attempt < MAX_RETRIES) {
219
- const retryAfter = resp.headers.get("retry-after");
220
- const delayMs = retryAfter
221
- ? parseInt(retryAfter, 10) * 1000
222
- : INITIAL_BACKOFF_MS * Math.pow(2, attempt);
223
- await new Promise((r) => setTimeout(r, delayMs));
224
- continue;
282
+ const doBatchFetch = async (token: string) => {
283
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
284
+ const resp = await fetch(GMAIL_BATCH_URL, {
285
+ method: "POST",
286
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS * 2),
287
+ headers: {
288
+ Authorization: `Bearer ${token}`,
289
+ "Content-Type": `multipart/mixed; boundary=${boundary}`,
290
+ },
291
+ body,
292
+ });
293
+
294
+ if (!resp.ok) {
295
+ if (isRetryable(resp.status) && attempt < MAX_RETRIES) {
296
+ const retryAfter = resp.headers.get("retry-after");
297
+ const delayMs = retryAfter
298
+ ? parseInt(retryAfter, 10) * 1000
299
+ : INITIAL_BACKOFF_MS * Math.pow(2, attempt);
300
+ await new Promise((r) => setTimeout(r, delayMs));
301
+ continue;
302
+ }
303
+ const errBody = await resp.text().catch(() => "");
304
+ throw new GmailApiError(
305
+ resp.status,
306
+ resp.statusText,
307
+ `Gmail batch API ${resp.status}: ${errBody}`,
308
+ );
225
309
  }
226
- const errBody = await resp.text().catch(() => "");
227
- throw new GmailApiError(
228
- resp.status,
229
- resp.statusText,
230
- `Gmail batch API ${resp.status}: ${errBody}`,
231
- );
232
- }
233
-
234
- const contentType = resp.headers.get("content-type") ?? "";
235
- const responseText = await resp.text();
236
-
237
- const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^\s;]+))/);
238
- const respBoundary = boundaryMatch?.[1] ?? boundaryMatch?.[2];
239
- if (!respBoundary)
240
- throw new Error("Missing boundary in Gmail batch response");
241
-
242
- const respParts = responseText.split(`--${respBoundary}`);
243
- const messages: Array<{ index: number; msg: GmailMessage }> = [];
244
- const failedIds: Array<{ index: number; id: string }> = [];
245
310
 
246
- for (const rp of respParts) {
247
- const parsed = parseSubResponse(rp);
248
- if (!parsed) continue;
311
+ const contentType = resp.headers.get("content-type") ?? "";
312
+ const responseText = await resp.text();
249
313
 
250
- if (parsed.status >= 200 && parsed.status < 300 && parsed.json) {
251
- try {
252
- messages.push({
314
+ const boundaryMatch = contentType.match(
315
+ /boundary=(?:"([^"]+)"|([^\s;]+))/,
316
+ );
317
+ const respBoundary = boundaryMatch?.[1] ?? boundaryMatch?.[2];
318
+ if (!respBoundary)
319
+ throw new Error("Missing boundary in Gmail batch response");
320
+
321
+ const respParts = responseText.split(`--${respBoundary}`);
322
+ const messages: Array<{ index: number; msg: GmailMessage }> = [];
323
+ const failedIds: Array<{ index: number; id: string }> = [];
324
+
325
+ for (const rp of respParts) {
326
+ const parsed = parseSubResponse(rp);
327
+ if (!parsed) continue;
328
+
329
+ if (parsed.status >= 200 && parsed.status < 300 && parsed.json) {
330
+ try {
331
+ messages.push({
332
+ index: parsed.index,
333
+ msg: JSON.parse(parsed.json) as GmailMessage,
334
+ });
335
+ } catch {
336
+ failedIds.push({
337
+ index: parsed.index,
338
+ id: messageIds[parsed.index],
339
+ });
340
+ }
341
+ } else {
342
+ failedIds.push({
253
343
  index: parsed.index,
254
- msg: JSON.parse(parsed.json) as GmailMessage,
344
+ id: messageIds[parsed.index],
255
345
  });
256
- } catch {
257
- failedIds.push({ index: parsed.index, id: messageIds[parsed.index] });
258
346
  }
259
- } else {
260
- failedIds.push({ index: parsed.index, id: messageIds[parsed.index] });
261
347
  }
348
+
349
+ return { messages, failedIds };
262
350
  }
263
351
 
264
- return { messages, failedIds };
265
- }
352
+ throw new Error(
353
+ "Unreachable: batch retry loop exited without returning or throwing",
354
+ );
355
+ };
266
356
 
267
- throw new Error(
268
- "Unreachable: batch retry loop exited without returning or throwing",
269
- );
357
+ // Use withToken to get raw token for batch endpoint
358
+ return connection.withToken(doBatchFetch);
359
+ }
360
+
361
+ /** Max concurrent individual getMessage requests (matches batch concurrency) */
362
+ const INDIVIDUAL_CONCURRENCY = BATCH_CONCURRENCY;
363
+
364
+ /**
365
+ * Fetch all messages individually using getMessage (no batch endpoint).
366
+ * Used as a fallback when the batch API is unavailable (e.g. platform connections
367
+ * that cannot expose raw tokens for the multipart batch endpoint).
368
+ *
369
+ * Processes messages in waves of INDIVIDUAL_CONCURRENCY to avoid unbounded
370
+ * parallelism that would trigger 429s on high-volume paths like senderDigest.
371
+ */
372
+ async function fetchMessagesIndividually(
373
+ connection: OAuthConnection,
374
+ messageIds: string[],
375
+ format: GmailMessageFormat,
376
+ metadataHeaders?: string[],
377
+ fields?: string,
378
+ ): Promise<GmailMessage[]> {
379
+ const results: GmailMessage[] = [];
380
+ for (let i = 0; i < messageIds.length; i += INDIVIDUAL_CONCURRENCY) {
381
+ const wave = messageIds.slice(i, i + INDIVIDUAL_CONCURRENCY);
382
+ const waveResults = await Promise.all(
383
+ wave.map((id) =>
384
+ getMessage(connection, id, format, metadataHeaders, fields),
385
+ ),
386
+ );
387
+ results.push(...waveResults);
388
+ }
389
+ return results;
270
390
  }
271
391
 
272
392
  /**
273
393
  * Get multiple messages using Gmail's batch HTTP endpoint.
274
394
  * Packs up to 100 sub-requests per HTTP call and runs up to BATCH_CONCURRENCY calls in parallel.
275
395
  * Falls back to individual getMessage for any sub-requests that fail within a batch.
396
+ *
397
+ * For connections that do not support raw token access (e.g. platform-managed connections),
398
+ * falls back to fetching each message individually via connection.request().
276
399
  */
277
400
  export async function batchGetMessages(
278
- token: string,
401
+ connection: OAuthConnection,
279
402
  messageIds: string[],
280
403
  format: GmailMessageFormat = "full",
281
404
  metadataHeaders?: string[],
@@ -283,13 +406,39 @@ export async function batchGetMessages(
283
406
  ): Promise<GmailMessage[]> {
284
407
  if (messageIds.length === 0) return [];
285
408
 
286
- // Single message just use getMessage directly
409
+ // Single message -- just use getMessage directly
287
410
  if (messageIds.length === 1) {
288
411
  return [
289
- await getMessage(token, messageIds[0], format, metadataHeaders, fields),
412
+ await getMessage(
413
+ connection,
414
+ messageIds[0],
415
+ format,
416
+ metadataHeaders,
417
+ fields,
418
+ ),
290
419
  ];
291
420
  }
292
421
 
422
+ // Try batch API first; fall back to individual fetches if withToken is unavailable
423
+ // (e.g. platform-managed connections where raw tokens cannot be exposed).
424
+ let useBatch = true;
425
+ try {
426
+ // Probe withToken availability with a no-op call
427
+ await connection.withToken(async (token) => token);
428
+ } catch {
429
+ useBatch = false;
430
+ }
431
+
432
+ if (!useBatch) {
433
+ return fetchMessagesIndividually(
434
+ connection,
435
+ messageIds,
436
+ format,
437
+ metadataHeaders,
438
+ fields,
439
+ );
440
+ }
441
+
293
442
  const results = new Array<GmailMessage | undefined>(messageIds.length).fill(
294
443
  undefined,
295
444
  );
@@ -307,7 +456,13 @@ export async function batchGetMessages(
307
456
  const wave = chunks.slice(i, i + BATCH_CONCURRENCY);
308
457
  const waveResults = await Promise.all(
309
458
  wave.map((chunk) =>
310
- executeBatchCall(token, chunk.ids, format, metadataHeaders, fields),
459
+ executeBatchCall(
460
+ connection,
461
+ chunk.ids,
462
+ format,
463
+ metadataHeaders,
464
+ fields,
465
+ ),
311
466
  ),
312
467
  );
313
468
 
@@ -324,7 +479,7 @@ export async function batchGetMessages(
324
479
  if (failedIds.length > 0) {
325
480
  const retried = await Promise.all(
326
481
  failedIds.map(({ id }) =>
327
- getMessage(token, id, format, metadataHeaders, fields),
482
+ getMessage(connection, id, format, metadataHeaders, fields),
328
483
  ),
329
484
  );
330
485
  for (let r = 0; r < failedIds.length; r++) {
@@ -339,11 +494,11 @@ export async function batchGetMessages(
339
494
 
340
495
  /** Modify labels on a single message. */
341
496
  export async function modifyMessage(
342
- token: string,
497
+ connection: OAuthConnection,
343
498
  messageId: string,
344
499
  modifications: GmailModifyRequest,
345
500
  ): Promise<GmailMessage> {
346
- return request<GmailMessage>(token, `/messages/${messageId}/modify`, {
501
+ return request<GmailMessage>(connection, `/messages/${messageId}/modify`, {
347
502
  method: "POST",
348
503
  body: JSON.stringify(modifications),
349
504
  retryable: true,
@@ -352,11 +507,11 @@ export async function modifyMessage(
352
507
 
353
508
  /** Batch modify labels on multiple messages. */
354
509
  export async function batchModifyMessages(
355
- token: string,
510
+ connection: OAuthConnection,
356
511
  messageIds: string[],
357
512
  modifications: GmailModifyRequest,
358
513
  ): Promise<void> {
359
- await request<void>(token, "/messages/batchModify", {
514
+ await request<void>(connection, "/messages/batchModify", {
360
515
  method: "POST",
361
516
  body: JSON.stringify({ ids: messageIds, ...modifications }),
362
517
  retryable: true,
@@ -365,24 +520,26 @@ export async function batchModifyMessages(
365
520
 
366
521
  /** Move a message to trash. */
367
522
  export async function trashMessage(
368
- token: string,
523
+ connection: OAuthConnection,
369
524
  messageId: string,
370
525
  ): Promise<GmailMessage> {
371
- return request<GmailMessage>(token, `/messages/${messageId}/trash`, {
526
+ return request<GmailMessage>(connection, `/messages/${messageId}/trash`, {
372
527
  method: "POST",
373
528
  retryable: true,
374
529
  });
375
530
  }
376
531
 
377
532
  /** List all labels. */
378
- export async function listLabels(token: string): Promise<GmailLabel[]> {
379
- const resp = await request<GmailLabelsListResponse>(token, "/labels");
533
+ export async function listLabels(
534
+ connection: OAuthConnection,
535
+ ): Promise<GmailLabel[]> {
536
+ const resp = await request<GmailLabelsListResponse>(connection, "/labels");
380
537
  return resp.labels ?? [];
381
538
  }
382
539
 
383
540
  /** Create a draft. */
384
541
  export async function createDraft(
385
- token: string,
542
+ connection: OAuthConnection,
386
543
  to: string,
387
544
  subject: string,
388
545
  body: string,
@@ -409,7 +566,7 @@ export async function createDraft(
409
566
  .replace(/=+$/, "");
410
567
  const message: Record<string, unknown> = { raw };
411
568
  if (threadId) message.threadId = threadId;
412
- return request<GmailDraft>(token, "/drafts", {
569
+ return request<GmailDraft>(connection, "/drafts", {
413
570
  method: "POST",
414
571
  body: JSON.stringify({ message }),
415
572
  });
@@ -417,13 +574,13 @@ export async function createDraft(
417
574
 
418
575
  /** Create a draft from a pre-built base64url MIME payload. */
419
576
  export async function createDraftRaw(
420
- token: string,
577
+ connection: OAuthConnection,
421
578
  raw: string,
422
579
  threadId?: string,
423
580
  ): Promise<GmailDraft> {
424
581
  const message: Record<string, unknown> = { raw };
425
582
  if (threadId) message.threadId = threadId;
426
- return request<GmailDraft>(token, "/drafts", {
583
+ return request<GmailDraft>(connection, "/drafts", {
427
584
  method: "POST",
428
585
  body: JSON.stringify({ message }),
429
586
  });
@@ -431,10 +588,10 @@ export async function createDraftRaw(
431
588
 
432
589
  /** Send an existing draft by ID. */
433
590
  export async function sendDraft(
434
- token: string,
591
+ connection: OAuthConnection,
435
592
  draftId: string,
436
593
  ): Promise<GmailMessage> {
437
- return request<GmailMessage>(token, "/drafts/send", {
594
+ return request<GmailMessage>(connection, "/drafts/send", {
438
595
  method: "POST",
439
596
  body: JSON.stringify({ id: draftId }),
440
597
  });
@@ -442,7 +599,7 @@ export async function sendDraft(
442
599
 
443
600
  /** Send an email. */
444
601
  export async function sendMessage(
445
- token: string,
602
+ connection: OAuthConnection,
446
603
  to: string,
447
604
  subject: string,
448
605
  body: string,
@@ -465,38 +622,40 @@ export async function sendMessage(
465
622
  .replace(/=+$/, "");
466
623
  const payload: Record<string, unknown> = { raw };
467
624
  if (threadId) payload.threadId = threadId;
468
- return request<GmailMessage>(token, "/messages/send", {
625
+ return request<GmailMessage>(connection, "/messages/send", {
469
626
  method: "POST",
470
627
  body: JSON.stringify(payload),
471
628
  });
472
629
  }
473
630
 
474
631
  /** Get the authenticated user's profile (email address). */
475
- export async function getProfile(token: string): Promise<GmailProfile> {
476
- return request<GmailProfile>(token, "/profile");
632
+ export async function getProfile(
633
+ connection: OAuthConnection,
634
+ ): Promise<GmailProfile> {
635
+ return request<GmailProfile>(connection, "/profile");
477
636
  }
478
637
 
479
638
  /** Get attachment data for a message. */
480
639
  export async function getAttachment(
481
- token: string,
640
+ connection: OAuthConnection,
482
641
  messageId: string,
483
642
  attachmentId: string,
484
643
  ): Promise<GmailAttachment> {
485
644
  return request<GmailAttachment>(
486
- token,
645
+ connection,
487
646
  `/messages/${messageId}/attachments/${attachmentId}`,
488
647
  );
489
648
  }
490
649
 
491
650
  /** Send an email with a pre-built raw MIME payload (for multipart/attachments). */
492
651
  export async function sendMessageRaw(
493
- token: string,
652
+ connection: OAuthConnection,
494
653
  raw: string,
495
654
  threadId?: string,
496
655
  ): Promise<GmailMessage> {
497
656
  const payload: Record<string, unknown> = { raw };
498
657
  if (threadId) payload.threadId = threadId;
499
- return request<GmailMessage>(token, "/messages/send", {
658
+ return request<GmailMessage>(connection, "/messages/send", {
500
659
  method: "POST",
501
660
  body: JSON.stringify(payload),
502
661
  });
@@ -504,23 +663,25 @@ export async function sendMessageRaw(
504
663
 
505
664
  /** Create a user label. */
506
665
  export async function createLabel(
507
- token: string,
666
+ connection: OAuthConnection,
508
667
  name: string,
509
668
  opts?: {
510
669
  messageListVisibility?: "show" | "hide";
511
670
  labelListVisibility?: "labelShow" | "labelShowIfUnread" | "labelHide";
512
671
  },
513
672
  ): Promise<GmailLabel> {
514
- return request<GmailLabel>(token, "/labels", {
673
+ return request<GmailLabel>(connection, "/labels", {
515
674
  method: "POST",
516
675
  body: JSON.stringify({ name, ...opts }),
517
676
  });
518
677
  }
519
678
 
520
679
  /** List all Gmail filters. */
521
- export async function listFilters(token: string): Promise<GmailFilter[]> {
680
+ export async function listFilters(
681
+ connection: OAuthConnection,
682
+ ): Promise<GmailFilter[]> {
522
683
  const resp = await request<GmailFiltersListResponse>(
523
- token,
684
+ connection,
524
685
  "/settings/filters",
525
686
  );
526
687
  return resp.filter ?? [];
@@ -528,11 +689,11 @@ export async function listFilters(token: string): Promise<GmailFilter[]> {
528
689
 
529
690
  /** Create a Gmail filter. */
530
691
  export async function createFilter(
531
- token: string,
692
+ connection: OAuthConnection,
532
693
  criteria: GmailFilterCriteria,
533
694
  action: GmailFilterAction,
534
695
  ): Promise<GmailFilter> {
535
- return request<GmailFilter>(token, "/settings/filters", {
696
+ return request<GmailFilter>(connection, "/settings/filters", {
536
697
  method: "POST",
537
698
  body: JSON.stringify({ criteria, action }),
538
699
  });
@@ -540,27 +701,27 @@ export async function createFilter(
540
701
 
541
702
  /** Delete a Gmail filter. */
542
703
  export async function deleteFilter(
543
- token: string,
704
+ connection: OAuthConnection,
544
705
  filterId: string,
545
706
  ): Promise<void> {
546
- await request<void>(token, `/settings/filters/${filterId}`, {
707
+ await request<void>(connection, `/settings/filters/${filterId}`, {
547
708
  method: "DELETE",
548
709
  });
549
710
  }
550
711
 
551
712
  /** Get vacation auto-reply settings. */
552
713
  export async function getVacation(
553
- token: string,
714
+ connection: OAuthConnection,
554
715
  ): Promise<GmailVacationSettings> {
555
- return request<GmailVacationSettings>(token, "/settings/vacation");
716
+ return request<GmailVacationSettings>(connection, "/settings/vacation");
556
717
  }
557
718
 
558
719
  /** Update vacation auto-reply settings. */
559
720
  export async function updateVacation(
560
- token: string,
721
+ connection: OAuthConnection,
561
722
  settings: GmailVacationSettings,
562
723
  ): Promise<GmailVacationSettings> {
563
- return request<GmailVacationSettings>(token, "/settings/vacation", {
724
+ return request<GmailVacationSettings>(connection, "/settings/vacation", {
564
725
  method: "PUT",
565
726
  body: JSON.stringify(settings),
566
727
  });