@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
package/src/daemon/session.ts
CHANGED
|
@@ -35,18 +35,23 @@ import {
|
|
|
35
35
|
} from "../events/tool-profiling-listener.js";
|
|
36
36
|
import { registerToolTraceListener } from "../events/tool-trace-listener.js";
|
|
37
37
|
import { getHookManager } from "../hooks/manager.js";
|
|
38
|
+
import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
38
39
|
import { PermissionPrompter } from "../permissions/prompter.js";
|
|
39
40
|
import { SecretPrompter } from "../permissions/secret-prompter.js";
|
|
41
|
+
import { patternMatchesCandidate } from "../permissions/trust-store.js";
|
|
40
42
|
import type { UserDecision } from "../permissions/types.js";
|
|
41
43
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
42
44
|
import type { Message } from "../providers/types.js";
|
|
43
45
|
import type { Provider } from "../providers/types.js";
|
|
44
46
|
import type { TrustClass } from "../runtime/actor-trust-resolver.js";
|
|
45
47
|
import type { AuthContext } from "../runtime/auth/types.js";
|
|
48
|
+
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
46
49
|
import * as approvalOverrides from "../runtime/session-approval-overrides.js";
|
|
47
50
|
import { ToolExecutor } from "../tools/executor.js";
|
|
48
51
|
import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
|
|
49
52
|
import { HostBashProxy } from "./host-bash-proxy.js";
|
|
53
|
+
import type { CuObservationResult } from "./host-cu-proxy.js";
|
|
54
|
+
import { HostCuProxy } from "./host-cu-proxy.js";
|
|
50
55
|
import { HostFileProxy } from "./host-file-proxy.js";
|
|
51
56
|
import type {
|
|
52
57
|
ServerMessage,
|
|
@@ -161,6 +166,7 @@ export class Session {
|
|
|
161
166
|
/** @internal */ taskRunId?: string;
|
|
162
167
|
/** @internal */ callSessionId?: string;
|
|
163
168
|
/** @internal */ hostBashProxy?: HostBashProxy;
|
|
169
|
+
/** @internal */ hostCuProxy?: HostCuProxy;
|
|
164
170
|
/** @internal */ hostFileProxy?: HostFileProxy;
|
|
165
171
|
/** @internal */ readonly queue = new MessageQueue();
|
|
166
172
|
/** @internal */ currentActiveSurfaceId?: string;
|
|
@@ -199,10 +205,6 @@ export class Session {
|
|
|
199
205
|
actions?: Array<{ id: string; label: string; style?: string }>;
|
|
200
206
|
display?: string;
|
|
201
207
|
}> = [];
|
|
202
|
-
/** @internal */ onEscalateToComputerUse?: (
|
|
203
|
-
task: string,
|
|
204
|
-
sourceSessionId: string,
|
|
205
|
-
) => boolean;
|
|
206
208
|
/** @internal */ workspaceTopLevelContext: string | null = null;
|
|
207
209
|
/** @internal */ workspaceTopLevelDirty = true;
|
|
208
210
|
public readonly traceEmitter: TraceEmitter;
|
|
@@ -324,7 +326,7 @@ export class Session {
|
|
|
324
326
|
const resolved = {
|
|
325
327
|
systemPrompt: hasSystemPromptOverride
|
|
326
328
|
? systemPrompt
|
|
327
|
-
: buildSystemPrompt(),
|
|
329
|
+
: buildSystemPrompt({ hasNoClient: this.hasNoClient }),
|
|
328
330
|
maxTokens: configuredMaxTokens,
|
|
329
331
|
};
|
|
330
332
|
return resolved;
|
|
@@ -346,7 +348,7 @@ export class Session {
|
|
|
346
348
|
);
|
|
347
349
|
this.contextWindowManager = new ContextWindowManager({
|
|
348
350
|
provider,
|
|
349
|
-
systemPrompt,
|
|
351
|
+
systemPrompt: () => resolveSystemPromptCallback([]).systemPrompt,
|
|
350
352
|
config: config.contextWindow,
|
|
351
353
|
});
|
|
352
354
|
|
|
@@ -388,6 +390,7 @@ export class Session {
|
|
|
388
390
|
this.traceEmitter.updateSender(sendToClient);
|
|
389
391
|
if (!opts?.skipProxySenderUpdate) {
|
|
390
392
|
this.hostBashProxy?.updateSender(sendToClient, !hasNoClient);
|
|
393
|
+
this.hostCuProxy?.updateSender(sendToClient, !hasNoClient);
|
|
391
394
|
this.hostFileProxy?.updateSender(sendToClient, !hasNoClient);
|
|
392
395
|
}
|
|
393
396
|
}
|
|
@@ -400,6 +403,7 @@ export class Session {
|
|
|
400
403
|
/** Mark host proxies as unavailable so tool execution uses local fallback. */
|
|
401
404
|
clearProxyAvailability(): void {
|
|
402
405
|
this.hostBashProxy?.updateSender(this.sendToClient, false);
|
|
406
|
+
this.hostCuProxy?.updateSender(this.sendToClient, false);
|
|
403
407
|
this.hostFileProxy?.updateSender(this.sendToClient, false);
|
|
404
408
|
}
|
|
405
409
|
|
|
@@ -407,6 +411,7 @@ export class Session {
|
|
|
407
411
|
restoreProxyAvailability(): void {
|
|
408
412
|
if (!this.hasNoClient) {
|
|
409
413
|
this.hostBashProxy?.updateSender(this.sendToClient, true);
|
|
414
|
+
this.hostCuProxy?.updateSender(this.sendToClient, true);
|
|
410
415
|
this.hostFileProxy?.updateSender(this.sendToClient, true);
|
|
411
416
|
}
|
|
412
417
|
}
|
|
@@ -415,16 +420,6 @@ export class Session {
|
|
|
415
420
|
this.sandboxOverride = enabled;
|
|
416
421
|
}
|
|
417
422
|
|
|
418
|
-
setEscalationHandler(
|
|
419
|
-
handler: (task: string, sourceSessionId: string) => boolean,
|
|
420
|
-
): void {
|
|
421
|
-
this.onEscalateToComputerUse = handler;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
hasEscalationHandler(): boolean {
|
|
425
|
-
return this.onEscalateToComputerUse !== undefined;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
423
|
isProcessing(): boolean {
|
|
429
424
|
return this.processing;
|
|
430
425
|
}
|
|
@@ -447,6 +442,7 @@ export class Session {
|
|
|
447
442
|
dispose(): void {
|
|
448
443
|
approvalOverrides.clearMode(this.conversationId);
|
|
449
444
|
this.hostBashProxy?.dispose();
|
|
445
|
+
this.hostCuProxy?.dispose();
|
|
450
446
|
this.hostFileProxy?.dispose();
|
|
451
447
|
disposeSession(this);
|
|
452
448
|
}
|
|
@@ -589,6 +585,122 @@ export class Session {
|
|
|
589
585
|
undefined,
|
|
590
586
|
"Resuming after approval",
|
|
591
587
|
);
|
|
588
|
+
|
|
589
|
+
// Cascade to other pending confirmations that match this decision
|
|
590
|
+
this.cascadePendingApprovals(requestId, decision, selectedPattern);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* After resolving one confirmation, auto-resolve other pending
|
|
595
|
+
* confirmations in the same conversation that match the decision.
|
|
596
|
+
*
|
|
597
|
+
* - allow_10m / allow_thread → approve ALL pending in conversation
|
|
598
|
+
* - always_allow / always_allow_high_risk → approve pattern-matching pending
|
|
599
|
+
* - always_deny → deny pattern-matching pending
|
|
600
|
+
* - allow / deny (one-time) → no cascading
|
|
601
|
+
*/
|
|
602
|
+
private cascadePendingApprovals(
|
|
603
|
+
primaryRequestId: string,
|
|
604
|
+
decision: UserDecision,
|
|
605
|
+
selectedPattern?: string,
|
|
606
|
+
): void {
|
|
607
|
+
// Single-action decisions don't cascade
|
|
608
|
+
if (decision === "allow" || decision === "deny") return;
|
|
609
|
+
|
|
610
|
+
const pendingRequestIds = this.prompter.getPendingRequestIds();
|
|
611
|
+
if (pendingRequestIds.length === 0) return;
|
|
612
|
+
|
|
613
|
+
for (const candidateId of pendingRequestIds) {
|
|
614
|
+
if (candidateId === primaryRequestId) continue;
|
|
615
|
+
|
|
616
|
+
const interaction = pendingInteractions.get(candidateId);
|
|
617
|
+
if (!interaction) continue;
|
|
618
|
+
if (interaction.conversationId !== this.conversationId) continue;
|
|
619
|
+
if (interaction.kind !== "confirmation") continue;
|
|
620
|
+
|
|
621
|
+
const cascadeResult = this.shouldCascade(
|
|
622
|
+
decision,
|
|
623
|
+
selectedPattern,
|
|
624
|
+
interaction.confirmationDetails,
|
|
625
|
+
);
|
|
626
|
+
if (!cascadeResult) continue;
|
|
627
|
+
|
|
628
|
+
// Consume from pending-interactions tracker
|
|
629
|
+
pendingInteractions.resolve(candidateId);
|
|
630
|
+
|
|
631
|
+
// Resolve via handleConfirmationResponse which emits events.
|
|
632
|
+
// Use simple "allow"/"deny" so the permission-checker won't save
|
|
633
|
+
// duplicate rules or re-activate temporary modes. Recursion
|
|
634
|
+
// terminates because allow/deny exit cascadePendingApprovals early.
|
|
635
|
+
this.handleConfirmationResponse(
|
|
636
|
+
candidateId,
|
|
637
|
+
cascadeResult.allow ? "allow" : "deny",
|
|
638
|
+
undefined,
|
|
639
|
+
undefined,
|
|
640
|
+
undefined,
|
|
641
|
+
{
|
|
642
|
+
source: "system",
|
|
643
|
+
causedByRequestId: primaryRequestId,
|
|
644
|
+
},
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
// Sync the canonical guardian request status for the cascaded request.
|
|
648
|
+
// Best-effort: canonical request tracking should not break the cascade flow.
|
|
649
|
+
try {
|
|
650
|
+
const targetStatus = cascadeResult.allow ? "approved" : "denied";
|
|
651
|
+
resolveCanonicalGuardianRequest(candidateId, "pending", {
|
|
652
|
+
status: targetStatus,
|
|
653
|
+
});
|
|
654
|
+
} catch {
|
|
655
|
+
// Ignore — canonical request tracking is best-effort
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Determine whether a pending confirmation should be auto-resolved
|
|
662
|
+
* based on the cascading decision and pattern.
|
|
663
|
+
*/
|
|
664
|
+
private shouldCascade(
|
|
665
|
+
decision: UserDecision,
|
|
666
|
+
selectedPattern: string | undefined,
|
|
667
|
+
details?: import("../runtime/pending-interactions.js").ConfirmationDetails,
|
|
668
|
+
): { allow: boolean } | null {
|
|
669
|
+
// Temporary overrides apply to the entire conversation
|
|
670
|
+
if (decision === "allow_10m" || decision === "allow_thread") {
|
|
671
|
+
return { allow: true };
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Persistent allow: cascade if the pattern matches any allowlist candidate.
|
|
675
|
+
// "always_allow" must NOT cascade to high-risk pending confirmations —
|
|
676
|
+
// only "always_allow_high_risk" has consent for those.
|
|
677
|
+
if (
|
|
678
|
+
(decision === "always_allow" || decision === "always_allow_high_risk") &&
|
|
679
|
+
selectedPattern &&
|
|
680
|
+
details
|
|
681
|
+
) {
|
|
682
|
+
if (decision === "always_allow" && details.riskLevel === "high") {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
for (const option of details.allowlistOptions) {
|
|
686
|
+
if (patternMatchesCandidate(selectedPattern, option.pattern)) {
|
|
687
|
+
return { allow: true };
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// Persistent deny: cascade denial if the pattern matches
|
|
694
|
+
if (decision === "always_deny" && selectedPattern && details) {
|
|
695
|
+
for (const option of details.allowlistOptions) {
|
|
696
|
+
if (patternMatchesCandidate(selectedPattern, option.pattern)) {
|
|
697
|
+
return { allow: false };
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return null;
|
|
592
704
|
}
|
|
593
705
|
|
|
594
706
|
handleSecretResponse(
|
|
@@ -632,6 +744,17 @@ export class Session {
|
|
|
632
744
|
this.hostFileProxy = proxy;
|
|
633
745
|
}
|
|
634
746
|
|
|
747
|
+
resolveHostCu(requestId: string, observation: CuObservationResult): void {
|
|
748
|
+
this.hostCuProxy?.resolve(requestId, observation);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
setHostCuProxy(proxy: HostCuProxy | undefined): void {
|
|
752
|
+
if (this.hostCuProxy && this.hostCuProxy !== proxy) {
|
|
753
|
+
this.hostCuProxy.dispose();
|
|
754
|
+
}
|
|
755
|
+
this.hostCuProxy = proxy;
|
|
756
|
+
}
|
|
757
|
+
|
|
635
758
|
// ── Server-authoritative state signals ─────────────────────────────
|
|
636
759
|
|
|
637
760
|
emitConfirmationStateChanged(
|
|
@@ -220,9 +220,7 @@ registerHook(
|
|
|
220
220
|
const SETTING_TO_KEY: Record<string, string> = {
|
|
221
221
|
activation_key: "pttActivationKey",
|
|
222
222
|
tts_voice_id: "ttsVoiceId",
|
|
223
|
-
|
|
224
|
-
wake_word_keyword: "wakeWordKeyword",
|
|
225
|
-
wake_word_timeout: "wakeWordTimeoutSeconds",
|
|
223
|
+
conversation_timeout: "voiceConversationTimeoutSeconds",
|
|
226
224
|
};
|
|
227
225
|
const key = SETTING_TO_KEY[setting];
|
|
228
226
|
if (!key) return;
|
|
@@ -231,12 +229,8 @@ registerHook(
|
|
|
231
229
|
// the validation logic in the tool's execute method.
|
|
232
230
|
const raw = input.value;
|
|
233
231
|
let coerced: string | boolean | number = raw as string;
|
|
234
|
-
if (setting === "
|
|
235
|
-
coerced = raw === true || raw === "true";
|
|
236
|
-
} else if (setting === "wake_word_timeout") {
|
|
232
|
+
if (setting === "conversation_timeout") {
|
|
237
233
|
coerced = typeof raw === "number" ? raw : Number(raw);
|
|
238
|
-
} else if (setting === "wake_word_keyword" && typeof raw === "string") {
|
|
239
|
-
coerced = raw.trim();
|
|
240
234
|
} else if (setting === "tts_voice_id" && typeof raw === "string") {
|
|
241
235
|
coerced = raw.trim();
|
|
242
236
|
}
|
|
@@ -79,8 +79,8 @@ export async function handleWatchObservation(
|
|
|
79
79
|
"Observation added to session",
|
|
80
80
|
);
|
|
81
81
|
|
|
82
|
-
// 4. Every 3 observations: call the LLM for live commentary
|
|
83
|
-
if (
|
|
82
|
+
// 4. Every 3 observations: call the LLM for live commentary
|
|
83
|
+
if (session.observations.length % 3 === 0) {
|
|
84
84
|
log.debug(
|
|
85
85
|
{ watchId: msg.watchId, observationCount: session.observations.length },
|
|
86
86
|
"Triggering commentary generation (every 3rd observation)",
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { getNestedValue, loadRawConfig } from "../../config/loader.js";
|
|
8
|
+
import { credentialKey } from "../../security/credential-key.js";
|
|
8
9
|
import { getSecureKey } from "../../security/secure-keys.js";
|
|
9
10
|
import { ConfigError } from "../../util/errors.js";
|
|
10
11
|
import type { EmailProvider } from "../provider.js";
|
|
@@ -13,7 +14,7 @@ export const SUPPORTED_PROVIDERS = ["agentmail"] as const;
|
|
|
13
14
|
export type SupportedProvider = (typeof SUPPORTED_PROVIDERS)[number];
|
|
14
15
|
|
|
15
16
|
const PROVIDER_KEY_MAP: Record<SupportedProvider, string[]> = {
|
|
16
|
-
agentmail: ["agentmail", "
|
|
17
|
+
agentmail: ["agentmail", credentialKey("agentmail", "api_key")],
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getLogger,
|
|
1
|
+
import { getLogger, truncateForLog } from "../util/logger.js";
|
|
2
2
|
import type { EventBus, Subscription } from "./bus.js";
|
|
3
3
|
import type { AssistantDomainEvents } from "./domain-events.js";
|
|
4
4
|
|
|
@@ -23,7 +23,7 @@ export function registerToolMetricsLoggingListener(
|
|
|
23
23
|
options?: MetricsListenerOptions,
|
|
24
24
|
): Subscription {
|
|
25
25
|
const logger = options?.logger ?? defaultLogger;
|
|
26
|
-
const debugEnabled = options?.debugEnabled ??
|
|
26
|
+
const debugEnabled = options?.debugEnabled ?? (() => false);
|
|
27
27
|
const truncate = options?.truncate ?? truncateForLog;
|
|
28
28
|
|
|
29
29
|
return eventBus.onAny((event) => {
|
package/src/hooks/manager.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type FSWatcher, watch } from "node:fs";
|
|
|
2
2
|
|
|
3
3
|
import { Debouncer } from "../util/debounce.js";
|
|
4
4
|
import { pathExists } from "../util/fs.js";
|
|
5
|
-
import { getLogger
|
|
5
|
+
import { getLogger } from "../util/logger.js";
|
|
6
6
|
import { getHooksDir } from "../util/platform.js";
|
|
7
7
|
import { discoverHooks } from "./discovery.js";
|
|
8
8
|
import { runHookScript } from "./runner.js";
|
|
@@ -73,9 +73,6 @@ export class HookManager {
|
|
|
73
73
|
"Hook exited with non-zero code",
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
|
-
if (result.stderr && isDebug()) {
|
|
77
|
-
process.stderr.write(result.stderr);
|
|
78
|
-
}
|
|
79
76
|
} catch (err) {
|
|
80
77
|
log.warn({ err, hook: hook.name, event }, "Hook execution failed");
|
|
81
78
|
}
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
* 1. **User Settings** (`config.ingress.publicBaseUrl`) — set via
|
|
9
9
|
* the in-chat config flow, the Settings UI, or `config set ingress.publicBaseUrl`. This is the
|
|
10
10
|
* primary source of truth. When the assistant spawns or restarts
|
|
11
|
-
* the gateway,
|
|
12
|
-
*
|
|
11
|
+
* the gateway, the workspace config file is read so both processes
|
|
12
|
+
* agree on the same URL.
|
|
13
13
|
*
|
|
14
|
-
* 2. **
|
|
15
|
-
* fallback for operational use (e.g.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* 2. **Module-level state** (`getIngressPublicBaseUrl()`) — serves as a
|
|
15
|
+
* fallback for operational use (e.g. runtime tunnel updates). When
|
|
16
|
+
* tunnels start or stop, `setIngressPublicBaseUrl()` updates this
|
|
17
|
+
* value in-process.
|
|
18
18
|
*
|
|
19
19
|
* This chain ensures that:
|
|
20
20
|
* - The assistant's outbound callback URLs (Twilio webhooks, OAuth
|
|
@@ -70,7 +70,7 @@ export function getPublicBaseUrl(config: IngressConfig): string {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
throw new Error(
|
|
73
|
-
"No public base URL configured. Set ingress.publicBaseUrl in config
|
|
73
|
+
"No public base URL configured. Set ingress.publicBaseUrl in config.",
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
|
package/src/instrument.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { arch, platform, release } from "node:os";
|
|
2
|
+
|
|
1
3
|
import * as Sentry from "@sentry/node";
|
|
2
4
|
|
|
3
5
|
import { getSentryDsn } from "./config/env.js";
|
|
4
|
-
import { APP_VERSION } from "./version.js";
|
|
6
|
+
import { APP_VERSION, COMMIT_SHA } from "./version.js";
|
|
5
7
|
|
|
6
8
|
/** Patterns that match sensitive data in Sentry event values. */
|
|
7
9
|
const PII_PATTERNS = [
|
|
@@ -42,8 +44,20 @@ export function initSentry(): void {
|
|
|
42
44
|
Sentry.init({
|
|
43
45
|
dsn: getSentryDsn(),
|
|
44
46
|
release: `vellum-assistant@${APP_VERSION}`,
|
|
47
|
+
dist: COMMIT_SHA,
|
|
45
48
|
environment: APP_VERSION === "0.0.0-dev" ? "development" : "production",
|
|
46
49
|
sendDefaultPii: false,
|
|
50
|
+
initialScope: {
|
|
51
|
+
tags: {
|
|
52
|
+
commit: COMMIT_SHA,
|
|
53
|
+
os_platform: platform(),
|
|
54
|
+
os_release: release(),
|
|
55
|
+
os_arch: arch(),
|
|
56
|
+
runtime: "bun",
|
|
57
|
+
runtime_version:
|
|
58
|
+
typeof Bun !== "undefined" ? Bun.version : process.version,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
47
61
|
beforeSend(event) {
|
|
48
62
|
if (event.exception?.values) {
|
|
49
63
|
event.exception.values = event.exception.values.map((ex) => ({
|
package/src/logfire.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getLogfireToken
|
|
1
|
+
import { getLogfireToken } from "./config/env.js";
|
|
2
2
|
import type {
|
|
3
3
|
Message,
|
|
4
4
|
Provider,
|
|
@@ -13,7 +13,7 @@ const log = getLogger("logfire");
|
|
|
13
13
|
|
|
14
14
|
type LogfireModule = typeof import("@pydantic/logfire-node");
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
let logfireEnabled: boolean = !!getLogfireToken();
|
|
17
17
|
|
|
18
18
|
let logfireInstance: LogfireModule | null = null;
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ let logfireInstance: LogfireModule | null = null;
|
|
|
23
23
|
* Non-fatal on failure (logs warning and continues).
|
|
24
24
|
*/
|
|
25
25
|
export async function initLogfire(): Promise<void> {
|
|
26
|
-
if (!
|
|
26
|
+
if (!logfireEnabled) return;
|
|
27
27
|
|
|
28
28
|
try {
|
|
29
29
|
const logfire = await import("@pydantic/logfire-node");
|
|
@@ -42,12 +42,23 @@ export async function initLogfire(): Promise<void> {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Disable Logfire after early initialization. Called when the user has opted
|
|
47
|
+
* out via the feature flag. Nulls out the instance so future wrapWithLogfire
|
|
48
|
+
* calls become no-ops.
|
|
49
|
+
*/
|
|
50
|
+
export function disableLogfire(): void {
|
|
51
|
+
logfireEnabled = false;
|
|
52
|
+
logfireInstance = null;
|
|
53
|
+
log.info("Logfire disabled by feature flag");
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
/**
|
|
46
57
|
* Wraps a provider with Logfire tracing spans.
|
|
47
|
-
* When
|
|
58
|
+
* When logfireEnabled is false, returns the provider as-is (no wrapper allocated).
|
|
48
59
|
*/
|
|
49
60
|
export function wrapWithLogfire(provider: Provider): Provider {
|
|
50
|
-
if (!
|
|
61
|
+
if (!logfireEnabled) return provider;
|
|
51
62
|
return new LogfireProvider(provider);
|
|
52
63
|
}
|
|
53
64
|
|
|
@@ -11,8 +11,16 @@ import { join } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import { getConfig } from "../config/loader.js";
|
|
13
13
|
import { getAppsDir } from "../memory/app-store.js";
|
|
14
|
+
import {
|
|
15
|
+
buildManagedBaseUrl,
|
|
16
|
+
resolveManagedProxyContext,
|
|
17
|
+
} from "../providers/managed-proxy/context.js";
|
|
14
18
|
import { getLogger } from "../util/logger.js";
|
|
15
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
generateImage,
|
|
21
|
+
type ImageGenCredentials,
|
|
22
|
+
mapGeminiError,
|
|
23
|
+
} from "./gemini-image-service.js";
|
|
16
24
|
|
|
17
25
|
const log = getLogger("app-icon-generator");
|
|
18
26
|
|
|
@@ -29,8 +37,26 @@ export async function generateAppIcon(
|
|
|
29
37
|
): Promise<void> {
|
|
30
38
|
const config = getConfig();
|
|
31
39
|
const apiKey = config.apiKeys.gemini ?? process.env.GEMINI_API_KEY;
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
|
|
41
|
+
let credentials: ImageGenCredentials | undefined;
|
|
42
|
+
if (apiKey) {
|
|
43
|
+
credentials = { type: "direct", apiKey };
|
|
44
|
+
} else {
|
|
45
|
+
const managedBaseUrl = buildManagedBaseUrl("vertex");
|
|
46
|
+
if (managedBaseUrl) {
|
|
47
|
+
const ctx = resolveManagedProxyContext();
|
|
48
|
+
credentials = {
|
|
49
|
+
type: "managed-proxy",
|
|
50
|
+
assistantApiKey: ctx.assistantApiKey,
|
|
51
|
+
baseUrl: managedBaseUrl,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!credentials) {
|
|
57
|
+
log.debug(
|
|
58
|
+
"No Gemini API key or managed proxy — skipping app icon generation",
|
|
59
|
+
);
|
|
34
60
|
return;
|
|
35
61
|
}
|
|
36
62
|
|
|
@@ -58,7 +84,7 @@ export async function generateAppIcon(
|
|
|
58
84
|
try {
|
|
59
85
|
log.info({ appId, appName }, "Generating app icon via Gemini");
|
|
60
86
|
|
|
61
|
-
const result = await generateImage(
|
|
87
|
+
const result = await generateImage(credentials, {
|
|
62
88
|
prompt,
|
|
63
89
|
mode: "generate",
|
|
64
90
|
model: config.imageGenModel,
|
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
|
+
import {
|
|
3
|
+
buildManagedBaseUrl,
|
|
4
|
+
resolveManagedProxyContext,
|
|
5
|
+
} from "../providers/managed-proxy/context.js";
|
|
2
6
|
import { ConfigError, ProviderError } from "../util/errors.js";
|
|
3
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
generateImage,
|
|
9
|
+
type ImageGenCredentials,
|
|
10
|
+
} from "./gemini-image-service.js";
|
|
4
11
|
|
|
5
12
|
export async function generateAvatar(
|
|
6
13
|
prompt: string,
|
|
7
14
|
): Promise<{ imageBase64: string; mimeType: string }> {
|
|
8
15
|
const config = getConfig();
|
|
9
16
|
const geminiKey = config.apiKeys.gemini ?? process.env.GEMINI_API_KEY;
|
|
10
|
-
|
|
17
|
+
|
|
18
|
+
let credentials: ImageGenCredentials | undefined;
|
|
19
|
+
if (geminiKey) {
|
|
20
|
+
credentials = { type: "direct", apiKey: geminiKey };
|
|
21
|
+
} else {
|
|
22
|
+
const managedBaseUrl = buildManagedBaseUrl("vertex");
|
|
23
|
+
if (managedBaseUrl) {
|
|
24
|
+
const ctx = resolveManagedProxyContext();
|
|
25
|
+
credentials = {
|
|
26
|
+
type: "managed-proxy",
|
|
27
|
+
assistantApiKey: ctx.assistantApiKey,
|
|
28
|
+
baseUrl: managedBaseUrl,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!credentials) {
|
|
11
34
|
throw new ConfigError(
|
|
12
35
|
"Gemini API key is not configured. Set it via `config set apiKeys.gemini <key>` or the GEMINI_API_KEY environment variable.",
|
|
13
36
|
);
|
|
14
37
|
}
|
|
15
38
|
|
|
16
|
-
const result = await generateImage(
|
|
39
|
+
const result = await generateImage(credentials, {
|
|
17
40
|
prompt,
|
|
18
41
|
mode: "generate",
|
|
19
42
|
model: config.imageGenModel,
|
|
@@ -13,6 +13,21 @@ export interface ImageGenerationRequest {
|
|
|
13
13
|
variants?: number;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/** Credentials for direct Gemini API access. */
|
|
17
|
+
export interface DirectCredentials {
|
|
18
|
+
type: "direct";
|
|
19
|
+
apiKey: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Credentials for managed proxy access via Vertex AI. */
|
|
23
|
+
export interface ManagedProxyCredentials {
|
|
24
|
+
type: "managed-proxy";
|
|
25
|
+
assistantApiKey: string;
|
|
26
|
+
baseUrl: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type ImageGenCredentials = DirectCredentials | ManagedProxyCredentials;
|
|
30
|
+
|
|
16
31
|
export interface GeneratedImage {
|
|
17
32
|
mimeType: string;
|
|
18
33
|
dataBase64: string;
|
|
@@ -64,7 +79,7 @@ export function mapGeminiError(error: unknown): string {
|
|
|
64
79
|
// --- Core function ---
|
|
65
80
|
|
|
66
81
|
export async function generateImage(
|
|
67
|
-
|
|
82
|
+
credentials: ImageGenCredentials,
|
|
68
83
|
request: ImageGenerationRequest,
|
|
69
84
|
): Promise<ImageGenerationResult> {
|
|
70
85
|
const model =
|
|
@@ -74,7 +89,18 @@ export async function generateImage(
|
|
|
74
89
|
|
|
75
90
|
const variants = Math.max(1, Math.min(request.variants ?? 1, MAX_VARIANTS));
|
|
76
91
|
|
|
77
|
-
const client =
|
|
92
|
+
const client =
|
|
93
|
+
credentials.type === "managed-proxy"
|
|
94
|
+
? new GoogleGenAI({
|
|
95
|
+
vertexai: true,
|
|
96
|
+
project: "proxy",
|
|
97
|
+
location: "us-central1",
|
|
98
|
+
httpOptions: {
|
|
99
|
+
baseUrl: credentials.baseUrl,
|
|
100
|
+
headers: { Authorization: `Bearer ${credentials.assistantApiKey}` },
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
: new GoogleGenAI({ apiKey: credentials.apiKey });
|
|
78
104
|
|
|
79
105
|
// Build contents array — append a title request so the model's text
|
|
80
106
|
// response contains a short filename-safe title for the generated image.
|
|
@@ -117,6 +117,27 @@ export function getOrCreateConversation(conversationKey: string): {
|
|
|
117
117
|
return { conversationId: existing.conversationId, created: false };
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// Check if the conversationKey itself is an existing conversation ID.
|
|
121
|
+
// This happens when the client loads a thread from the conversations list
|
|
122
|
+
// and uses the server's conversationId as its local sessionId / conversationKey.
|
|
123
|
+
const existingConversation = tx
|
|
124
|
+
.select({ id: conversations.id })
|
|
125
|
+
.from(conversations)
|
|
126
|
+
.where(eq(conversations.id, conversationKey))
|
|
127
|
+
.get();
|
|
128
|
+
|
|
129
|
+
if (existingConversation) {
|
|
130
|
+
tx.insert(conversationKeys)
|
|
131
|
+
.values({
|
|
132
|
+
id: uuid(),
|
|
133
|
+
conversationKey,
|
|
134
|
+
conversationId: existingConversation.id,
|
|
135
|
+
createdAt: Date.now(),
|
|
136
|
+
})
|
|
137
|
+
.run();
|
|
138
|
+
return { conversationId: existingConversation.id, created: false };
|
|
139
|
+
}
|
|
140
|
+
|
|
120
141
|
const now = Date.now();
|
|
121
142
|
const conversationId = uuid();
|
|
122
143
|
|
package/src/memory/db-init.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
createMediaAssetsTables,
|
|
29
29
|
createMessagesFts,
|
|
30
30
|
createNotificationTables,
|
|
31
|
+
createOAuthTables,
|
|
31
32
|
createScopedApprovalGrantsTable,
|
|
32
33
|
createSequenceTables,
|
|
33
34
|
createTasksAndWorkItemsTables,
|
|
@@ -340,6 +341,9 @@ export function initializeDb(): void {
|
|
|
340
341
|
// 52. Drop the legacy reminders table after data migration
|
|
341
342
|
migrateDropRemindersTable(database);
|
|
342
343
|
|
|
344
|
+
// 53. OAuth provider/app/connection tables
|
|
345
|
+
createOAuthTables(database);
|
|
346
|
+
|
|
343
347
|
validateMigrationState(database);
|
|
344
348
|
|
|
345
349
|
if (process.env.BUN_TEST === "1") {
|
|
@@ -44,7 +44,7 @@ export type FollowupState =
|
|
|
44
44
|
| "completed"
|
|
45
45
|
| "declined"
|
|
46
46
|
| "failed";
|
|
47
|
-
export type FollowupAction = "call_back" | "
|
|
47
|
+
export type FollowupAction = "call_back" | "decline";
|
|
48
48
|
|
|
49
49
|
export interface GuardianActionRequest {
|
|
50
50
|
id: string;
|