@vellumai/assistant 0.5.6 → 0.5.8
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/.env.example +16 -2
- package/ARCHITECTURE.md +6 -75
- package/Dockerfile +3 -2
- package/README.md +0 -2
- package/bun.lock +0 -414
- package/docker-entrypoint.sh +9 -0
- package/docs/architecture/keychain-broker.md +45 -240
- package/docs/architecture/memory.md +13 -11
- package/docs/architecture/security.md +0 -17
- package/docs/credential-execution-service.md +2 -2
- package/node_modules/@vellumai/ces-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-contracts/src/error.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/grants.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/index.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +120 -1
- package/node_modules/@vellumai/credential-storage/package.json +1 -0
- package/node_modules/@vellumai/egress-proxy/package.json +1 -0
- package/package.json +2 -3
- package/src/__tests__/actor-token-service.test.ts +0 -114
- package/src/__tests__/approval-cascade.test.ts +0 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-skill-endstate.test.ts +6 -5
- package/src/__tests__/btw-routes.test.ts +0 -39
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-domain.test.ts +0 -128
- package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
- package/src/__tests__/ces-startup-timeout.test.ts +40 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -5
- package/src/__tests__/channel-readiness-service.test.ts +1 -60
- package/src/__tests__/checker.test.ts +4 -2
- package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -2
- package/src/__tests__/config-schema.test.ts +3 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +2 -4
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +15 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-messaging-secret-redirect.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +0 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -1
- package/src/__tests__/conversation-queue.test.ts +0 -1
- package/src/__tests__/conversation-skill-tools.test.ts +0 -54
- package/src/__tests__/conversation-slash-queue.test.ts +0 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
- package/src/__tests__/conversation-title-service.test.ts +87 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
- package/src/__tests__/credential-execution-client.test.ts +5 -2
- package/src/__tests__/credential-execution-feature-gates.test.ts +59 -30
- package/src/__tests__/credential-execution-managed-contract.test.ts +35 -20
- package/src/__tests__/credential-security-e2e.test.ts +1 -67
- package/src/__tests__/credential-security-invariants.test.ts +6 -50
- package/src/__tests__/credentials-cli.test.ts +82 -3
- package/src/__tests__/daemon-credential-client.test.ts +123 -0
- package/src/__tests__/db-migration-rollback.test.ts +2015 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +34 -143
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
- package/src/__tests__/gateway-client-managed-outbound.test.ts +79 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -7
- package/src/__tests__/http-user-message-parity.test.ts +3 -103
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
- package/src/__tests__/intent-routing.test.ts +0 -13
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
- package/src/__tests__/journal-context.test.ts +335 -0
- package/src/__tests__/keychain-broker-client.test.ts +161 -22
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -3
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +70 -25
- package/src/__tests__/memory-recall-quality.test.ts +48 -17
- package/src/__tests__/memory-regressions.test.ts +408 -363
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -3
- package/src/__tests__/migration-export-http.test.ts +2 -2
- package/src/__tests__/migration-import-commit-http.test.ts +2 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
- package/src/__tests__/migration-validate-http.test.ts +2 -2
- package/src/__tests__/non-member-access-request.test.ts +2 -7
- package/src/__tests__/notification-decision-fallback.test.ts +4 -0
- package/src/__tests__/notification-decision-identity.test.ts +4 -0
- package/src/__tests__/notification-decision-strategy.test.ts +71 -0
- package/src/__tests__/oauth-cli.test.ts +5 -1
- package/src/__tests__/permission-types.test.ts +1 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -37
- package/src/__tests__/provider-error-scenarios.test.ts +0 -267
- package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
- package/src/__tests__/provider-streaming.benchmark.test.ts +2 -81
- package/src/__tests__/qdrant-manager.test.ts +28 -2
- package/src/__tests__/registry.test.ts +0 -6
- package/src/__tests__/relay-server.test.ts +1 -2
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
- package/src/__tests__/script-proxy-injection-runtime.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -1
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
- package/src/__tests__/secure-keys.test.ts +95 -272
- package/src/__tests__/shell-identity.test.ts +96 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
- package/src/__tests__/skill-feature-flags.test.ts +46 -45
- package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
- package/src/__tests__/skill-load-inline-command.test.ts +8 -12
- package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
- package/src/__tests__/skill-load-tool.test.ts +0 -2
- package/src/__tests__/skill-memory.test.ts +17 -3
- package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
- package/src/__tests__/skills.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +0 -4
- package/src/__tests__/stale-approval-dedup.test.ts +171 -0
- package/src/__tests__/stt-hints.test.ts +437 -0
- package/src/__tests__/suggestion-routes.test.ts +1 -32
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/task-memory-cleanup.test.ts +14 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
- package/src/__tests__/twilio-routes-twiml.test.ts +139 -1
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
- package/src/__tests__/voice-quality.test.ts +58 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -7
- package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
- package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +220 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
- package/src/acp/agent-process.ts +9 -1
- package/src/agent/loop.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +164 -38
- package/src/calls/__tests__/tts-text-sanitizer.test.ts +254 -0
- package/src/calls/audio-store.test.ts +97 -0
- package/src/calls/audio-store.ts +205 -0
- package/src/calls/call-controller.ts +90 -8
- package/src/calls/call-domain.ts +3 -0
- package/src/calls/call-store.ts +10 -3
- package/src/calls/fish-audio-client.ts +129 -0
- package/src/calls/relay-server.ts +27 -0
- package/src/calls/stt-hints.ts +189 -0
- package/src/calls/tts-text-sanitizer.ts +61 -0
- package/src/calls/twilio-routes.ts +34 -5
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-ingress-preflight.ts +0 -42
- package/src/calls/voice-quality.ts +38 -5
- package/src/calls/voice-session-bridge.ts +7 -12
- package/src/cli/commands/avatar.ts +2 -2
- package/src/cli/commands/config.ts +1 -4
- package/src/cli/commands/credentials.ts +128 -82
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/keys.ts +7 -7
- package/src/cli/commands/memory.ts +1 -1
- package/src/cli/commands/oauth/connections.ts +11 -29
- package/src/cli/commands/oauth/index.ts +7 -0
- package/src/cli/commands/oauth/platform.ts +525 -0
- package/src/cli/commands/platform.ts +3 -3
- package/src/cli/lib/daemon-credential-client.ts +284 -0
- package/src/cli.ts +1 -1
- package/src/config/assistant-feature-flags.ts +186 -5
- package/src/config/bundled-skills/AGENTS.md +34 -0
- package/src/config/bundled-skills/acp/SKILL.md +10 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +0 -4
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
- package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -0
- package/src/config/bundled-skills/settings/SKILL.md +15 -2
- package/src/config/bundled-skills/settings/TOOLS.json +47 -2
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +59 -0
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +80 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
- package/src/config/bundled-skills/slack/SKILL.md +1 -1
- package/src/config/bundled-tool-registry.ts +5 -11
- package/src/config/defaults.ts +0 -2
- package/src/config/env-registry.ts +5 -5
- package/src/config/env.ts +21 -14
- package/src/config/feature-flag-registry.json +49 -9
- package/src/config/loader.ts +106 -42
- package/src/config/schema.ts +9 -29
- package/src/config/schemas/calls.ts +30 -0
- package/src/config/schemas/fish-audio.ts +39 -0
- package/src/config/schemas/inference.ts +2 -2
- package/src/config/schemas/journal.ts +16 -0
- package/src/config/schemas/memory-processing.ts +2 -2
- package/src/config/schemas/security.ts +0 -4
- package/src/config/types.ts +1 -1
- package/src/contacts/contact-store.ts +39 -0
- package/src/contacts/types.ts +2 -0
- package/src/credential-execution/approval-bridge.ts +1 -0
- package/src/credential-execution/executable-discovery.ts +28 -4
- package/src/credential-execution/feature-gates.ts +16 -0
- package/src/credential-execution/process-manager.ts +38 -0
- package/src/credential-execution/startup-timeout.ts +36 -0
- package/src/daemon/approval-generators.ts +3 -9
- package/src/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/config-watcher.ts +5 -0
- package/src/daemon/conversation-error.ts +13 -1
- package/src/daemon/conversation-memory.ts +1 -2
- package/src/daemon/conversation-process.ts +18 -1
- package/src/daemon/conversation-surfaces.ts +30 -1
- package/src/daemon/conversation-tool-setup.ts +0 -105
- package/src/daemon/conversation.ts +21 -1
- package/src/daemon/guardian-action-generators.ts +3 -9
- package/src/daemon/handlers/config-vercel.ts +92 -0
- package/src/daemon/handlers/skills.ts +2 -15
- package/src/daemon/install-symlink.ts +195 -0
- package/src/daemon/lifecycle.ts +234 -51
- package/src/daemon/message-types/conversations.ts +4 -4
- package/src/daemon/message-types/diagnostics.ts +3 -22
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/message-types/upgrades.ts +8 -0
- package/src/daemon/server.ts +32 -95
- package/src/events/domain-events.ts +2 -1
- package/src/inbound/platform-callback-registration.ts +3 -3
- package/src/instrument.ts +8 -5
- package/src/memory/app-store.ts +31 -0
- package/src/memory/conversation-title-service.ts +50 -1
- package/src/memory/db-init.ts +16 -0
- package/src/memory/indexer.ts +19 -10
- package/src/memory/items-extractor.ts +328 -321
- package/src/memory/job-handlers/conversation-starters.ts +4 -1
- package/src/memory/job-handlers/summarization.ts +26 -16
- package/src/memory/jobs-store.ts +63 -6
- package/src/memory/jobs-worker.ts +31 -7
- package/src/memory/journal-memory.ts +214 -0
- package/src/memory/migrations/001-job-deferrals.ts +19 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
- package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
- package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
- package/src/memory/migrations/116-messages-fts.ts +106 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
- package/src/memory/migrations/141-rename-verification-table.ts +54 -0
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
- package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
- package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
- package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
- package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
- package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
- package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
- package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
- package/src/memory/migrations/193-add-source-type-columns.ts +81 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +98 -0
- package/src/memory/migrations/validate-migration-state.ts +137 -11
- package/src/memory/qdrant-circuit-breaker.ts +9 -0
- package/src/memory/qdrant-manager.ts +64 -7
- package/src/memory/retriever.test.ts +37 -25
- package/src/memory/retriever.ts +24 -49
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/memory-core.ts +2 -0
- package/src/memory/search/formatting.ts +7 -44
- package/src/memory/search/staleness.ts +4 -0
- package/src/memory/search/tier-classifier.ts +10 -2
- package/src/memory/search/types.ts +2 -5
- package/src/memory/task-memory-cleanup.ts +4 -3
- package/src/notifications/adapters/slack.ts +168 -6
- package/src/notifications/broadcaster.ts +1 -0
- package/src/notifications/copy-composer.ts +59 -2
- package/src/notifications/decision-engine.ts +4 -1
- package/src/notifications/signal.ts +2 -0
- package/src/notifications/types.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -4
- package/src/permissions/checker.ts +0 -38
- package/src/permissions/shell-identity.ts +76 -22
- package/src/permissions/types.ts +4 -2
- package/src/platform/client.ts +35 -7
- package/src/prompts/journal-context.ts +133 -0
- package/src/prompts/persona-resolver.ts +194 -0
- package/src/prompts/system-prompt.ts +44 -4
- package/src/prompts/templates/SOUL.md +10 -0
- package/src/prompts/templates/users/default.md +1 -0
- package/src/providers/provider-send-message.ts +3 -32
- package/src/providers/registry.ts +29 -179
- package/src/providers/types.ts +1 -1
- package/src/runtime/access-request-helper.ts +4 -0
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
- package/src/runtime/auth/__tests__/guard-tests.test.ts +9 -50
- package/src/runtime/auth/external-assistant-id.ts +13 -59
- package/src/runtime/auth/route-policy.ts +17 -1
- package/src/runtime/auth/token-service.ts +43 -138
- package/src/runtime/channel-readiness-service.ts +1 -16
- package/src/runtime/gateway-client.ts +47 -4
- package/src/runtime/guardian-decision-types.ts +45 -4
- package/src/runtime/http-server.ts +31 -3
- package/src/runtime/middleware/error-handler.ts +1 -9
- package/src/runtime/routes/access-request-decision.ts +2 -2
- package/src/runtime/routes/app-management-routes.ts +2 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +219 -30
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +37 -14
- package/src/runtime/routes/audio-routes.ts +40 -0
- package/src/runtime/routes/btw-routes.ts +0 -17
- package/src/runtime/routes/channel-readiness-routes.ts +9 -4
- package/src/runtime/routes/conversation-query-routes.ts +63 -1
- package/src/runtime/routes/conversation-routes.ts +4 -44
- package/src/runtime/routes/debug-routes.ts +12 -9
- package/src/runtime/routes/diagnostics-routes.ts +1 -477
- package/src/runtime/routes/guardian-approval-interception.ts +168 -11
- package/src/runtime/routes/guardian-approval-prompt.ts +6 -1
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +103 -21
- package/src/runtime/routes/identity-routes.ts +19 -30
- package/src/runtime/routes/inbound-message-handler.ts +31 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +64 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +52 -40
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
- package/src/runtime/routes/integrations/twilio.ts +52 -10
- package/src/runtime/routes/integrations/vercel.ts +89 -0
- package/src/runtime/routes/log-export-routes.ts +5 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -3
- package/src/runtime/routes/memory-item-routes.ts +46 -14
- package/src/runtime/routes/migration-rollback-routes.ts +209 -0
- package/src/runtime/routes/migration-routes.ts +17 -1
- package/src/runtime/routes/notification-routes.ts +58 -0
- package/src/runtime/routes/schedule-routes.ts +65 -0
- package/src/runtime/routes/secret-routes.ts +141 -10
- package/src/runtime/routes/settings-routes.ts +41 -1
- package/src/runtime/routes/tts-routes.ts +96 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +26 -2
- package/src/runtime/routes/workspace-commit-routes.ts +62 -0
- package/src/runtime/routes/workspace-routes.test.ts +22 -1
- package/src/runtime/routes/workspace-routes.ts +1 -1
- package/src/runtime/routes/workspace-utils.ts +86 -2
- package/src/security/ces-credential-client.ts +75 -29
- package/src/security/ces-rpc-credential-backend.ts +86 -0
- package/src/security/credential-backend.ts +22 -92
- package/src/security/keychain-broker-client.ts +10 -2
- package/src/security/secure-keys.ts +113 -115
- package/src/skills/catalog-install.ts +6 -32
- package/src/skills/skill-memory.ts +1 -0
- package/src/subagent/manager.ts +2 -5
- package/src/telemetry/usage-telemetry-reporter.ts +4 -2
- package/src/tools/acp/spawn.ts +78 -1
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/credentials/vault.ts +5 -3
- package/src/tools/executor.ts +0 -4
- package/src/tools/memory/definitions.ts +3 -2
- package/src/tools/memory/handlers.ts +10 -7
- package/src/tools/network/script-proxy/session-manager.ts +19 -4
- package/src/tools/network/web-fetch.ts +3 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/types.ts +0 -8
- package/src/util/browser.ts +15 -0
- package/src/util/errors.ts +0 -12
- package/src/util/platform.ts +4 -51
- package/src/workspace/git-service.ts +5 -2
- package/src/workspace/migrations/001-avatar-rename.ts +15 -0
- package/src/workspace/migrations/003-seed-device-id.ts +17 -1
- package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
- package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
- package/src/workspace/migrations/006-services-config.ts +49 -0
- package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
- package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
- package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +96 -0
- package/src/workspace/migrations/018-rekey-compound-credential-keys.ts +184 -0
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +103 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +27 -5
- package/src/workspace/migrations/registry.ts +12 -0
- package/src/workspace/migrations/runner.ts +106 -2
- package/src/workspace/migrations/types.ts +4 -0
- package/src/workspace/provider-commit-message-generator.ts +12 -21
- package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
- package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
- package/src/__tests__/diagnostics-export.test.ts +0 -288
- package/src/__tests__/local-gateway-health.test.ts +0 -209
- package/src/__tests__/provider-fail-open-selection.test.ts +0 -271
- package/src/__tests__/provider-failover-actual-provider.test.ts +0 -66
- package/src/__tests__/secret-ingress-handler.test.ts +0 -120
- package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
- package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
- package/src/__tests__/swarm-orchestrator.test.ts +0 -463
- package/src/__tests__/swarm-plan-validator.test.ts +0 -384
- package/src/__tests__/swarm-recursion.test.ts +0 -197
- package/src/__tests__/swarm-router-planner.test.ts +0 -234
- package/src/__tests__/swarm-tool.test.ts +0 -185
- package/src/__tests__/swarm-worker-backend.test.ts +0 -144
- package/src/__tests__/swarm-worker-runner.test.ts +0 -288
- package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
- package/src/commands/cc-command-registry.ts +0 -248
- package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
- package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
- package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
- package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
- package/src/config/schemas/swarm.ts +0 -82
- package/src/logfire.ts +0 -135
- package/src/memory/search/lexical.ts +0 -48
- package/src/providers/failover.ts +0 -186
- package/src/runtime/local-gateway-health.ts +0 -275
- package/src/security/secret-ingress.ts +0 -68
- package/src/swarm/backend-claude-code.ts +0 -225
- package/src/swarm/checkpoint.ts +0 -137
- package/src/swarm/graph-utils.ts +0 -53
- package/src/swarm/index.ts +0 -55
- package/src/swarm/limits.ts +0 -66
- package/src/swarm/orchestrator.ts +0 -424
- package/src/swarm/plan-validator.ts +0 -117
- package/src/swarm/router-planner.ts +0 -162
- package/src/swarm/router-prompts.ts +0 -39
- package/src/swarm/synthesizer.ts +0 -81
- package/src/swarm/types.ts +0 -72
- package/src/swarm/worker-backend.ts +0 -131
- package/src/swarm/worker-prompts.ts +0 -80
- package/src/swarm/worker-runner.ts +0 -170
- package/src/tools/claude-code/claude-code.ts +0 -610
- package/src/tools/swarm/delegate.ts +0 -205
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { wrapWithLogfire } from "../logfire.js";
|
|
2
1
|
import { getProviderKeyAsync } from "../security/secure-keys.js";
|
|
3
|
-
import {
|
|
2
|
+
import { ProviderNotConfiguredError } from "../util/errors.js";
|
|
4
3
|
import { AnthropicProvider } from "./anthropic/client.js";
|
|
5
|
-
import { FailoverProvider, type ProviderHealthStatus } from "./failover.js";
|
|
6
4
|
import { FireworksProvider } from "./fireworks/client.js";
|
|
7
5
|
import { GeminiProvider } from "./gemini/client.js";
|
|
8
6
|
import {
|
|
@@ -18,8 +16,6 @@ import type { Provider } from "./types.js";
|
|
|
18
16
|
|
|
19
17
|
const providers = new Map<string, Provider>();
|
|
20
18
|
const routingSources = new Map<string, "user-key" | "managed-proxy">();
|
|
21
|
-
let cachedFailoverProvider: FailoverProvider | null = null;
|
|
22
|
-
let cachedFailoverKey: string | null = null;
|
|
23
19
|
|
|
24
20
|
export function registerProvider(name: string, provider: Provider): void {
|
|
25
21
|
providers.set(name, provider);
|
|
@@ -28,95 +24,11 @@ export function registerProvider(name: string, provider: Provider): void {
|
|
|
28
24
|
export function getProvider(name: string): Provider {
|
|
29
25
|
const provider = providers.get(name);
|
|
30
26
|
if (!provider) {
|
|
31
|
-
throw new
|
|
32
|
-
`Provider "${name}" not found. Available: ${listProviders().join(", ")}`,
|
|
33
|
-
);
|
|
27
|
+
throw new ProviderNotConfiguredError(name, listProviders());
|
|
34
28
|
}
|
|
35
29
|
return provider;
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
export interface ProviderSelection {
|
|
39
|
-
/** Ordered list of available provider names */
|
|
40
|
-
availableProviders: string[];
|
|
41
|
-
/** The selected (effective) primary provider name, or null if none available */
|
|
42
|
-
selectedPrimary: string | null;
|
|
43
|
-
/** Whether the effective primary differs from the requested primary */
|
|
44
|
-
usedFallbackPrimary: boolean;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Resolve provider selection from requested primary and provider order.
|
|
49
|
-
* Dedupes [requestedPrimary, ...providerOrder], filtered to initialized providers.
|
|
50
|
-
* Returns null selectedPrimary when no providers are available.
|
|
51
|
-
*/
|
|
52
|
-
export function resolveProviderSelection(
|
|
53
|
-
requestedPrimary: string,
|
|
54
|
-
providerOrder: string[],
|
|
55
|
-
): ProviderSelection {
|
|
56
|
-
const ordered: string[] = [];
|
|
57
|
-
const seen = new Set<string>();
|
|
58
|
-
|
|
59
|
-
for (const name of [requestedPrimary, ...providerOrder]) {
|
|
60
|
-
if (seen.has(name)) continue;
|
|
61
|
-
seen.add(name);
|
|
62
|
-
if (providers.has(name)) {
|
|
63
|
-
ordered.push(name);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (ordered.length === 0) {
|
|
68
|
-
return {
|
|
69
|
-
availableProviders: [],
|
|
70
|
-
selectedPrimary: null,
|
|
71
|
-
usedFallbackPrimary: false,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
availableProviders: ordered,
|
|
77
|
-
selectedPrimary: ordered[0],
|
|
78
|
-
usedFallbackPrimary: ordered[0] !== requestedPrimary,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Build a provider that tries the effective primary provider first, then falls
|
|
84
|
-
* back to others in the configured order. If the requested primary is not
|
|
85
|
-
* available, automatically selects the first available provider from the
|
|
86
|
-
* deduped [primaryName, ...providerOrder] list (fail-open).
|
|
87
|
-
*
|
|
88
|
-
* Throws ConfigError only when NO providers are available at all.
|
|
89
|
-
* Caches the FailoverProvider instance so health state persists across calls.
|
|
90
|
-
*/
|
|
91
|
-
export function getFailoverProvider(
|
|
92
|
-
primaryName: string,
|
|
93
|
-
providerOrder: string[],
|
|
94
|
-
): Provider {
|
|
95
|
-
const selection = resolveProviderSelection(primaryName, providerOrder);
|
|
96
|
-
|
|
97
|
-
if (!selection.selectedPrimary) {
|
|
98
|
-
throw new ProviderNotConfiguredError(primaryName, listProviders());
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const orderedProviders: Provider[] = selection.availableProviders.map(
|
|
102
|
-
(name) => providers.get(name)!,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if (orderedProviders.length === 1) {
|
|
106
|
-
return orderedProviders[0];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Cache key from effective ordered providers (not raw input strings)
|
|
110
|
-
const cacheKey = selection.availableProviders.join(",");
|
|
111
|
-
if (cachedFailoverProvider && cachedFailoverKey === cacheKey) {
|
|
112
|
-
return cachedFailoverProvider;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
cachedFailoverProvider = new FailoverProvider(orderedProviders);
|
|
116
|
-
cachedFailoverKey = cacheKey;
|
|
117
|
-
return cachedFailoverProvider;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
32
|
export function listProviders(): string[] {
|
|
121
33
|
return Array.from(providers.keys());
|
|
122
34
|
}
|
|
@@ -152,7 +64,6 @@ export interface ProvidersConfig {
|
|
|
152
64
|
provider: string;
|
|
153
65
|
};
|
|
154
66
|
};
|
|
155
|
-
providerOrder?: string[];
|
|
156
67
|
timeouts?: { providerStreamTimeoutSec?: number };
|
|
157
68
|
}
|
|
158
69
|
|
|
@@ -173,53 +84,6 @@ function resolveModel(config: ProvidersConfig, providerName: string): string {
|
|
|
173
84
|
return getProviderDefaultModel(providerName);
|
|
174
85
|
}
|
|
175
86
|
|
|
176
|
-
export interface ProviderDebugStatus {
|
|
177
|
-
configuredPrimary: string;
|
|
178
|
-
activePrimary: string | null;
|
|
179
|
-
usedFallback: boolean;
|
|
180
|
-
registeredProviders: string[];
|
|
181
|
-
failoverHealth: ProviderHealthStatus[] | null;
|
|
182
|
-
overallHealth: "healthy" | "degraded" | "down";
|
|
183
|
-
routingSources: Record<string, "user-key" | "managed-proxy">;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export function getProviderDebugStatus(
|
|
187
|
-
configuredProvider: string,
|
|
188
|
-
providerOrder: string[],
|
|
189
|
-
): ProviderDebugStatus {
|
|
190
|
-
const registered = listProviders();
|
|
191
|
-
const selection = resolveProviderSelection(configuredProvider, providerOrder);
|
|
192
|
-
|
|
193
|
-
let failoverHealth: ProviderHealthStatus[] | null = null;
|
|
194
|
-
if (cachedFailoverProvider) {
|
|
195
|
-
failoverHealth = cachedFailoverProvider.getHealthStatus();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
let overallHealth: "healthy" | "degraded" | "down" = "down";
|
|
199
|
-
if (registered.length > 0 && selection.selectedPrimary) {
|
|
200
|
-
if (!failoverHealth) {
|
|
201
|
-
overallHealth = "healthy";
|
|
202
|
-
} else {
|
|
203
|
-
const healthyCount = failoverHealth.filter((h) => h.healthy).length;
|
|
204
|
-
if (healthyCount === failoverHealth.length) {
|
|
205
|
-
overallHealth = "healthy";
|
|
206
|
-
} else if (healthyCount > 0) {
|
|
207
|
-
overallHealth = "degraded";
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
configuredPrimary: configuredProvider,
|
|
214
|
-
activePrimary: selection.selectedPrimary,
|
|
215
|
-
usedFallback: selection.usedFallbackPrimary,
|
|
216
|
-
registeredProviders: registered,
|
|
217
|
-
failoverHealth,
|
|
218
|
-
overallHealth,
|
|
219
|
-
routingSources: Object.fromEntries(routingSources),
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
87
|
/**
|
|
224
88
|
* Resolve provider credentials using mode-aware logic.
|
|
225
89
|
* In "managed" mode, routes through the platform proxy.
|
|
@@ -274,8 +138,6 @@ export async function initializeProviders(
|
|
|
274
138
|
): Promise<void> {
|
|
275
139
|
providers.clear();
|
|
276
140
|
routingSources.clear();
|
|
277
|
-
cachedFailoverProvider = null;
|
|
278
|
-
cachedFailoverKey = null;
|
|
279
141
|
|
|
280
142
|
const streamTimeoutMs =
|
|
281
143
|
(config.timeouts?.providerStreamTimeoutSec ?? 300) * 1000;
|
|
@@ -293,15 +155,13 @@ export async function initializeProviders(
|
|
|
293
155
|
registerProvider(
|
|
294
156
|
"anthropic",
|
|
295
157
|
new RetryProvider(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}),
|
|
304
|
-
),
|
|
158
|
+
new AnthropicProvider(anthropicCreds.apiKey, model, {
|
|
159
|
+
useNativeWebSearch,
|
|
160
|
+
streamTimeoutMs,
|
|
161
|
+
...(anthropicCreds.baseURL
|
|
162
|
+
? { baseURL: anthropicCreds.baseURL }
|
|
163
|
+
: {}),
|
|
164
|
+
}),
|
|
305
165
|
),
|
|
306
166
|
);
|
|
307
167
|
routingSources.set("anthropic", anthropicCreds.source);
|
|
@@ -314,12 +174,10 @@ export async function initializeProviders(
|
|
|
314
174
|
registerProvider(
|
|
315
175
|
"openai",
|
|
316
176
|
new RetryProvider(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}),
|
|
322
|
-
),
|
|
177
|
+
new OpenAIProvider(openaiCreds.apiKey, model, {
|
|
178
|
+
streamTimeoutMs,
|
|
179
|
+
...(openaiCreds.baseURL ? { baseURL: openaiCreds.baseURL } : {}),
|
|
180
|
+
}),
|
|
323
181
|
),
|
|
324
182
|
);
|
|
325
183
|
routingSources.set("openai", openaiCreds.source);
|
|
@@ -332,14 +190,12 @@ export async function initializeProviders(
|
|
|
332
190
|
registerProvider(
|
|
333
191
|
"gemini",
|
|
334
192
|
new RetryProvider(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}),
|
|
342
|
-
),
|
|
193
|
+
new GeminiProvider(geminiCreds.apiKey, model, {
|
|
194
|
+
streamTimeoutMs,
|
|
195
|
+
...(geminiCreds.baseURL
|
|
196
|
+
? { managedBaseUrl: geminiCreds.baseURL }
|
|
197
|
+
: {}),
|
|
198
|
+
}),
|
|
343
199
|
),
|
|
344
200
|
);
|
|
345
201
|
routingSources.set("gemini", geminiCreds.source);
|
|
@@ -352,12 +208,10 @@ export async function initializeProviders(
|
|
|
352
208
|
registerProvider(
|
|
353
209
|
"ollama",
|
|
354
210
|
new RetryProvider(
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}),
|
|
360
|
-
),
|
|
211
|
+
new OllamaProvider(model, {
|
|
212
|
+
apiKey: ollamaKey ?? undefined,
|
|
213
|
+
streamTimeoutMs,
|
|
214
|
+
}),
|
|
361
215
|
),
|
|
362
216
|
);
|
|
363
217
|
routingSources.set("ollama", "user-key");
|
|
@@ -370,11 +224,9 @@ export async function initializeProviders(
|
|
|
370
224
|
registerProvider(
|
|
371
225
|
"fireworks",
|
|
372
226
|
new RetryProvider(
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}),
|
|
377
|
-
),
|
|
227
|
+
new FireworksProvider(fireworksKey, model, {
|
|
228
|
+
streamTimeoutMs,
|
|
229
|
+
}),
|
|
378
230
|
),
|
|
379
231
|
);
|
|
380
232
|
routingSources.set("fireworks", "user-key");
|
|
@@ -387,11 +239,9 @@ export async function initializeProviders(
|
|
|
387
239
|
registerProvider(
|
|
388
240
|
"openrouter",
|
|
389
241
|
new RetryProvider(
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}),
|
|
394
|
-
),
|
|
242
|
+
new OpenRouterProvider(openrouterKey, model, {
|
|
243
|
+
streamTimeoutMs,
|
|
244
|
+
}),
|
|
395
245
|
),
|
|
396
246
|
);
|
|
397
247
|
routingSources.set("openrouter", "user-key");
|
package/src/providers/types.ts
CHANGED
|
@@ -55,6 +55,8 @@ export interface AccessRequestParams {
|
|
|
55
55
|
actorDisplayName?: string;
|
|
56
56
|
actorUsername?: string;
|
|
57
57
|
previousMemberStatus?: Exclude<ChannelStatus, "unverified">;
|
|
58
|
+
/** Preview of the requester's original message, shown to the guardian. */
|
|
59
|
+
messagePreview?: string;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
export type AccessRequestResult =
|
|
@@ -90,6 +92,7 @@ export function notifyGuardianOfAccessRequest(
|
|
|
90
92
|
actorDisplayName,
|
|
91
93
|
actorUsername,
|
|
92
94
|
previousMemberStatus,
|
|
95
|
+
messagePreview,
|
|
93
96
|
} = params;
|
|
94
97
|
|
|
95
98
|
if (!actorExternalId) {
|
|
@@ -244,6 +247,7 @@ export function notifyGuardianOfAccessRequest(
|
|
|
244
247
|
guardianBindingChannel,
|
|
245
248
|
guardianResolutionSource,
|
|
246
249
|
previousMemberStatus: previousMemberStatus ?? null,
|
|
250
|
+
messagePreview: messagePreview ?? null,
|
|
247
251
|
},
|
|
248
252
|
dedupeKey: `access-request:${canonicalRequest.id}`,
|
|
249
253
|
onConversationCreated: (info) => {
|
|
@@ -17,7 +17,6 @@ mock.module("../../../util/platform.js", () => ({
|
|
|
17
17
|
getDataDir: () => testDir,
|
|
18
18
|
getDbPath: () => join(testDir, "test.db"),
|
|
19
19
|
normalizeAssistantId: (id: string) => (id === "self" ? "self" : id),
|
|
20
|
-
readLockfile: () => ({ assistants: [{ assistantId: "vellum-test-eel" }] }),
|
|
21
20
|
isMacOS: () => process.platform === "darwin",
|
|
22
21
|
isLinux: () => process.platform === "linux",
|
|
23
22
|
isWindows: () => process.platform === "win32",
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for getExternalAssistantId
|
|
2
|
+
* Tests for getExternalAssistantId.
|
|
3
3
|
*/
|
|
4
|
-
import { afterEach, describe, expect,
|
|
5
|
-
|
|
6
|
-
mock.module("../../../util/logger.js", () => ({
|
|
7
|
-
getLogger: () =>
|
|
8
|
-
new Proxy({} as Record<string, unknown>, {
|
|
9
|
-
get: () => () => {},
|
|
10
|
-
}),
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
// Controllable mock for readLockfile — defaults to null (no lockfile data)
|
|
14
|
-
const mockReadLockfile = mock(() => null as Record<string, unknown> | null);
|
|
15
|
-
|
|
16
|
-
mock.module("../../../util/platform.js", () => ({
|
|
17
|
-
readLockfile: mockReadLockfile,
|
|
18
|
-
}));
|
|
4
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
19
5
|
|
|
20
6
|
import {
|
|
21
7
|
getExternalAssistantId,
|
|
@@ -24,65 +10,24 @@ import {
|
|
|
24
10
|
|
|
25
11
|
afterEach(() => {
|
|
26
12
|
resetExternalAssistantIdCache();
|
|
27
|
-
|
|
28
|
-
mockReadLockfile.mockImplementation(() => null);
|
|
29
|
-
delete process.env.BASE_DATA_DIR;
|
|
13
|
+
delete process.env.VELLUM_ASSISTANT_NAME;
|
|
30
14
|
});
|
|
31
15
|
|
|
32
16
|
describe("getExternalAssistantId", () => {
|
|
33
|
-
test("resolves from
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{ assistantId: "vellum-old-fox", hatchedAt: "2025-01-01T00:00:00Z" },
|
|
37
|
-
{ assistantId: "vellum-new-eel", hatchedAt: "2025-06-15T12:00:00Z" },
|
|
38
|
-
],
|
|
39
|
-
}));
|
|
40
|
-
expect(getExternalAssistantId()).toBe("vellum-new-eel");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("resolves from lockfile with single assistant entry", () => {
|
|
44
|
-
mockReadLockfile.mockImplementation(() => ({
|
|
45
|
-
assistants: [
|
|
46
|
-
{ assistantId: "vellum-solo-cat", hatchedAt: "2025-03-01T00:00:00Z" },
|
|
47
|
-
],
|
|
48
|
-
}));
|
|
49
|
-
expect(getExternalAssistantId()).toBe("vellum-solo-cat");
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("resolves from BASE_DATA_DIR when lockfile has no data", () => {
|
|
53
|
-
process.env.BASE_DATA_DIR = "/tmp/vellum/assistants/vellum-true-eel";
|
|
54
|
-
expect(getExternalAssistantId()).toBe("vellum-true-eel");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("resolves from BASE_DATA_DIR with trailing slash", () => {
|
|
58
|
-
process.env.BASE_DATA_DIR = "/tmp/vellum/assistants/vellum-cool-heron/";
|
|
59
|
-
expect(getExternalAssistantId()).toBe("vellum-cool-heron");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("resolves from BASE_DATA_DIR with Windows-style backslashes", () => {
|
|
63
|
-
process.env.BASE_DATA_DIR =
|
|
64
|
-
"C:\\Users\\user\\.local\\share\\vellum\\assistants\\vellum-nice-fox";
|
|
65
|
-
expect(getExternalAssistantId()).toBe("vellum-nice-fox");
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("resolves from BASE_DATA_DIR with /instances/<name> path", () => {
|
|
69
|
-
process.env.BASE_DATA_DIR = "/home/user/.vellum/instances/vellum-swift-owl";
|
|
70
|
-
expect(getExternalAssistantId()).toBe("vellum-swift-owl");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("resolves from BASE_DATA_DIR with /instances/<name> trailing slash", () => {
|
|
74
|
-
process.env.BASE_DATA_DIR =
|
|
75
|
-
"/home/user/.vellum/instances/vellum-swift-owl/";
|
|
76
|
-
expect(getExternalAssistantId()).toBe("vellum-swift-owl");
|
|
17
|
+
test("resolves from VELLUM_ASSISTANT_NAME env var", () => {
|
|
18
|
+
process.env.VELLUM_ASSISTANT_NAME = "vellum-cool-eel";
|
|
19
|
+
expect(getExternalAssistantId()).toBe("vellum-cool-eel");
|
|
77
20
|
});
|
|
78
21
|
|
|
79
|
-
test("
|
|
80
|
-
process.env.
|
|
81
|
-
expect(getExternalAssistantId()).toBe(
|
|
22
|
+
test("caches the resolved value", () => {
|
|
23
|
+
process.env.VELLUM_ASSISTANT_NAME = "vellum-cool-eel";
|
|
24
|
+
expect(getExternalAssistantId()).toBe("vellum-cool-eel");
|
|
25
|
+
// Change env var — cached value should still be returned
|
|
26
|
+
process.env.VELLUM_ASSISTANT_NAME = "vellum-other-fox";
|
|
27
|
+
expect(getExternalAssistantId()).toBe("vellum-cool-eel");
|
|
82
28
|
});
|
|
83
29
|
|
|
84
|
-
test("
|
|
85
|
-
delete process.env.BASE_DATA_DIR;
|
|
30
|
+
test("returns undefined when env var is not set", () => {
|
|
86
31
|
expect(getExternalAssistantId()).toBe(undefined);
|
|
87
32
|
});
|
|
88
33
|
});
|
|
@@ -16,6 +16,10 @@ import { readFileSync } from "node:fs";
|
|
|
16
16
|
import { basename, resolve } from "node:path";
|
|
17
17
|
import { describe, expect, test } from "bun:test";
|
|
18
18
|
|
|
19
|
+
// Cross-package import: gateway duplicates the epoch constant and both must
|
|
20
|
+
// stay in sync. Importing directly is more reliable than regex-extracting.
|
|
21
|
+
import { CURRENT_POLICY_EPOCH as GATEWAY_POLICY_EPOCH } from "../../../../../gateway/src/auth/policy.js";
|
|
22
|
+
import { CURRENT_POLICY_EPOCH } from "../policy.js";
|
|
19
23
|
import { resolveScopeProfile } from "../scopes.js";
|
|
20
24
|
import type { Scope, ScopeProfile } from "../types.js";
|
|
21
25
|
|
|
@@ -337,56 +341,11 @@ describe("scope profile contract", () => {
|
|
|
337
341
|
// ---------------------------------------------------------------------------
|
|
338
342
|
|
|
339
343
|
describe("CURRENT_POLICY_EPOCH sync", () => {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
*/
|
|
345
|
-
|
|
346
|
-
const EPOCH_FILES = [
|
|
347
|
-
{
|
|
348
|
-
label: "assistant",
|
|
349
|
-
path: resolve(PROJECT_ROOT, "assistant/src/runtime/auth/policy.ts"),
|
|
350
|
-
},
|
|
351
|
-
{
|
|
352
|
-
label: "gateway",
|
|
353
|
-
path: resolve(PROJECT_ROOT, "gateway/src/auth/policy.ts"),
|
|
354
|
-
},
|
|
355
|
-
];
|
|
356
|
-
|
|
357
|
-
function extractEpoch(filePath: string): number {
|
|
358
|
-
const src = readFileSync(filePath, "utf-8");
|
|
359
|
-
const match = src.match(
|
|
360
|
-
/export\s+const\s+CURRENT_POLICY_EPOCH\s*=\s*(\d+)/,
|
|
361
|
-
);
|
|
362
|
-
if (!match) {
|
|
363
|
-
throw new Error(`Could not find CURRENT_POLICY_EPOCH in ${filePath}`);
|
|
364
|
-
}
|
|
365
|
-
return parseInt(match[1], 10);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
test("all non-skill packages export the same CURRENT_POLICY_EPOCH value", () => {
|
|
369
|
-
const values = EPOCH_FILES.map((f) => ({
|
|
370
|
-
label: f.label,
|
|
371
|
-
epoch: extractEpoch(f.path),
|
|
372
|
-
}));
|
|
373
|
-
|
|
374
|
-
const canonical = values[0];
|
|
375
|
-
const mismatches = values.filter((v) => v.epoch !== canonical.epoch);
|
|
376
|
-
|
|
377
|
-
if (mismatches.length > 0) {
|
|
378
|
-
const summary = values
|
|
379
|
-
.map((v) => ` - ${v.label}: ${v.epoch}`)
|
|
380
|
-
.join("\n");
|
|
381
|
-
const message = [
|
|
382
|
-
"CURRENT_POLICY_EPOCH is out of sync across packages:",
|
|
383
|
-
"",
|
|
384
|
-
summary,
|
|
385
|
-
"",
|
|
386
|
-
"All locations must have the same value.",
|
|
344
|
+
test("assistant and gateway export the same CURRENT_POLICY_EPOCH value", () => {
|
|
345
|
+
expect(
|
|
346
|
+
CURRENT_POLICY_EPOCH,
|
|
347
|
+
`CURRENT_POLICY_EPOCH mismatch: assistant=${CURRENT_POLICY_EPOCH}, gateway=${GATEWAY_POLICY_EPOCH}. ` +
|
|
387
348
|
"The canonical source is assistant/src/runtime/auth/policy.ts.",
|
|
388
|
-
|
|
389
|
-
expect(mismatches, message).toEqual([]);
|
|
390
|
-
}
|
|
349
|
+
).toBe(GATEWAY_POLICY_EPOCH);
|
|
391
350
|
});
|
|
392
351
|
});
|
|
@@ -6,81 +6,35 @@
|
|
|
6
6
|
* must identify which assistant the token belongs to, while the daemon
|
|
7
7
|
* internally uses 'self'.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 2. Most recently hatched entry in lockfile assistants array
|
|
12
|
-
* (sorted by `hatchedAt` descending) → assistantId
|
|
13
|
-
* 3. BASE_DATA_DIR path matching `/assistants/<name>` or `/instances/<name>` suffix
|
|
14
|
-
* 4. `undefined` — callers must handle the missing value
|
|
9
|
+
* Reads from the VELLUM_ASSISTANT_NAME env var, which is set by CLI
|
|
10
|
+
* hatch and Docker setup. Returns `undefined` if the env var is not set.
|
|
15
11
|
*
|
|
16
|
-
* The value is cached in memory after the first
|
|
12
|
+
* The value is cached in memory after the first read.
|
|
17
13
|
*/
|
|
18
14
|
|
|
19
|
-
import { getBaseDataDir } from "../../config/env-registry.js";
|
|
20
15
|
import { getLogger } from "../../util/logger.js";
|
|
21
|
-
import { readLockfile } from "../../util/platform.js";
|
|
22
16
|
|
|
23
17
|
const log = getLogger("external-assistant-id");
|
|
24
18
|
|
|
25
19
|
let cached: string | null | undefined;
|
|
26
20
|
|
|
27
21
|
/**
|
|
28
|
-
* Get the external assistant ID.
|
|
29
|
-
*
|
|
30
|
-
* Resolution order:
|
|
31
|
-
* 1. Cached in-memory value (populated on first call)
|
|
32
|
-
* 2. Most recently hatched entry in lockfile assistants array
|
|
33
|
-
* (sorted by `hatchedAt` descending) → assistantId
|
|
34
|
-
* 3. BASE_DATA_DIR path matching `/assistants/<name>` or `/instances/<name>` suffix
|
|
35
|
-
* 4. `undefined` when resolution fails entirely
|
|
22
|
+
* Get the external assistant ID from the VELLUM_ASSISTANT_NAME env var.
|
|
23
|
+
* Returns `undefined` when the env var is not set.
|
|
36
24
|
*/
|
|
37
25
|
export function getExternalAssistantId(): string | undefined {
|
|
38
26
|
if (cached !== undefined) {
|
|
39
27
|
return cached ?? undefined;
|
|
40
28
|
}
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// matching the pattern used elsewhere in the codebase.
|
|
51
|
-
const sorted = [...assistants].sort((a, b) => {
|
|
52
|
-
const dateA = new Date((a.hatchedAt as string) || 0).getTime();
|
|
53
|
-
const dateB = new Date((b.hatchedAt as string) || 0).getTime();
|
|
54
|
-
return dateB - dateA;
|
|
55
|
-
});
|
|
56
|
-
const latest = sorted[0];
|
|
57
|
-
if (typeof latest.assistantId === "string") {
|
|
58
|
-
cached = latest.assistantId;
|
|
59
|
-
log.info(
|
|
60
|
-
{ externalAssistantId: cached },
|
|
61
|
-
"Resolved external assistant ID from lockfile",
|
|
62
|
-
);
|
|
63
|
-
return cached;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
} catch (err) {
|
|
68
|
-
log.warn({ err }, "Failed to read lockfile for external assistant ID");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Fallback: derive from BASE_DATA_DIR path
|
|
72
|
-
const base = getBaseDataDir();
|
|
73
|
-
if (base && typeof base === "string") {
|
|
74
|
-
const normalized = base.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
75
|
-
const match = normalized.match(/\/(?:assistants|instances)\/([^/]+)$/);
|
|
76
|
-
if (match) {
|
|
77
|
-
cached = match[1];
|
|
78
|
-
log.info(
|
|
79
|
-
{ externalAssistantId: cached },
|
|
80
|
-
"Resolved external assistant ID from BASE_DATA_DIR",
|
|
81
|
-
);
|
|
82
|
-
return cached;
|
|
83
|
-
}
|
|
30
|
+
const envName = process.env.VELLUM_ASSISTANT_NAME;
|
|
31
|
+
if (envName) {
|
|
32
|
+
cached = envName;
|
|
33
|
+
log.info(
|
|
34
|
+
{ externalAssistantId: cached },
|
|
35
|
+
"Resolved external assistant ID from VELLUM_ASSISTANT_NAME",
|
|
36
|
+
);
|
|
37
|
+
return cached;
|
|
84
38
|
}
|
|
85
39
|
|
|
86
40
|
cached = null;
|
|
@@ -259,6 +259,8 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
259
259
|
|
|
260
260
|
// Secrets
|
|
261
261
|
{ endpoint: "secrets", scopes: ["settings.write"] },
|
|
262
|
+
{ endpoint: "secrets:GET", scopes: ["settings.read"] },
|
|
263
|
+
{ endpoint: "secrets/read", scopes: ["settings.write"] },
|
|
262
264
|
|
|
263
265
|
// Pairing (authenticated)
|
|
264
266
|
{ endpoint: "pairing/register", scopes: ["settings.write"] },
|
|
@@ -352,6 +354,10 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
352
354
|
{ endpoint: "config/permissions/skip:GET", scopes: ["settings.read"] },
|
|
353
355
|
{ endpoint: "config/permissions/skip:PUT", scopes: ["settings.write"] },
|
|
354
356
|
|
|
357
|
+
// Generic config read/patch
|
|
358
|
+
{ endpoint: "config:GET", scopes: ["settings.read"] },
|
|
359
|
+
{ endpoint: "config:PATCH", scopes: ["settings.write"] },
|
|
360
|
+
|
|
355
361
|
// Conversation management
|
|
356
362
|
{ endpoint: "conversations:DELETE", scopes: ["chat.write"] },
|
|
357
363
|
{ endpoint: "conversations/wipe", scopes: ["chat.write"] },
|
|
@@ -366,6 +372,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
366
372
|
// Message content
|
|
367
373
|
{ endpoint: "messages/content", scopes: ["chat.read"] },
|
|
368
374
|
{ endpoint: "messages/llm-context", scopes: ["chat.read"] },
|
|
375
|
+
{ endpoint: "messages/tts", scopes: ["chat.read"] },
|
|
369
376
|
|
|
370
377
|
// Queued message deletion
|
|
371
378
|
{ endpoint: "messages/queued", scopes: ["chat.write"] },
|
|
@@ -443,7 +450,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
443
450
|
|
|
444
451
|
// Diagnostics
|
|
445
452
|
{ endpoint: "export", scopes: ["settings.read"] },
|
|
446
|
-
{ endpoint: "diagnostics/export", scopes: ["settings.read"] },
|
|
447
453
|
{ endpoint: "diagnostics/env-vars", scopes: ["settings.read"] },
|
|
448
454
|
|
|
449
455
|
// Dictation
|
|
@@ -512,3 +518,13 @@ registerPolicy("admin/upgrade-broadcast", {
|
|
|
512
518
|
requiredScopes: ["internal.write"],
|
|
513
519
|
allowedPrincipalTypes: ["svc_gateway"],
|
|
514
520
|
});
|
|
521
|
+
|
|
522
|
+
registerPolicy("admin/workspace-commit", {
|
|
523
|
+
requiredScopes: ["internal.write"],
|
|
524
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
registerPolicy("admin/rollback-migrations", {
|
|
528
|
+
requiredScopes: ["internal.write"],
|
|
529
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
530
|
+
});
|