@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
|
@@ -84,7 +84,10 @@ export class PermissionPrompter {
|
|
|
84
84
|
"Permission prompt timed out, defaulting to deny",
|
|
85
85
|
);
|
|
86
86
|
this.onStateChanged?.(requestId, "timed_out", "timeout", toolUseId);
|
|
87
|
-
resolve({
|
|
87
|
+
resolve({
|
|
88
|
+
decision: "deny",
|
|
89
|
+
decisionContext: `The permission prompt for the "${toolName}" tool timed out. The user did not explicitly deny this request — they may have been away or busy. You may retry this tool call if it is still needed for the current task.`,
|
|
90
|
+
});
|
|
88
91
|
}, timeoutMs);
|
|
89
92
|
|
|
90
93
|
this.pending.set(requestId, { resolve, reject, timer, toolUseId });
|
|
@@ -121,6 +124,7 @@ export class PermissionPrompter {
|
|
|
121
124
|
executionTarget,
|
|
122
125
|
persistentDecisionsAllowed: persistentDecisionsAllowed ?? true,
|
|
123
126
|
temporaryOptionsAvailable,
|
|
127
|
+
toolUseId,
|
|
124
128
|
});
|
|
125
129
|
|
|
126
130
|
this.onStateChanged?.(requestId, "pending", "system", toolUseId);
|
|
@@ -131,6 +135,11 @@ export class PermissionPrompter {
|
|
|
131
135
|
return this.pending.has(requestId);
|
|
132
136
|
}
|
|
133
137
|
|
|
138
|
+
/** Returns all currently pending request IDs. */
|
|
139
|
+
getPendingRequestIds(): string[] {
|
|
140
|
+
return [...this.pending.keys()];
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
/** Returns the toolUseId associated with a pending request, if any. */
|
|
135
144
|
getToolUseId(requestId: string): string | undefined {
|
|
136
145
|
return this.pending.get(requestId)?.toolUseId;
|
|
@@ -76,6 +76,19 @@ function getCompiledPattern(pattern: string): Minimatch | null {
|
|
|
76
76
|
return compiled;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Check whether a minimatch pattern matches a candidate string.
|
|
81
|
+
* Reuses the compiled pattern cache from trust rule evaluation.
|
|
82
|
+
*/
|
|
83
|
+
export function patternMatchesCandidate(
|
|
84
|
+
pattern: string,
|
|
85
|
+
candidate: string,
|
|
86
|
+
): boolean {
|
|
87
|
+
const compiled = getCompiledPattern(pattern);
|
|
88
|
+
if (!compiled) return false;
|
|
89
|
+
return compiled.match(candidate);
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
/** Rebuild the compiled pattern cache from the current rule set. */
|
|
80
93
|
function rebuildPatternCache(rules: TrustRule[]): void {
|
|
81
94
|
compiledPatterns.clear();
|
|
@@ -38,7 +38,9 @@ describe("buildCliReferenceSection", () => {
|
|
|
38
38
|
"prefer real `assistant` CLI workflows over any legacy account-record abstraction",
|
|
39
39
|
);
|
|
40
40
|
expect(result).toContain("assistant credentials");
|
|
41
|
-
expect(result).toContain(
|
|
41
|
+
expect(result).toContain(
|
|
42
|
+
"assistant oauth connections token <provider-key>",
|
|
43
|
+
);
|
|
42
44
|
expect(result).toContain("assistant mcp auth <name>");
|
|
43
45
|
expect(result).toContain("assistant platform status");
|
|
44
46
|
});
|
|
@@ -4,10 +4,10 @@ import { join } from "node:path";
|
|
|
4
4
|
import { CLI_HELP_REFERENCE } from "../cli/reference.js";
|
|
5
5
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
6
6
|
import { getBaseDataDir, getIsContainerized } from "../config/env-registry.js";
|
|
7
|
-
import { getConfig
|
|
7
|
+
import { getConfig } from "../config/loader.js";
|
|
8
8
|
import { skillFlagKey } from "../config/skill-state.js";
|
|
9
9
|
import { loadSkillCatalog, type SkillSummary } from "../config/skills.js";
|
|
10
|
-
import {
|
|
10
|
+
import { listConnections } from "../oauth/oauth-store.js";
|
|
11
11
|
import { resolveBundledDir } from "../util/bundled-asset.js";
|
|
12
12
|
import { getLogger } from "../util/logger.js";
|
|
13
13
|
import {
|
|
@@ -109,7 +109,11 @@ export function isOnboardingComplete(): boolean {
|
|
|
109
109
|
* 3. If BOOTSTRAP.md exists, append first-run ritual instructions
|
|
110
110
|
* 4. Append skills catalog from ~/.vellum/workspace/skills
|
|
111
111
|
*/
|
|
112
|
-
export
|
|
112
|
+
export interface BuildSystemPromptOptions {
|
|
113
|
+
hasNoClient?: boolean;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
113
117
|
const soulPath = getWorkspacePromptPath("SOUL.md");
|
|
114
118
|
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
115
119
|
const userPath = getWorkspacePromptPath("USER.md");
|
|
@@ -156,13 +160,14 @@ export function buildSystemPrompt(): string {
|
|
|
156
160
|
);
|
|
157
161
|
}
|
|
158
162
|
if (getIsContainerized()) parts.push(buildContainerizedSection());
|
|
159
|
-
|
|
163
|
+
const hasNoClient = options?.hasNoClient ?? false;
|
|
164
|
+
parts.push(buildConfigSection(hasNoClient));
|
|
160
165
|
parts.push(buildCliReferenceSection());
|
|
161
166
|
parts.push(buildPostToolResponseSection());
|
|
162
167
|
parts.push(buildExternalCommsIdentitySection());
|
|
163
168
|
parts.push(buildChannelAwarenessSection());
|
|
164
169
|
const config = getConfig();
|
|
165
|
-
parts.push(buildToolPermissionSection());
|
|
170
|
+
if (!hasNoClient) parts.push(buildToolPermissionSection());
|
|
166
171
|
parts.push(buildTaskScheduleReminderRoutingSection());
|
|
167
172
|
if (
|
|
168
173
|
isAssistantFeatureFlagEnabled(
|
|
@@ -181,9 +186,9 @@ export function buildSystemPrompt(): string {
|
|
|
181
186
|
if (!isOnboardingComplete()) {
|
|
182
187
|
parts.push(buildStarterTaskPlaybookSection());
|
|
183
188
|
}
|
|
184
|
-
parts.push(buildSystemPermissionSection());
|
|
189
|
+
if (!hasNoClient) parts.push(buildSystemPermissionSection());
|
|
185
190
|
parts.push(buildSwarmGuidanceSection());
|
|
186
|
-
parts.push(buildAccessPreferenceSection());
|
|
191
|
+
parts.push(buildAccessPreferenceSection(hasNoClient));
|
|
187
192
|
parts.push(buildIntegrationSection());
|
|
188
193
|
parts.push(buildMemoryPersistenceSection());
|
|
189
194
|
parts.push(buildMemoryRecallSection());
|
|
@@ -278,7 +283,7 @@ function buildAttachmentSection(): string {
|
|
|
278
283
|
"",
|
|
279
284
|
'Example: `<vellum-attachment source="sandbox" path="scratch/chart.png" />`',
|
|
280
285
|
"",
|
|
281
|
-
"Limits:
|
|
286
|
+
"Limits: 20 MB per attachment. Tool outputs that produce image or file content blocks are also automatically converted into attachments.",
|
|
282
287
|
"",
|
|
283
288
|
"### Inline Images and GIFs",
|
|
284
289
|
"Embed images/GIFs inline using markdown: ``. Do NOT wrap in code fences.",
|
|
@@ -363,13 +368,11 @@ export function buildVoiceSetupRoutingSection(): string {
|
|
|
363
368
|
return [
|
|
364
369
|
"## Routing: Voice Setup & Troubleshooting",
|
|
365
370
|
"",
|
|
366
|
-
"Voice features include push-to-talk (PTT)
|
|
371
|
+
"Voice features include push-to-talk (PTT) and text-to-speech.",
|
|
367
372
|
"",
|
|
368
373
|
"### Quick changes — use `voice_config_update` directly",
|
|
369
374
|
'- "Change my PTT key to ctrl" — call `voice_config_update` with `setting: "activation_key"`',
|
|
370
|
-
'- "
|
|
371
|
-
'- "Set my wake word to jarvis" — call `voice_config_update` with `setting: "wake_word_keyword"`',
|
|
372
|
-
'- "Set wake word timeout to 30 seconds" — call `voice_config_update` with `setting: "wake_word_timeout"`',
|
|
375
|
+
'- "Set conversation timeout to 30 seconds" — call `voice_config_update` with `setting: "conversation_timeout"`',
|
|
373
376
|
"",
|
|
374
377
|
"For simple setting changes, use the tool directly without loading the voice-setup skill.",
|
|
375
378
|
"",
|
|
@@ -379,15 +382,14 @@ export function buildVoiceSetupRoutingSection(): string {
|
|
|
379
382
|
"**Trigger phrases:**",
|
|
380
383
|
'- "Help me set up voice"',
|
|
381
384
|
'- "Set up push-to-talk"',
|
|
382
|
-
'- "Configure voice / PTT
|
|
385
|
+
'- "Configure voice / PTT"',
|
|
383
386
|
'- "PTT isn\'t working" / "push-to-talk not working"',
|
|
384
387
|
'- "Recording but no text"',
|
|
385
|
-
'- "Wake word not detecting"',
|
|
386
388
|
'- "Microphone not working"',
|
|
387
389
|
'- "Set up ElevenLabs" / "configure TTS"',
|
|
388
390
|
"",
|
|
389
391
|
"### Disambiguation",
|
|
390
|
-
"- Voice setup (this skill) = **local PTT,
|
|
392
|
+
"- Voice setup (this skill) = **local PTT, microphone permissions** on the Mac desktop app.",
|
|
391
393
|
"- Phone calls skill = **Twilio-powered voice calls** over the phone network. Completely separate.",
|
|
392
394
|
'- If the user says "voice" in the context of phone calls or Twilio, load `phone-calls` instead.',
|
|
393
395
|
].join("\n");
|
|
@@ -418,7 +420,7 @@ export function buildPhoneCallsRoutingSection(): string {
|
|
|
418
420
|
"",
|
|
419
421
|
"### Exclusivity rules",
|
|
420
422
|
"- Do NOT improvise Twilio setup instructions from general knowledge — always load the skill first.",
|
|
421
|
-
"- Do NOT confuse with voice-setup (local PTT/
|
|
423
|
+
"- Do NOT confuse with voice-setup (local PTT/microphone) or guardian-verify-setup (channel verification).",
|
|
422
424
|
'- If the user says "voice" in the context of phone calls or Twilio, load phone-calls, not voice-setup.',
|
|
423
425
|
"- For guardian voice verification specifically, load guardian-verify-setup instead.",
|
|
424
426
|
].join("\n");
|
|
@@ -572,7 +574,23 @@ export function buildSwarmGuidanceSection(): string {
|
|
|
572
574
|
].join("\n");
|
|
573
575
|
}
|
|
574
576
|
|
|
575
|
-
function buildAccessPreferenceSection(): string {
|
|
577
|
+
function buildAccessPreferenceSection(hasNoClient: boolean): string {
|
|
578
|
+
if (hasNoClient) {
|
|
579
|
+
return [
|
|
580
|
+
"## External Service Access Preference",
|
|
581
|
+
"",
|
|
582
|
+
"When interacting with external services (GitHub, Slack, Linear, Jira, cloud providers, etc.),",
|
|
583
|
+
"follow this priority order:",
|
|
584
|
+
"",
|
|
585
|
+
"1. **Sandbox first (`bash`)** — Always try to do things in your own sandbox environment first.",
|
|
586
|
+
" If a tool (git, curl, jq, etc.) is not installed, install it yourself using `bash`",
|
|
587
|
+
" (e.g. `apt-get install -y git`). The sandbox is your own machine — you have full control.",
|
|
588
|
+
"2. **web_fetch** — For public endpoints or simple API calls that don't need auth.",
|
|
589
|
+
"3. **Browser automation as last resort** — Only when the task genuinely requires a browser",
|
|
590
|
+
" (e.g., no API exists, visual interaction needed, or OAuth consent screen).",
|
|
591
|
+
].join("\n");
|
|
592
|
+
}
|
|
593
|
+
|
|
576
594
|
return [
|
|
577
595
|
"## External Service Access Preference",
|
|
578
596
|
"",
|
|
@@ -609,38 +627,38 @@ function buildAccessPreferenceSection(): string {
|
|
|
609
627
|
"",
|
|
610
628
|
"### Foreground Computer Use — Last Resort",
|
|
611
629
|
"",
|
|
612
|
-
"
|
|
613
|
-
"
|
|
630
|
+
"Computer use tools (clicking, typing, scrolling) take over the user's cursor and keyboard.",
|
|
631
|
+
"They are disruptive and should be your LAST resort. Prefer this hierarchy:",
|
|
614
632
|
"",
|
|
615
633
|
"1. **CLI tools / osascript** — Use `host_bash` with shell commands or `osascript` with",
|
|
616
634
|
" AppleScript to accomplish tasks in the background without interrupting the user.",
|
|
617
635
|
"2. **Background computer use** — If you must interact with a GUI app, prefer AppleScript",
|
|
618
636
|
' automation (e.g. `tell application "Safari" to set URL of current tab to ...`).',
|
|
619
|
-
"3. **Foreground computer use** — Only
|
|
620
|
-
"
|
|
621
|
-
"
|
|
637
|
+
"3. **Foreground computer use** — Only use computer use tools when the task genuinely",
|
|
638
|
+
" cannot be done any other way (e.g. complex multi-step GUI interactions with no scripting",
|
|
639
|
+
" support) or the user explicitly asks you to take control.",
|
|
622
640
|
]
|
|
623
641
|
: []),
|
|
624
642
|
].join("\n");
|
|
625
643
|
}
|
|
626
644
|
|
|
627
645
|
function buildIntegrationSection(): string {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
646
|
+
let connections: { providerKey: string; accountInfo?: string | null }[];
|
|
647
|
+
try {
|
|
648
|
+
connections = listConnections().filter((c) => c.status === "active");
|
|
649
|
+
} catch {
|
|
650
|
+
// DB not available — no connected services to show
|
|
651
|
+
return "";
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (connections.length === 0) return "";
|
|
634
655
|
|
|
635
|
-
const raw = loadRawConfig();
|
|
636
656
|
const lines = ["## Connected Services", ""];
|
|
637
|
-
for (const
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
const state = acctInfo ? `Connected (${acctInfo})` : "Connected";
|
|
643
|
-
lines.push(`- **${cred.service}**: ${state}`);
|
|
657
|
+
for (const conn of connections) {
|
|
658
|
+
const state = conn.accountInfo
|
|
659
|
+
? `Connected (${conn.accountInfo})`
|
|
660
|
+
: "Connected";
|
|
661
|
+
lines.push(`- **${conn.providerKey}**: ${state}`);
|
|
644
662
|
}
|
|
645
663
|
|
|
646
664
|
return lines.join("\n");
|
|
@@ -751,10 +769,12 @@ function buildPostToolResponseSection(): string {
|
|
|
751
769
|
" → Call document_create",
|
|
752
770
|
"",
|
|
753
771
|
"For permission-gated tools, send one short context sentence immediately before the tool call so the user can make an informed allow/deny decision.",
|
|
772
|
+
"",
|
|
773
|
+
'**Reason field:** For every tool call, include a `reason` parameter — a brief, non-technical explanation of what you are doing and why. This is shown to the user as a live status update. Use simple language a non-technical person would understand (e.g. "Checking your project settings" not "file_read config.ts").',
|
|
754
774
|
].join("\n");
|
|
755
775
|
}
|
|
756
776
|
|
|
757
|
-
function buildConfigSection(): string {
|
|
777
|
+
function buildConfigSection(hasNoClient: boolean): string {
|
|
758
778
|
// Always use `file_edit` (not `host_file_edit`) for workspace files — file_edit
|
|
759
779
|
// handles sandbox path mapping internally, and host_file_edit is permission-gated
|
|
760
780
|
// which would trigger approval prompts for routine workspace updates.
|
|
@@ -763,10 +783,14 @@ function buildConfigSection(): string {
|
|
|
763
783
|
const config = getConfig();
|
|
764
784
|
const configPreamble = `Your configuration directory is \`${hostWorkspaceDir}/\`.`;
|
|
765
785
|
|
|
786
|
+
const fileToolGuidance = hasNoClient
|
|
787
|
+
? `${configPreamble} **Always use \`file_read\` and \`file_edit\` for these files** — they are inside your sandbox working directory:`
|
|
788
|
+
: `${configPreamble} **Always use \`file_read\` and \`file_edit\` (not \`host_file_read\` / \`host_file_edit\`) for these files** — they are inside your sandbox working directory and do not require host access or user approval:`;
|
|
789
|
+
|
|
766
790
|
return [
|
|
767
791
|
"## Configuration",
|
|
768
792
|
`- **Active model**: \`${config.model}\` (provider: ${config.provider})`,
|
|
769
|
-
|
|
793
|
+
fileToolGuidance,
|
|
770
794
|
"",
|
|
771
795
|
"- `IDENTITY.md` — Your name, nature, personality, and emoji. Updated during the first-run ritual.",
|
|
772
796
|
"- `SOUL.md` — Core principles, personality, and evolution guidance. Your behavioral foundation.",
|
|
@@ -801,7 +825,13 @@ function buildConfigSection(): string {
|
|
|
801
825
|
"- They rename you or change your role",
|
|
802
826
|
"- Your avatar appearance changes (update the `## Avatar` section with a description of the new look)",
|
|
803
827
|
"",
|
|
804
|
-
|
|
828
|
+
...(hasNoClient
|
|
829
|
+
? [
|
|
830
|
+
"When reading or updating workspace files, always use the sandbox tools (`file_read`, `file_edit`).",
|
|
831
|
+
]
|
|
832
|
+
: [
|
|
833
|
+
"When reading or updating workspace files, always use the sandbox tools (`file_read`, `file_edit`). Never use `host_file_read` or `host_file_edit` for workspace files — those are for host-only resources outside your workspace.",
|
|
834
|
+
]),
|
|
805
835
|
"",
|
|
806
836
|
"When updating, read the file first, then make a targeted edit. Include all useful information, but don't bloat the files over time",
|
|
807
837
|
].join("\n");
|
|
@@ -818,7 +848,7 @@ export function buildCliReferenceSection(): string {
|
|
|
818
848
|
"The `assistant` CLI is installed on the user's machine and available via `bash`.",
|
|
819
849
|
"For account and authentication work, prefer real `assistant` CLI workflows over any legacy account-record abstraction.",
|
|
820
850
|
"- Use `assistant credentials ...` for stored secrets and credential metadata.",
|
|
821
|
-
"- Use `assistant oauth token <
|
|
851
|
+
"- Use `assistant oauth connections token <provider-key>` for connected integration tokens.",
|
|
822
852
|
"- Use `assistant mcp auth <name>` when an MCP server needs OAuth login.",
|
|
823
853
|
"- Use `assistant platform status` for platform-linked deployment and auth context.",
|
|
824
854
|
"- If a bundled skill documents a service-specific `assistant <service>` auth or session flow, follow that CLI exactly.",
|
|
@@ -992,10 +1022,5 @@ function formatSkillsCatalog(skills: SkillSummary[]): string {
|
|
|
992
1022
|
"",
|
|
993
1023
|
lines.join("\n"),
|
|
994
1024
|
"",
|
|
995
|
-
"### Installing additional skills",
|
|
996
|
-
"If `skill_load` fails because a skill is not found, additional first-party skills may be available in the Vellum catalog.",
|
|
997
|
-
"Use `bash` to discover and install them:",
|
|
998
|
-
"- `assistant skills list` — list all available catalog skills",
|
|
999
|
-
"- `assistant skills install <skill-id>` — install a skill, then retry `skill_load`",
|
|
1000
1025
|
].join("\n");
|
|
1001
1026
|
}
|
|
@@ -63,6 +63,20 @@ function isToolUseBlock(block: unknown): block is Anthropic.ToolUseBlockParam {
|
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/** Type-guard for server_tool_use blocks (e.g. native web search). */
|
|
67
|
+
function isServerToolUseBlock(block: unknown): block is {
|
|
68
|
+
type: "server_tool_use";
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
input: unknown;
|
|
72
|
+
} {
|
|
73
|
+
return (
|
|
74
|
+
typeof block === "object" &&
|
|
75
|
+
block != null &&
|
|
76
|
+
(block as { type: string }).type === "server_tool_use"
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
/** Type-guard for tool_result blocks in Anthropic-formatted content. */
|
|
67
81
|
function isToolResultBlock(
|
|
68
82
|
block: unknown,
|
|
@@ -74,6 +88,19 @@ function isToolResultBlock(
|
|
|
74
88
|
);
|
|
75
89
|
}
|
|
76
90
|
|
|
91
|
+
/** Type-guard for web_search_tool_result blocks. */
|
|
92
|
+
function isWebSearchToolResultBlock(block: unknown): block is {
|
|
93
|
+
type: "web_search_tool_result";
|
|
94
|
+
tool_use_id: string;
|
|
95
|
+
content: unknown;
|
|
96
|
+
} {
|
|
97
|
+
return (
|
|
98
|
+
typeof block === "object" &&
|
|
99
|
+
block != null &&
|
|
100
|
+
(block as { type: string }).type === "web_search_tool_result"
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
77
104
|
/**
|
|
78
105
|
* Build a short diagnostic summary of a message array for error logging.
|
|
79
106
|
* Shows role + block types (with tool_use/tool_result IDs) for each message.
|
|
@@ -84,8 +111,12 @@ function summarizeMessages(messages: Anthropic.MessageParam[]): string[] {
|
|
|
84
111
|
const blockDescs = content.map((b) => {
|
|
85
112
|
const bt = (b as { type: string }).type;
|
|
86
113
|
if (bt === "tool_use") return `tool_use(${(b as { id: string }).id})`;
|
|
114
|
+
if (bt === "server_tool_use")
|
|
115
|
+
return `server_tool_use(${(b as { id: string }).id})`;
|
|
87
116
|
if (bt === "tool_result")
|
|
88
117
|
return `tool_result(${(b as { tool_use_id: string }).tool_use_id})`;
|
|
118
|
+
if (bt === "web_search_tool_result")
|
|
119
|
+
return `web_search_tool_result(${(b as { tool_use_id: string }).tool_use_id})`;
|
|
89
120
|
return bt;
|
|
90
121
|
});
|
|
91
122
|
return `[${idx}] ${m.role}: ${blockDescs.join(", ") || "(empty)"}`;
|
|
@@ -103,29 +134,70 @@ function buildSyntheticToolResult(
|
|
|
103
134
|
};
|
|
104
135
|
}
|
|
105
136
|
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
):
|
|
137
|
+
function buildSyntheticWebSearchToolResult(
|
|
138
|
+
toolUseId: string,
|
|
139
|
+
): Anthropic.ContentBlockParam {
|
|
140
|
+
return {
|
|
141
|
+
type: "web_search_tool_result",
|
|
142
|
+
tool_use_id: toolUseId,
|
|
143
|
+
content: {
|
|
144
|
+
type: "web_search_tool_result_error",
|
|
145
|
+
error_code: "unavailable",
|
|
146
|
+
},
|
|
147
|
+
} as unknown as Anthropic.ContentBlockParam;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Build the appropriate synthetic result block based on whether the ID is for a server tool or regular tool. */
|
|
151
|
+
function buildSyntheticResult(
|
|
152
|
+
toolUseId: string,
|
|
153
|
+
serverToolIds: ReadonlySet<string>,
|
|
154
|
+
): Anthropic.ContentBlockParam {
|
|
155
|
+
if (serverToolIds.has(toolUseId)) {
|
|
156
|
+
return buildSyntheticWebSearchToolResult(toolUseId);
|
|
157
|
+
}
|
|
158
|
+
return buildSyntheticToolResult(toolUseId);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function getOrderedToolUseIds(content: Anthropic.ContentBlockParam[]): {
|
|
162
|
+
ids: string[];
|
|
163
|
+
serverToolIds: Set<string>;
|
|
164
|
+
} {
|
|
109
165
|
const ids: string[] = [];
|
|
110
166
|
const seen = new Set<string>();
|
|
167
|
+
const serverToolIds = new Set<string>();
|
|
111
168
|
for (const block of content) {
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
169
|
+
if (isToolUseBlock(block)) {
|
|
170
|
+
if (!seen.has(block.id)) {
|
|
171
|
+
seen.add(block.id);
|
|
172
|
+
ids.push(block.id);
|
|
173
|
+
}
|
|
174
|
+
} else if (isServerToolUseBlock(block)) {
|
|
175
|
+
if (!seen.has(block.id)) {
|
|
176
|
+
seen.add(block.id);
|
|
177
|
+
ids.push(block.id);
|
|
178
|
+
serverToolIds.add(block.id);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
116
181
|
}
|
|
117
|
-
return ids;
|
|
182
|
+
return { ids, serverToolIds };
|
|
118
183
|
}
|
|
119
184
|
|
|
120
185
|
function hasOrderedToolResultPrefix(
|
|
121
186
|
content: Anthropic.ContentBlockParam[],
|
|
122
187
|
orderedToolUseIds: string[],
|
|
188
|
+
serverToolIds: ReadonlySet<string>,
|
|
123
189
|
): boolean {
|
|
124
190
|
if (content.length < orderedToolUseIds.length) return false;
|
|
125
191
|
for (let idx = 0; idx < orderedToolUseIds.length; idx++) {
|
|
126
192
|
const block = content[idx];
|
|
127
|
-
|
|
128
|
-
if (
|
|
193
|
+
const expectedId = orderedToolUseIds[idx];
|
|
194
|
+
if (serverToolIds.has(expectedId)) {
|
|
195
|
+
if (!isWebSearchToolResultBlock(block)) return false;
|
|
196
|
+
if (block.tool_use_id !== expectedId) return false;
|
|
197
|
+
} else {
|
|
198
|
+
if (!isToolResultBlock(block)) return false;
|
|
199
|
+
if (block.tool_use_id !== expectedId) return false;
|
|
200
|
+
}
|
|
129
201
|
}
|
|
130
202
|
return true;
|
|
131
203
|
}
|
|
@@ -134,14 +206,15 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
134
206
|
pairedContent: Anthropic.ContentBlockParam[];
|
|
135
207
|
carryoverContent: Anthropic.ContentBlockParam[];
|
|
136
208
|
toolUseIds: string[];
|
|
209
|
+
serverToolIds: Set<string>;
|
|
137
210
|
} {
|
|
138
211
|
const leading: Anthropic.ContentBlockParam[] = [];
|
|
139
|
-
const toolUseBlocks: Anthropic.
|
|
212
|
+
const toolUseBlocks: Anthropic.ContentBlockParam[] = [];
|
|
140
213
|
const carryover: Anthropic.ContentBlockParam[] = [];
|
|
141
214
|
let seenToolUse = false;
|
|
142
215
|
|
|
143
216
|
for (const block of content) {
|
|
144
|
-
if (isToolUseBlock(block)) {
|
|
217
|
+
if (isToolUseBlock(block) || isServerToolUseBlock(block)) {
|
|
145
218
|
seenToolUse = true;
|
|
146
219
|
toolUseBlocks.push(block);
|
|
147
220
|
continue;
|
|
@@ -158,6 +231,7 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
158
231
|
pairedContent: content,
|
|
159
232
|
carryoverContent: [],
|
|
160
233
|
toolUseIds: [],
|
|
234
|
+
serverToolIds: new Set(),
|
|
161
235
|
};
|
|
162
236
|
}
|
|
163
237
|
|
|
@@ -165,16 +239,19 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
165
239
|
...leading,
|
|
166
240
|
...toolUseBlocks,
|
|
167
241
|
];
|
|
242
|
+
const { ids, serverToolIds } = getOrderedToolUseIds(pairedContent);
|
|
168
243
|
return {
|
|
169
244
|
pairedContent,
|
|
170
245
|
carryoverContent: carryover,
|
|
171
|
-
toolUseIds:
|
|
246
|
+
toolUseIds: ids,
|
|
247
|
+
serverToolIds,
|
|
172
248
|
};
|
|
173
249
|
}
|
|
174
250
|
|
|
175
251
|
function normalizeFollowingUserContent(
|
|
176
252
|
nextContent: Anthropic.ContentBlockParam[],
|
|
177
253
|
orderedToolUseIds: string[],
|
|
254
|
+
serverToolIds: ReadonlySet<string>,
|
|
178
255
|
): {
|
|
179
256
|
toolResultPrefix: Anthropic.ContentBlockParam[];
|
|
180
257
|
remainingContent: Anthropic.ContentBlockParam[];
|
|
@@ -182,24 +259,37 @@ function normalizeFollowingUserContent(
|
|
|
182
259
|
hadOrderedPrefix: boolean;
|
|
183
260
|
} {
|
|
184
261
|
const pendingIds = new Set(orderedToolUseIds);
|
|
185
|
-
const matchedById = new Map<string, Anthropic.
|
|
262
|
+
const matchedById = new Map<string, Anthropic.ContentBlockParam>();
|
|
186
263
|
const remaining: Anthropic.ContentBlockParam[] = [];
|
|
187
264
|
|
|
188
265
|
for (const block of nextContent) {
|
|
189
266
|
if (
|
|
190
267
|
isToolResultBlock(block) &&
|
|
191
268
|
pendingIds.has(block.tool_use_id) &&
|
|
192
|
-
!matchedById.has(block.tool_use_id)
|
|
269
|
+
!matchedById.has(block.tool_use_id) &&
|
|
270
|
+
!serverToolIds.has(block.tool_use_id)
|
|
193
271
|
) {
|
|
194
272
|
matchedById.set(block.tool_use_id, block);
|
|
195
273
|
continue;
|
|
196
274
|
}
|
|
275
|
+
if (
|
|
276
|
+
isWebSearchToolResultBlock(block) &&
|
|
277
|
+
pendingIds.has(block.tool_use_id) &&
|
|
278
|
+
!matchedById.has(block.tool_use_id) &&
|
|
279
|
+
serverToolIds.has(block.tool_use_id)
|
|
280
|
+
) {
|
|
281
|
+
matchedById.set(
|
|
282
|
+
block.tool_use_id,
|
|
283
|
+
block as unknown as Anthropic.ContentBlockParam,
|
|
284
|
+
);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
197
287
|
remaining.push(block);
|
|
198
288
|
}
|
|
199
289
|
|
|
200
290
|
const missingIds = orderedToolUseIds.filter((id) => !matchedById.has(id));
|
|
201
291
|
const orderedResults = orderedToolUseIds.map(
|
|
202
|
-
(id) => matchedById.get(id) ??
|
|
292
|
+
(id) => matchedById.get(id) ?? buildSyntheticResult(id, serverToolIds),
|
|
203
293
|
);
|
|
204
294
|
|
|
205
295
|
return {
|
|
@@ -209,6 +299,7 @@ function normalizeFollowingUserContent(
|
|
|
209
299
|
hadOrderedPrefix: hasOrderedToolResultPrefix(
|
|
210
300
|
nextContent,
|
|
211
301
|
orderedToolUseIds,
|
|
302
|
+
serverToolIds,
|
|
212
303
|
),
|
|
213
304
|
};
|
|
214
305
|
}
|
|
@@ -237,7 +328,7 @@ function ensureToolPairing(
|
|
|
237
328
|
}
|
|
238
329
|
|
|
239
330
|
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
240
|
-
const { pairedContent, carryoverContent, toolUseIds } =
|
|
331
|
+
const { pairedContent, carryoverContent, toolUseIds, serverToolIds } =
|
|
241
332
|
splitAssistantForToolPairing(content);
|
|
242
333
|
|
|
243
334
|
if (toolUseIds.length === 0) {
|
|
@@ -246,7 +337,7 @@ function ensureToolPairing(
|
|
|
246
337
|
continue;
|
|
247
338
|
}
|
|
248
339
|
|
|
249
|
-
// Assistant message — push the paired portion (pre-tool text + tool_use blocks)
|
|
340
|
+
// Assistant message — push the paired portion (pre-tool text + tool_use/server_tool_use blocks)
|
|
250
341
|
result.push({
|
|
251
342
|
role: "assistant" as const,
|
|
252
343
|
content: pairedContent,
|
|
@@ -267,7 +358,11 @@ function ensureToolPairing(
|
|
|
267
358
|
const next = messages[i + 1];
|
|
268
359
|
if (next && next.role === "user") {
|
|
269
360
|
const nextContent = Array.isArray(next.content) ? next.content : [];
|
|
270
|
-
const normalized = normalizeFollowingUserContent(
|
|
361
|
+
const normalized = normalizeFollowingUserContent(
|
|
362
|
+
nextContent,
|
|
363
|
+
toolUseIds,
|
|
364
|
+
serverToolIds,
|
|
365
|
+
);
|
|
271
366
|
if (normalized.missingIds.length > 0) {
|
|
272
367
|
log.warn(
|
|
273
368
|
{
|
|
@@ -332,7 +427,9 @@ function ensureToolPairing(
|
|
|
332
427
|
);
|
|
333
428
|
result.push({
|
|
334
429
|
role: "user" as const,
|
|
335
|
-
content: toolUseIds.map((id) =>
|
|
430
|
+
content: toolUseIds.map((id) =>
|
|
431
|
+
buildSyntheticResult(id, serverToolIds),
|
|
432
|
+
),
|
|
336
433
|
});
|
|
337
434
|
|
|
338
435
|
// If the assistant contained collapsed post-tool text, preserve it as a
|
|
@@ -353,17 +450,29 @@ function ensureToolPairing(
|
|
|
353
450
|
const m = result[j];
|
|
354
451
|
if (m.role !== "assistant") continue;
|
|
355
452
|
const c = Array.isArray(m.content) ? m.content : [];
|
|
356
|
-
const ids =
|
|
357
|
-
|
|
453
|
+
const { ids: validationIds, serverToolIds: validationServerToolIds } =
|
|
454
|
+
getOrderedToolUseIds(c);
|
|
455
|
+
if (validationIds.length === 0) continue;
|
|
358
456
|
|
|
359
457
|
const nxt = result[j + 1];
|
|
360
458
|
const nxtContent =
|
|
361
459
|
nxt && nxt.role === "user" && Array.isArray(nxt.content)
|
|
362
460
|
? nxt.content
|
|
363
461
|
: [];
|
|
364
|
-
if (
|
|
365
|
-
|
|
462
|
+
if (
|
|
463
|
+
!hasOrderedToolResultPrefix(
|
|
464
|
+
nxtContent,
|
|
465
|
+
validationIds,
|
|
466
|
+
validationServerToolIds,
|
|
467
|
+
)
|
|
468
|
+
) {
|
|
469
|
+
const unmatchedIds = validationIds.filter((id, idx) => {
|
|
366
470
|
const block = nxtContent[idx];
|
|
471
|
+
if (validationServerToolIds.has(id)) {
|
|
472
|
+
return !(
|
|
473
|
+
isWebSearchToolResultBlock(block) && block.tool_use_id === id
|
|
474
|
+
);
|
|
475
|
+
}
|
|
367
476
|
return !(isToolResultBlock(block) && block.tool_use_id === id);
|
|
368
477
|
});
|
|
369
478
|
log.error(
|
|
@@ -16,6 +16,10 @@ export interface GeminiProviderOptions {
|
|
|
16
16
|
streamTimeoutMs?: number;
|
|
17
17
|
/** When set, routes requests through the managed proxy at this base URL. */
|
|
18
18
|
managedBaseUrl?: string;
|
|
19
|
+
/** Vertex AI project placeholder (used with managed proxy). */
|
|
20
|
+
vertexProject?: string;
|
|
21
|
+
/** Vertex AI location placeholder (used with managed proxy). */
|
|
22
|
+
vertexLocation?: string;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export class GeminiProvider implements Provider {
|
|
@@ -29,12 +33,17 @@ export class GeminiProvider implements Provider {
|
|
|
29
33
|
model: string,
|
|
30
34
|
options: GeminiProviderOptions = {},
|
|
31
35
|
) {
|
|
32
|
-
this.client =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
this.client = options.managedBaseUrl
|
|
37
|
+
? new GoogleGenAI({
|
|
38
|
+
vertexai: true,
|
|
39
|
+
project: options.vertexProject ?? "proxy",
|
|
40
|
+
location: options.vertexLocation ?? "us-central1",
|
|
41
|
+
httpOptions: {
|
|
42
|
+
baseUrl: options.managedBaseUrl,
|
|
43
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
: new GoogleGenAI({ apiKey });
|
|
38
47
|
this.model = model;
|
|
39
48
|
this.streamTimeoutMs = options.streamTimeoutMs ?? 300_000;
|
|
40
49
|
}
|
|
@@ -29,12 +29,12 @@ export const MANAGED_PROVIDER_META: Record<string, ManagedProviderMeta> = {
|
|
|
29
29
|
anthropic: {
|
|
30
30
|
name: "anthropic",
|
|
31
31
|
managed: true,
|
|
32
|
-
proxyPath: "/v1/runtime-proxy/
|
|
32
|
+
proxyPath: "/v1/runtime-proxy/vertex",
|
|
33
33
|
},
|
|
34
34
|
gemini: {
|
|
35
35
|
name: "gemini",
|
|
36
36
|
managed: true,
|
|
37
|
-
proxyPath: "/v1/runtime-proxy/
|
|
37
|
+
proxyPath: "/v1/runtime-proxy/vertex",
|
|
38
38
|
},
|
|
39
39
|
fireworks: {
|
|
40
40
|
name: "fireworks",
|