@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
|
@@ -16,8 +16,8 @@ You are a Google Calendar assistant with full access to the user's calendar. Use
|
|
|
16
16
|
Before using any Calendar tool, verify that Google Calendar is connected by attempting a lightweight call (e.g., `calendar_list_events` with a narrow date range). If the call fails with a token/authorization error:
|
|
17
17
|
|
|
18
18
|
1. **Do NOT call `credential_store oauth2_connect` yourself.** You do not have valid OAuth client credentials, and fabricating a client_id will cause a "401: invalid_client" error from Google.
|
|
19
|
-
2. Instead, load the **google-oauth-
|
|
20
|
-
- Call `skill_load` with `skill: "google-oauth-
|
|
19
|
+
2. Instead, load the **google-oauth-applescript** skill, which walks the user through creating real credentials in Google Cloud Console:
|
|
20
|
+
- Call `skill_load` with `skill: "google-oauth-applescript"` to load the dependency skill.
|
|
21
21
|
3. Tell the user: _"Google Calendar isn't connected yet. I've loaded a setup guide that will walk you through connecting your Google account — it only takes a couple of minutes."_
|
|
22
22
|
|
|
23
23
|
## Capabilities
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { OAuthConnection } from "../../../oauth/connection.js";
|
|
2
|
+
|
|
3
|
+
const GOOGLE_CALENDAR_BASE_URL = "https://www.googleapis.com/calendar/v3";
|
|
1
4
|
import type {
|
|
2
5
|
CalendarEvent,
|
|
3
6
|
CalendarEventsListResponse,
|
|
@@ -6,8 +9,6 @@ import type {
|
|
|
6
9
|
FreeBusyResponse,
|
|
7
10
|
} from "./types.js";
|
|
8
11
|
|
|
9
|
-
const CALENDAR_API_BASE = "https://www.googleapis.com/calendar/v3";
|
|
10
|
-
|
|
11
12
|
export class CalendarApiError extends Error {
|
|
12
13
|
constructor(
|
|
13
14
|
public readonly status: number,
|
|
@@ -20,39 +21,82 @@ export class CalendarApiError extends Error {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
async function request<T>(
|
|
23
|
-
|
|
24
|
+
connection: OAuthConnection,
|
|
24
25
|
path: string,
|
|
25
26
|
options?: RequestInit,
|
|
27
|
+
query?: Record<string, string | string[]>,
|
|
26
28
|
): Promise<T> {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const method = (options?.method ?? "GET").toUpperCase();
|
|
30
|
+
|
|
31
|
+
// Extract non-auth headers
|
|
32
|
+
let extraHeaders: Record<string, string> | undefined;
|
|
33
|
+
if (options?.headers) {
|
|
34
|
+
const raw = options.headers;
|
|
35
|
+
const result: Record<string, string> = {};
|
|
36
|
+
if (raw instanceof Headers) {
|
|
37
|
+
raw.forEach((v, k) => {
|
|
38
|
+
if (k.toLowerCase() !== "authorization") result[k] = v;
|
|
39
|
+
});
|
|
40
|
+
} else if (Array.isArray(raw)) {
|
|
41
|
+
for (const [k, v] of raw) {
|
|
42
|
+
if (k.toLowerCase() !== "authorization") result[k] = v;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
46
|
+
if (k.toLowerCase() !== "authorization" && v !== undefined)
|
|
47
|
+
result[k] = v;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (Object.keys(result).length > 0) extraHeaders = result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Extract body
|
|
54
|
+
let reqBody: unknown | undefined;
|
|
55
|
+
if (options?.body) {
|
|
56
|
+
if (typeof options.body === "string") {
|
|
57
|
+
try {
|
|
58
|
+
reqBody = JSON.parse(options.body);
|
|
59
|
+
} catch {
|
|
60
|
+
reqBody = options.body;
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
reqBody = options.body;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const resp = await connection.request({
|
|
68
|
+
method,
|
|
69
|
+
path,
|
|
70
|
+
query,
|
|
71
|
+
baseUrl: GOOGLE_CALENDAR_BASE_URL,
|
|
30
72
|
headers: {
|
|
31
|
-
Authorization: `Bearer ${token}`,
|
|
32
73
|
"Content-Type": "application/json",
|
|
33
|
-
...
|
|
74
|
+
...extraHeaders,
|
|
34
75
|
},
|
|
76
|
+
body: reqBody,
|
|
35
77
|
});
|
|
36
|
-
|
|
37
|
-
|
|
78
|
+
|
|
79
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
80
|
+
const bodyStr =
|
|
81
|
+
typeof resp.body === "string"
|
|
82
|
+
? resp.body
|
|
83
|
+
: JSON.stringify(resp.body ?? "");
|
|
38
84
|
throw new CalendarApiError(
|
|
39
85
|
resp.status,
|
|
40
|
-
|
|
41
|
-
`Calendar API ${resp.status}: ${
|
|
86
|
+
"",
|
|
87
|
+
`Calendar API ${resp.status}: ${bodyStr}`,
|
|
42
88
|
);
|
|
43
89
|
}
|
|
44
|
-
|
|
45
|
-
if (resp.status === 204 ||
|
|
90
|
+
|
|
91
|
+
if (resp.status === 204 || resp.body === undefined) {
|
|
46
92
|
return undefined as T;
|
|
47
93
|
}
|
|
48
|
-
|
|
49
|
-
if (!text) return undefined as T;
|
|
50
|
-
return JSON.parse(text) as T;
|
|
94
|
+
return resp.body as T;
|
|
51
95
|
}
|
|
52
96
|
|
|
53
97
|
/** List events from a calendar. */
|
|
54
98
|
export async function listEvents(
|
|
55
|
-
|
|
99
|
+
connection: OAuthConnection,
|
|
56
100
|
calendarId = "primary",
|
|
57
101
|
options?: {
|
|
58
102
|
timeMin?: string;
|
|
@@ -65,40 +109,42 @@ export async function listEvents(
|
|
|
65
109
|
syncToken?: string;
|
|
66
110
|
},
|
|
67
111
|
): Promise<CalendarEventsListResponse> {
|
|
68
|
-
const
|
|
112
|
+
const query: Record<string, string> = {};
|
|
69
113
|
|
|
70
|
-
if (options?.timeMin)
|
|
71
|
-
if (options?.timeMax)
|
|
72
|
-
|
|
73
|
-
if (options?.query)
|
|
114
|
+
if (options?.timeMin) query.timeMin = options.timeMin;
|
|
115
|
+
if (options?.timeMax) query.timeMax = options.timeMax;
|
|
116
|
+
query.maxResults = String(options?.maxResults ?? 25);
|
|
117
|
+
if (options?.query) query.q = options.query;
|
|
74
118
|
|
|
75
119
|
// Default to expanding recurring events into instances
|
|
76
120
|
const singleEvents = options?.singleEvents ?? true;
|
|
77
|
-
|
|
121
|
+
query.singleEvents = String(singleEvents);
|
|
78
122
|
|
|
79
123
|
if (singleEvents && options?.orderBy) {
|
|
80
|
-
|
|
124
|
+
query.orderBy = options.orderBy;
|
|
81
125
|
} else if (singleEvents) {
|
|
82
|
-
|
|
126
|
+
query.orderBy = "startTime";
|
|
83
127
|
}
|
|
84
128
|
|
|
85
|
-
if (options?.pageToken)
|
|
86
|
-
if (options?.syncToken)
|
|
129
|
+
if (options?.pageToken) query.pageToken = options.pageToken;
|
|
130
|
+
if (options?.syncToken) query.syncToken = options.syncToken;
|
|
87
131
|
|
|
88
132
|
return request<CalendarEventsListResponse>(
|
|
89
|
-
|
|
90
|
-
`/calendars/${encodeURIComponent(calendarId)}/events
|
|
133
|
+
connection,
|
|
134
|
+
`/calendars/${encodeURIComponent(calendarId)}/events`,
|
|
135
|
+
undefined,
|
|
136
|
+
query,
|
|
91
137
|
);
|
|
92
138
|
}
|
|
93
139
|
|
|
94
140
|
/** Get a single event by ID. */
|
|
95
141
|
export async function getEvent(
|
|
96
|
-
|
|
142
|
+
connection: OAuthConnection,
|
|
97
143
|
eventId: string,
|
|
98
144
|
calendarId = "primary",
|
|
99
145
|
): Promise<CalendarEvent> {
|
|
100
146
|
return request<CalendarEvent>(
|
|
101
|
-
|
|
147
|
+
connection,
|
|
102
148
|
`/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(
|
|
103
149
|
eventId,
|
|
104
150
|
)}`,
|
|
@@ -107,7 +153,7 @@ export async function getEvent(
|
|
|
107
153
|
|
|
108
154
|
/** Create a new event. */
|
|
109
155
|
export async function createEvent(
|
|
110
|
-
|
|
156
|
+
connection: OAuthConnection,
|
|
111
157
|
event: {
|
|
112
158
|
summary: string;
|
|
113
159
|
start: { dateTime?: string; date?: string; timeZone?: string };
|
|
@@ -119,20 +165,20 @@ export async function createEvent(
|
|
|
119
165
|
calendarId = "primary",
|
|
120
166
|
sendUpdates: "all" | "externalOnly" | "none" = "all",
|
|
121
167
|
): Promise<CalendarEvent> {
|
|
122
|
-
const params = new URLSearchParams({ sendUpdates });
|
|
123
168
|
return request<CalendarEvent>(
|
|
124
|
-
|
|
125
|
-
`/calendars/${encodeURIComponent(calendarId)}/events
|
|
169
|
+
connection,
|
|
170
|
+
`/calendars/${encodeURIComponent(calendarId)}/events`,
|
|
126
171
|
{
|
|
127
172
|
method: "POST",
|
|
128
173
|
body: JSON.stringify(event),
|
|
129
174
|
},
|
|
175
|
+
{ sendUpdates },
|
|
130
176
|
);
|
|
131
177
|
}
|
|
132
178
|
|
|
133
179
|
/** Update an event (patch). */
|
|
134
180
|
export async function patchEvent(
|
|
135
|
-
|
|
181
|
+
connection: OAuthConnection,
|
|
136
182
|
eventId: string,
|
|
137
183
|
updates: Partial<{
|
|
138
184
|
summary: string;
|
|
@@ -145,25 +191,25 @@ export async function patchEvent(
|
|
|
145
191
|
calendarId = "primary",
|
|
146
192
|
sendUpdates: "all" | "externalOnly" | "none" = "all",
|
|
147
193
|
): Promise<CalendarEvent> {
|
|
148
|
-
const params = new URLSearchParams({ sendUpdates });
|
|
149
194
|
return request<CalendarEvent>(
|
|
150
|
-
|
|
195
|
+
connection,
|
|
151
196
|
`/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(
|
|
152
197
|
eventId,
|
|
153
|
-
)}
|
|
198
|
+
)}`,
|
|
154
199
|
{
|
|
155
200
|
method: "PATCH",
|
|
156
201
|
body: JSON.stringify(updates),
|
|
157
202
|
},
|
|
203
|
+
{ sendUpdates },
|
|
158
204
|
);
|
|
159
205
|
}
|
|
160
206
|
|
|
161
207
|
/** Query free/busy information. */
|
|
162
208
|
export async function freeBusy(
|
|
163
|
-
|
|
209
|
+
connection: OAuthConnection,
|
|
164
210
|
query: FreeBusyRequest,
|
|
165
211
|
): Promise<FreeBusyResponse> {
|
|
166
|
-
return request<FreeBusyResponse>(
|
|
212
|
+
return request<FreeBusyResponse>(connection, "/freeBusy", {
|
|
167
213
|
method: "POST",
|
|
168
214
|
body: JSON.stringify(query),
|
|
169
215
|
});
|
|
@@ -171,7 +217,7 @@ export async function freeBusy(
|
|
|
171
217
|
|
|
172
218
|
/** List calendars the user has access to. */
|
|
173
219
|
export async function listCalendars(
|
|
174
|
-
|
|
220
|
+
connection: OAuthConnection,
|
|
175
221
|
): Promise<CalendarListResponse> {
|
|
176
|
-
return request<CalendarListResponse>(
|
|
222
|
+
return request<CalendarListResponse>(connection, "/users/me/calendarList");
|
|
177
223
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolExecutionResult,
|
|
4
4
|
} from "../../../../tools/types.js";
|
|
5
5
|
import * as calendar from "../calendar-client.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getCalendarConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -14,14 +14,13 @@ export async function run(
|
|
|
14
14
|
const calendarIds = (input.calendar_ids as string[]) ?? ["primary"];
|
|
15
15
|
const timezone = input.timezone as string | undefined;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
return ok(JSON.stringify(result, null, 2));
|
|
17
|
+
const connection = getCalendarConnection();
|
|
18
|
+
const result = await calendar.freeBusy(connection, {
|
|
19
|
+
timeMin,
|
|
20
|
+
timeMax,
|
|
21
|
+
timeZone: timezone,
|
|
22
|
+
items: calendarIds.map((id) => ({ id })),
|
|
26
23
|
});
|
|
24
|
+
|
|
25
|
+
return ok(JSON.stringify(result, null, 2));
|
|
27
26
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolExecutionResult,
|
|
4
4
|
} from "../../../../tools/types.js";
|
|
5
5
|
import * as calendar from "../calendar-client.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getCalendarConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -40,9 +40,8 @@ export async function run(
|
|
|
40
40
|
eventBody.attendees = attendees.map((email) => ({ email }));
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
});
|
|
43
|
+
const connection = getCalendarConnection();
|
|
44
|
+
const event = await calendar.createEvent(connection, eventBody, calendarId);
|
|
45
|
+
const link = event.htmlLink ? ` View it here: ${event.htmlLink}` : "";
|
|
46
|
+
return ok(`Event created (ID: ${event.id}).${link}`);
|
|
48
47
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolExecutionResult,
|
|
4
4
|
} from "../../../../tools/types.js";
|
|
5
5
|
import * as calendar from "../calendar-client.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getCalendarConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -12,8 +12,7 @@ export async function run(
|
|
|
12
12
|
const eventId = input.event_id as string;
|
|
13
13
|
const calendarId = (input.calendar_id as string) ?? "primary";
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
15
|
+
const connection = getCalendarConnection();
|
|
16
|
+
const event = await calendar.getEvent(connection, eventId, calendarId);
|
|
17
|
+
return ok(JSON.stringify(event, null, 2));
|
|
19
18
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolExecutionResult,
|
|
4
4
|
} from "../../../../tools/types.js";
|
|
5
5
|
import * as calendar from "../calendar-client.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getCalendarConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -17,20 +17,19 @@ export async function run(
|
|
|
17
17
|
const singleEvents = (input.single_events as boolean) ?? true;
|
|
18
18
|
const orderBy = input.order_by as "startTime" | "updated" | undefined;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
const connection = getCalendarConnection();
|
|
21
|
+
const result = await calendar.listEvents(connection, calendarId, {
|
|
22
|
+
timeMin,
|
|
23
|
+
timeMax,
|
|
24
|
+
maxResults,
|
|
25
|
+
query,
|
|
26
|
+
singleEvents,
|
|
27
|
+
orderBy,
|
|
28
|
+
});
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
if (!result.items?.length) {
|
|
31
|
+
return ok("No events found in the specified time range.");
|
|
32
|
+
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
});
|
|
34
|
+
return ok(JSON.stringify(result, null, 2));
|
|
36
35
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
ToolExecutionResult,
|
|
4
4
|
} from "../../../../tools/types.js";
|
|
5
5
|
import * as calendar from "../calendar-client.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getCalendarConnection, ok } from "./shared.js";
|
|
7
7
|
|
|
8
8
|
export async function run(
|
|
9
9
|
input: Record<string, unknown>,
|
|
@@ -13,45 +13,45 @@ export async function run(
|
|
|
13
13
|
const response = input.response as "accepted" | "declined" | "tentative";
|
|
14
14
|
const calendarId = (input.calendar_id as string) ?? "primary";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
// First get the event to find the user's attendee entry
|
|
18
|
-
const event = await calendar.getEvent(token, eventId, calendarId);
|
|
19
|
-
const selfAttendee = event.attendees?.find((a) => a.self);
|
|
16
|
+
const connection = getCalendarConnection();
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (event.organizer?.self) {
|
|
25
|
-
return ok("You are the organizer of this event. No RSVP needed.");
|
|
26
|
-
}
|
|
27
|
-
return ok(
|
|
28
|
-
"Could not find your attendee entry for this event. You may not be invited.",
|
|
29
|
-
);
|
|
30
|
-
}
|
|
18
|
+
// First get the event to find the user's attendee entry
|
|
19
|
+
const event = await calendar.getEvent(connection, eventId, calendarId);
|
|
20
|
+
const selfAttendee = event.attendees?.find((a) => a.self);
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
if (!selfAttendee) {
|
|
23
|
+
// If the user is the organizer and not in the attendees list,
|
|
24
|
+
// they don't need to RSVP
|
|
25
|
+
if (event.organizer?.self) {
|
|
26
|
+
return ok("You are the organizer of this event. No RSVP needed.");
|
|
27
|
+
}
|
|
28
|
+
return ok(
|
|
29
|
+
"Could not find your attendee entry for this event. You may not be invited.",
|
|
35
30
|
);
|
|
31
|
+
}
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
// Update the attendee's response status
|
|
34
|
+
const updatedAttendees = event.attendees!.map((a) =>
|
|
35
|
+
a.self ? { ...a, responseStatus: response } : a,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
await calendar.patchEvent(
|
|
39
|
+
connection,
|
|
40
|
+
eventId,
|
|
41
|
+
{
|
|
42
|
+
attendees: updatedAttendees as Array<{
|
|
43
|
+
email: string;
|
|
44
|
+
responseStatus?: string;
|
|
45
|
+
}>,
|
|
46
|
+
},
|
|
47
|
+
calendarId,
|
|
48
|
+
);
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
});
|
|
50
|
+
const responseLabel =
|
|
51
|
+
response === "accepted"
|
|
52
|
+
? "Accepted"
|
|
53
|
+
: response === "declined"
|
|
54
|
+
? "Declined"
|
|
55
|
+
: "Tentatively accepted";
|
|
56
|
+
return ok(`${responseLabel} the event "${event.summary ?? eventId}".`);
|
|
57
57
|
}
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
2
|
+
import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
|
|
2
3
|
import type { ToolExecutionResult } from "../../../../tools/types.js";
|
|
3
4
|
|
|
4
5
|
export function ok(content: string): ToolExecutionResult {
|
|
5
6
|
return { content, isError: false };
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
export function err(message: string): ToolExecutionResult {
|
|
9
|
-
return { content: message, isError: true };
|
|
10
|
-
}
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* Calendar uses the same OAuth credential service as Gmail since both
|
|
14
11
|
* scopes are granted in a single OAuth consent flow.
|
|
15
12
|
*/
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
): Promise<T> {
|
|
19
|
-
return withValidToken("integration:gmail", fn);
|
|
13
|
+
export function getCalendarConnection(): OAuthConnection {
|
|
14
|
+
return resolveOAuthConnection("integration:gmail");
|
|
20
15
|
}
|
|
@@ -5,10 +5,15 @@ import {
|
|
|
5
5
|
} from "../../../../daemon/media-visibility-policy.js";
|
|
6
6
|
import {
|
|
7
7
|
generateImage,
|
|
8
|
+
type ImageGenCredentials,
|
|
8
9
|
mapGeminiError,
|
|
9
10
|
} from "../../../../media/gemini-image-service.js";
|
|
10
11
|
import { getAttachmentsByIds } from "../../../../memory/attachments-store.js";
|
|
11
12
|
import { getConversationThreadType } from "../../../../memory/conversation-crud.js";
|
|
13
|
+
import {
|
|
14
|
+
buildManagedBaseUrl,
|
|
15
|
+
resolveManagedProxyContext,
|
|
16
|
+
} from "../../../../providers/managed-proxy/context.js";
|
|
12
17
|
import type { ImageContent } from "../../../../providers/types.js";
|
|
13
18
|
import { getAttachmentSourceConversations } from "../../../../tools/assets/search.js";
|
|
14
19
|
import type {
|
|
@@ -46,9 +51,25 @@ export async function run(
|
|
|
46
51
|
context: ToolContext,
|
|
47
52
|
): Promise<ToolExecutionResult> {
|
|
48
53
|
const config = getConfig();
|
|
49
|
-
const apiKey = config.apiKeys.gemini;
|
|
54
|
+
const apiKey = config.apiKeys.gemini ?? process.env.GEMINI_API_KEY;
|
|
55
|
+
|
|
56
|
+
// Resolve credentials: prefer direct API key, fall back to managed proxy
|
|
57
|
+
let credentials: ImageGenCredentials | undefined;
|
|
58
|
+
if (apiKey) {
|
|
59
|
+
credentials = { type: "direct", apiKey };
|
|
60
|
+
} else {
|
|
61
|
+
const managedBaseUrl = buildManagedBaseUrl("vertex");
|
|
62
|
+
if (managedBaseUrl) {
|
|
63
|
+
const ctx = resolveManagedProxyContext();
|
|
64
|
+
credentials = {
|
|
65
|
+
type: "managed-proxy",
|
|
66
|
+
assistantApiKey: ctx.assistantApiKey,
|
|
67
|
+
baseUrl: managedBaseUrl,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
50
71
|
|
|
51
|
-
if (!
|
|
72
|
+
if (!credentials) {
|
|
52
73
|
return {
|
|
53
74
|
content:
|
|
54
75
|
"No Gemini API key configured. Please set your Gemini API key to use image generation.",
|
|
@@ -95,7 +116,7 @@ export async function run(
|
|
|
95
116
|
}
|
|
96
117
|
|
|
97
118
|
try {
|
|
98
|
-
const result = await generateImage(
|
|
119
|
+
const result = await generateImage(credentials, {
|
|
99
120
|
prompt,
|
|
100
121
|
mode,
|
|
101
122
|
sourceImages,
|
|
@@ -33,9 +33,9 @@ When a platform is connected (auth test succeeds), always use the messaging API
|
|
|
33
33
|
|
|
34
34
|
Before using any messaging tool, verify that the platform is connected by calling `messaging_auth_test` with the appropriate `platform` parameter. If the call fails with a token/authorization error, follow the steps below.
|
|
35
35
|
|
|
36
|
-
### Public Ingress (required for
|
|
36
|
+
### Public Ingress (required for Slack and Telegram)
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Slack and Telegram setup require a publicly reachable URL for OAuth callbacks or webhook delivery. The **public-ingress** skill handles ngrok tunnel setup and persists the URL as `ingress.publicBaseUrl`. Gmail on the desktop app uses a loopback callback and does not require public ingress; the channel path (Path B in the google-oauth-applescript skill) handles public ingress internally when needed.
|
|
39
39
|
|
|
40
40
|
### Email Connection Flow
|
|
41
41
|
|
|
@@ -48,11 +48,11 @@ When the user asks to "connect my email", "set up email", "manage my email", or
|
|
|
48
48
|
### Gmail
|
|
49
49
|
|
|
50
50
|
1. **Try connecting directly first.** Call `credential_store` with `action: "oauth2_connect"` and `service: "gmail"`. The tool auto-fills Google's OAuth endpoints and looks up any previously stored client credentials — so this single call may be all that's needed.
|
|
51
|
-
2. **If it fails because no client_id is found:** The user needs to create Google Cloud OAuth credentials first. Load the **google-oauth-
|
|
52
|
-
- Call `skill_load` with `skill: "google-oauth-
|
|
51
|
+
2. **If it fails because no client_id is found:** The user needs to create Google Cloud OAuth credentials first. Load the **google-oauth-applescript** skill:
|
|
52
|
+
- Call `skill_load` with `skill: "google-oauth-applescript"` to load the dependency skill.
|
|
53
53
|
- Tell the user Gmail isn't connected yet and briefly explain what the setup involves, then use `ui_show` with `surface_type: "confirmation"` to ask for permission to start:
|
|
54
54
|
- **message:** "Ready to set up Gmail?"
|
|
55
|
-
- **detail:** "I'll open a browser
|
|
55
|
+
- **detail:** "I'll open a few pages in your browser and walk you through setting up Google Cloud credentials — creating a project, enabling APIs, and connecting your account. Takes about 5 minutes."
|
|
56
56
|
- **confirmLabel:** "Get Started"
|
|
57
57
|
- **cancelLabel:** "Not Now"
|
|
58
58
|
- If the user confirms, briefly acknowledge (e.g., "Setting up Gmail now...") and proceed with the setup guide. If they decline, acknowledge and let them know they can set it up later.
|
|
@@ -95,7 +95,7 @@ The guardian-verify-setup skill handles the full outbound verification flow for
|
|
|
95
95
|
When a messaging tool fails with a token or authorization error:
|
|
96
96
|
|
|
97
97
|
1. **Try to reconnect silently.** Call `credential_store` with `action: "oauth2_connect"` and the appropriate `service`. This often resolves expired tokens automatically.
|
|
98
|
-
2. **If reconnection fails, go straight to setup.** Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected — let me set that up") and immediately follow the connection setup flow for that platform (e.g., install and load **google-oauth-
|
|
98
|
+
2. **If reconnection fails, go straight to setup.** Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected — let me set that up") and immediately follow the connection setup flow for that platform (e.g., install and load **google-oauth-applescript** for Gmail). The user came to you to get something done, not to troubleshoot OAuth — make it seamless.
|
|
99
99
|
3. **Never try alternative approaches.** Don't use bash, curl, browser automation, or any workaround. If the messaging tools can't do it, the reconnection flow is the answer.
|
|
100
100
|
4. **Never expose error details.** The user doesn't need to see error messages about tokens, OAuth, or API failures. Translate errors into plain language.
|
|
101
101
|
|