@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.
- package/ARCHITECTURE.md +7 -7
- package/README.md +2 -23
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/architecture/security.md +5 -5
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/anthropic-provider.test.ts +156 -0
- package/src/__tests__/approval-cascade.test.ts +810 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-fill-credential.test.ts +5 -2
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +35 -25
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +9 -29
- package/src/__tests__/cli.test.ts +23 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
- package/src/__tests__/credential-broker-server-use.test.ts +22 -21
- package/src/__tests__/credential-broker.test.ts +2 -1
- package/src/__tests__/credential-metadata-store.test.ts +239 -26
- package/src/__tests__/credential-resolve.test.ts +5 -4
- package/src/__tests__/credential-security-e2e.test.ts +8 -8
- package/src/__tests__/credential-security-invariants.test.ts +111 -7
- package/src/__tests__/credential-vault-unit.test.ts +287 -54
- package/src/__tests__/credential-vault.test.ts +406 -12
- package/src/__tests__/credentials-cli.test.ts +82 -6
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-image-service.test.ts +75 -45
- package/src/__tests__/gemini-provider.test.ts +9 -6
- package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
- package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
- package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-grant-minting.test.ts +35 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/host-cu-proxy.test.ts +629 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +38 -25
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +11 -43
- package/src/__tests__/managed-proxy-context.test.ts +5 -3
- package/src/__tests__/media-generate-image.test.ts +63 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
- package/src/__tests__/messaging-send-tool.test.ts +4 -6
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +373 -14
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +756 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
- package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/schema-transforms.test.ts +226 -0
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
- package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
- package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/secret-onetime-send.test.ts +5 -3
- package/src/__tests__/send-endpoint-busy.test.ts +21 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-uninstall.test.ts +3 -3
- package/src/__tests__/skills.test.ts +3 -12
- package/src/__tests__/slack-channel-config.test.ts +76 -11
- package/src/__tests__/slack-share-routes.test.ts +17 -14
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +1 -22
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +2 -1
- package/src/__tests__/twilio-provider.test.ts +4 -2
- package/src/__tests__/twilio-routes.test.ts +5 -20
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +235 -0
- package/src/agent/loop.ts +76 -130
- package/src/calls/call-domain.ts +8 -10
- package/src/calls/relay-server.ts +9 -13
- package/src/calls/twilio-config.ts +4 -8
- package/src/calls/twilio-provider.ts +2 -1
- package/src/calls/twilio-rest.ts +2 -1
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +46 -15
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +110 -23
- package/src/cli/commands/oauth/apps.ts +255 -0
- package/src/cli/commands/oauth/connections.ts +299 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +242 -0
- package/src/cli/commands/skills.ts +4 -338
- package/src/cli/program.ts +1 -5
- package/src/cli/reference.ts +1 -3
- package/src/cli.ts +3 -2
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
- package/src/config/bundled-skills/gmail/SKILL.md +4 -4
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
- package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +90 -44
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
- package/src/config/bundled-skills/messaging/SKILL.md +6 -6
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
- package/src/config/bundled-skills/messaging/tools/shared.ts +12 -15
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/schema.ts +3 -1
- package/src/config/skills.ts +21 -2
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +49 -10
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/guardian-action-generators.ts +4 -5
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +76 -56
- package/src/daemon/handlers/config-telegram.ts +53 -24
- package/src/daemon/handlers/sessions.ts +10 -24
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/host-cu-proxy.ts +401 -0
- package/src/daemon/lifecycle.ts +39 -63
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +2 -119
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/integrations.ts +1 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/server.ts +14 -21
- package/src/daemon/session-agent-loop-handlers.ts +2 -0
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-messaging.ts +3 -1
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +40 -28
- package/src/daemon/session-tool-setup.ts +20 -11
- package/src/daemon/session.ts +139 -16
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/email/providers/index.ts +2 -1
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/instrument.ts +15 -1
- package/src/logfire.ts +16 -5
- package/src/media/app-icon-generator.ts +30 -4
- package/src/media/avatar-router.ts +26 -3
- package/src/media/gemini-image-service.ts +28 -2
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/db-init.ts +4 -0
- package/src/memory/guardian-action-store.ts +1 -1
- package/src/memory/migrations/149-oauth-tables.ts +60 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/guardian.ts +1 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/oauth.ts +65 -0
- package/src/messaging/provider.ts +19 -13
- package/src/messaging/providers/gmail/adapter.ts +40 -23
- package/src/messaging/providers/gmail/client.ts +283 -122
- package/src/messaging/providers/gmail/people-client.ts +32 -24
- package/src/messaging/providers/slack/adapter.ts +29 -19
- package/src/messaging/providers/slack/client.ts +265 -78
- package/src/messaging/providers/telegram-bot/adapter.ts +19 -18
- package/src/messaging/providers/whatsapp/adapter.ts +17 -11
- package/src/messaging/registry.ts +2 -31
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +537 -0
- package/src/oauth/byo-connection.ts +128 -0
- package/src/oauth/connect-orchestrator.ts +139 -56
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +58 -0
- package/src/oauth/connection.ts +38 -0
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +496 -0
- package/src/oauth/platform-connection.test.ts +192 -0
- package/src/oauth/platform-connection.ts +111 -0
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +161 -0
- package/src/oauth/token-persistence.ts +74 -78
- package/src/permissions/checker.ts +8 -4
- package/src/permissions/defaults.ts +0 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +13 -0
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +70 -45
- package/src/providers/anthropic/client.ts +133 -24
- package/src/providers/gemini/client.ts +15 -6
- package/src/providers/managed-proxy/constants.ts +2 -2
- package/src/providers/managed-proxy/context.ts +5 -1
- package/src/providers/ratelimit.ts +17 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +1 -27
- package/src/runtime/AGENTS.md +17 -0
- package/src/runtime/auth/route-policy.ts +0 -3
- package/src/runtime/channel-invite-transports/telegram.ts +2 -1
- package/src/runtime/channel-readiness-service.ts +168 -195
- package/src/runtime/channel-readiness-types.ts +4 -0
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/guardian-action-conversation-turn.ts +1 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -1
- package/src/runtime/guardian-action-message-composer.ts +3 -23
- package/src/runtime/http-server.ts +17 -10
- package/src/runtime/http-types.ts +2 -3
- package/src/runtime/middleware/rate-limiter.ts +74 -20
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/channel-readiness-routes.ts +2 -0
- package/src/runtime/routes/conversation-routes.ts +73 -19
- package/src/runtime/routes/diagnostics-routes.ts +11 -9
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/guardian-approval-interception.ts +20 -5
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -6
- package/src/runtime/routes/integrations/twilio.ts +6 -5
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/secret-routes.ts +3 -2
- package/src/runtime/routes/settings-routes.ts +113 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/schedule/integration-status.ts +10 -8
- package/src/security/credential-key.ts +14 -0
- package/src/security/keychain-broker-client.ts +5 -6
- package/src/security/oauth2.ts +1 -1
- package/src/security/token-manager.ts +145 -43
- package/src/skills/catalog-install.ts +358 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/apps/definitions.ts +0 -5
- package/src/tools/assets/materialize.ts +0 -5
- package/src/tools/assets/search.ts +0 -5
- package/src/tools/browser/headless-browser.ts +1 -67
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/claude-code/claude-code.ts +0 -5
- package/src/tools/computer-use/definitions.ts +46 -11
- package/src/tools/computer-use/registry.ts +4 -5
- package/src/tools/credentials/broker.ts +5 -4
- package/src/tools/credentials/metadata-store.ts +22 -74
- package/src/tools/credentials/resolve.ts +2 -1
- package/src/tools/credentials/vault.ts +139 -151
- package/src/tools/filesystem/edit.ts +1 -6
- package/src/tools/filesystem/read.ts +0 -5
- package/src/tools/filesystem/write.ts +1 -6
- package/src/tools/host-filesystem/edit.ts +1 -6
- package/src/tools/host-filesystem/read.ts +1 -6
- package/src/tools/host-filesystem/write.ts +1 -6
- package/src/tools/mcp/mcp-tool-factory.ts +18 -1
- package/src/tools/memory/definitions.ts +0 -5
- package/src/tools/network/web-fetch.ts +0 -5
- package/src/tools/network/web-search.ts +0 -5
- package/src/tools/registry.ts +2 -7
- package/src/tools/schema-transforms.ts +99 -0
- package/src/tools/skills/load.ts +62 -8
- package/src/tools/swarm/delegate.ts +0 -5
- package/src/tools/system/avatar-generator.ts +0 -5
- package/src/tools/ui-surface/definitions.ts +0 -15
- package/src/tools/watch/screen-watch.ts +0 -5
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/version.ts +10 -0
- package/src/watcher/providers/github.ts +51 -52
- package/src/watcher/providers/gmail.ts +88 -80
- package/src/watcher/providers/google-calendar.ts +94 -86
- package/src/watcher/providers/linear.ts +87 -93
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
- package/src/daemon/computer-use-session.ts +0 -1020
- package/src/daemon/ride-shotgun-handler.ts +0 -567
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -597
- package/src/runtime/telegram-streaming-delivery.ts +0 -383
- 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
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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 (
|
|
142
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
77
143
|
if (canRetry && isRetryable(resp.status) && attempt < MAX_RETRIES) {
|
|
78
|
-
const retryAfter =
|
|
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
|
|
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
|
-
|
|
89
|
-
`Gmail API ${resp.status}: ${
|
|
158
|
+
"",
|
|
159
|
+
`Gmail API ${resp.status}: ${bodyStr}`,
|
|
90
160
|
);
|
|
91
161
|
}
|
|
92
162
|
|
|
93
|
-
//
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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>(
|
|
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
|
-
|
|
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>(
|
|
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
|
-
|
|
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
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
247
|
-
const
|
|
248
|
-
if (!parsed) continue;
|
|
311
|
+
const contentType = resp.headers.get("content-type") ?? "";
|
|
312
|
+
const responseText = await resp.text();
|
|
249
313
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
265
|
-
|
|
352
|
+
throw new Error(
|
|
353
|
+
"Unreachable: batch retry loop exited without returning or throwing",
|
|
354
|
+
);
|
|
355
|
+
};
|
|
266
356
|
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
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
|
|
409
|
+
// Single message -- just use getMessage directly
|
|
287
410
|
if (messageIds.length === 1) {
|
|
288
411
|
return [
|
|
289
|
-
await getMessage(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
497
|
+
connection: OAuthConnection,
|
|
343
498
|
messageId: string,
|
|
344
499
|
modifications: GmailModifyRequest,
|
|
345
500
|
): Promise<GmailMessage> {
|
|
346
|
-
return request<GmailMessage>(
|
|
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
|
-
|
|
510
|
+
connection: OAuthConnection,
|
|
356
511
|
messageIds: string[],
|
|
357
512
|
modifications: GmailModifyRequest,
|
|
358
513
|
): Promise<void> {
|
|
359
|
-
await request<void>(
|
|
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
|
-
|
|
523
|
+
connection: OAuthConnection,
|
|
369
524
|
messageId: string,
|
|
370
525
|
): Promise<GmailMessage> {
|
|
371
|
-
return request<GmailMessage>(
|
|
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(
|
|
379
|
-
|
|
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
|
-
|
|
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>(
|
|
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
|
-
|
|
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>(
|
|
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
|
-
|
|
591
|
+
connection: OAuthConnection,
|
|
435
592
|
draftId: string,
|
|
436
593
|
): Promise<GmailMessage> {
|
|
437
|
-
return request<GmailMessage>(
|
|
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
|
-
|
|
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>(
|
|
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(
|
|
476
|
-
|
|
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
|
-
|
|
640
|
+
connection: OAuthConnection,
|
|
482
641
|
messageId: string,
|
|
483
642
|
attachmentId: string,
|
|
484
643
|
): Promise<GmailAttachment> {
|
|
485
644
|
return request<GmailAttachment>(
|
|
486
|
-
|
|
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
|
-
|
|
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>(
|
|
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
|
-
|
|
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>(
|
|
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(
|
|
680
|
+
export async function listFilters(
|
|
681
|
+
connection: OAuthConnection,
|
|
682
|
+
): Promise<GmailFilter[]> {
|
|
522
683
|
const resp = await request<GmailFiltersListResponse>(
|
|
523
|
-
|
|
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
|
-
|
|
692
|
+
connection: OAuthConnection,
|
|
532
693
|
criteria: GmailFilterCriteria,
|
|
533
694
|
action: GmailFilterAction,
|
|
534
695
|
): Promise<GmailFilter> {
|
|
535
|
-
return request<GmailFilter>(
|
|
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
|
-
|
|
704
|
+
connection: OAuthConnection,
|
|
544
705
|
filterId: string,
|
|
545
706
|
): Promise<void> {
|
|
546
|
-
await request<void>(
|
|
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
|
-
|
|
714
|
+
connection: OAuthConnection,
|
|
554
715
|
): Promise<GmailVacationSettings> {
|
|
555
|
-
return request<GmailVacationSettings>(
|
|
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
|
-
|
|
721
|
+
connection: OAuthConnection,
|
|
561
722
|
settings: GmailVacationSettings,
|
|
562
723
|
): Promise<GmailVacationSettings> {
|
|
563
|
-
return request<GmailVacationSettings>(
|
|
724
|
+
return request<GmailVacationSettings>(connection, "/settings/vacation", {
|
|
564
725
|
method: "PUT",
|
|
565
726
|
body: JSON.stringify(settings),
|
|
566
727
|
});
|