@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
|
@@ -128,6 +128,7 @@ describe("TwiML parameter propagation", () => {
|
|
|
128
128
|
transcriptionProvider: "deepgram",
|
|
129
129
|
ttsProvider: "google",
|
|
130
130
|
voice: "en-US-Standard-A",
|
|
131
|
+
interruptSensitivity: "low",
|
|
131
132
|
};
|
|
132
133
|
|
|
133
134
|
test("includes verificationSessionId as Parameter when provided", () => {
|
|
@@ -1,31 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* and local mode (file-based load/create).
|
|
2
|
+
* Tests for resolveSigningKey() covering env var injection (Docker)
|
|
3
|
+
* and file-based load/create (local mode).
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
|
-
import {
|
|
6
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync } from "node:fs";
|
|
8
7
|
import { tmpdir } from "node:os";
|
|
9
8
|
import { join } from "node:path";
|
|
10
9
|
import { afterAll, afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
// Temp directory for signing key persistence
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
const testDir = realpathSync(mkdtempSync(join(tmpdir(), "docker-signing-key-test-")));
|
|
17
|
-
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
// Mock platform to redirect signing key file to our temp directory
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
11
|
+
const testDir = realpathSync(mkdtempSync(join(tmpdir(), "signing-key-test-")));
|
|
21
12
|
|
|
22
13
|
mock.module("../util/platform.js", () => ({
|
|
23
14
|
getRootDir: () => testDir,
|
|
24
15
|
getDataDir: () => testDir,
|
|
25
16
|
getDbPath: () => join(testDir, "test.db"),
|
|
26
17
|
normalizeAssistantId: (id: string) => (id === "self" ? "self" : id),
|
|
27
|
-
readLockfile: () => null,
|
|
28
|
-
writeLockfile: () => {},
|
|
29
18
|
isMacOS: () => process.platform === "darwin",
|
|
30
19
|
isLinux: () => process.platform === "linux",
|
|
31
20
|
isWindows: () => process.platform === "win32",
|
|
@@ -41,53 +30,23 @@ mock.module("../util/logger.js", () => ({
|
|
|
41
30
|
}),
|
|
42
31
|
}));
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
// Import the functions under test (after mocks are installed)
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
|
|
48
|
-
const {
|
|
49
|
-
resolveSigningKey,
|
|
50
|
-
loadOrCreateSigningKey: _loadOrCreateSigningKey,
|
|
51
|
-
BootstrapAlreadyCompleted: _BootstrapAlreadyCompleted,
|
|
52
|
-
} = await import("../runtime/auth/token-service.js");
|
|
53
|
-
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
// Test constants
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
33
|
+
const { resolveSigningKey } = await import("../runtime/auth/token-service.js");
|
|
57
34
|
|
|
58
|
-
const
|
|
59
|
-
const SIGNING_KEY_PATH = join(testDir, "protected", "actor-token-signing-key");
|
|
35
|
+
const VALID_HEX_KEY = "ab".repeat(32); // 64 hex chars = 32 bytes
|
|
60
36
|
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// Environment & fetch state management
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
|
|
65
|
-
const originalFetch = globalThis.fetch;
|
|
66
37
|
const savedEnv: Record<string, string | undefined> = {};
|
|
67
38
|
|
|
68
|
-
function saveEnv(...keys: string[]) {
|
|
69
|
-
for (const key of keys) {
|
|
70
|
-
savedEnv[key] = process.env[key];
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function restoreEnv() {
|
|
75
|
-
for (const [key, val] of Object.entries(savedEnv)) {
|
|
76
|
-
if (val === undefined) {
|
|
77
|
-
delete process.env[key];
|
|
78
|
-
} else {
|
|
79
|
-
process.env[key] = val;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
39
|
beforeEach(() => {
|
|
85
|
-
|
|
40
|
+
savedEnv.ACTOR_TOKEN_SIGNING_KEY = process.env.ACTOR_TOKEN_SIGNING_KEY;
|
|
41
|
+
mkdirSync(join(testDir, "protected"), { recursive: true });
|
|
86
42
|
});
|
|
87
43
|
|
|
88
44
|
afterEach(() => {
|
|
89
|
-
|
|
90
|
-
|
|
45
|
+
if (savedEnv.ACTOR_TOKEN_SIGNING_KEY === undefined) {
|
|
46
|
+
delete process.env.ACTOR_TOKEN_SIGNING_KEY;
|
|
47
|
+
} else {
|
|
48
|
+
process.env.ACTOR_TOKEN_SIGNING_KEY = savedEnv.ACTOR_TOKEN_SIGNING_KEY;
|
|
49
|
+
}
|
|
91
50
|
});
|
|
92
51
|
|
|
93
52
|
afterAll(() => {
|
|
@@ -96,112 +55,44 @@ afterAll(() => {
|
|
|
96
55
|
} catch {}
|
|
97
56
|
});
|
|
98
57
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
describe("resolveSigningKey — Docker bootstrap lifecycle", () => {
|
|
104
|
-
test("fresh bootstrap: fetches key from gateway and persists to disk", async () => {
|
|
105
|
-
process.env.IS_CONTAINERIZED = "true";
|
|
106
|
-
process.env.GATEWAY_INTERNAL_URL = "http://localhost:19876";
|
|
58
|
+
describe("resolveSigningKey", () => {
|
|
59
|
+
test("reads key from ACTOR_TOKEN_SIGNING_KEY env var", () => {
|
|
60
|
+
process.env.ACTOR_TOKEN_SIGNING_KEY = VALID_HEX_KEY;
|
|
107
61
|
|
|
108
|
-
|
|
109
|
-
globalThis.fetch = (async () =>
|
|
110
|
-
new Response(JSON.stringify({ key: VALID_32_BYTE_KEY }), {
|
|
111
|
-
status: 200,
|
|
112
|
-
headers: { "Content-Type": "application/json" },
|
|
113
|
-
})) as unknown as typeof fetch;
|
|
62
|
+
const key = resolveSigningKey();
|
|
114
63
|
|
|
115
|
-
const key = await resolveSigningKey();
|
|
116
|
-
|
|
117
|
-
// Verify the returned key is a 32-byte buffer with the expected content.
|
|
118
64
|
expect(key).toBeInstanceOf(Buffer);
|
|
119
65
|
expect(key.length).toBe(32);
|
|
120
|
-
expect(key.toString("hex")).toBe(
|
|
121
|
-
|
|
122
|
-
// Verify the key was persisted to disk.
|
|
123
|
-
const persisted = readFileSync(SIGNING_KEY_PATH);
|
|
124
|
-
expect(persisted.length).toBe(32);
|
|
125
|
-
expect(Buffer.from(persisted).equals(key)).toBe(true);
|
|
66
|
+
expect(key.toString("hex")).toBe(VALID_HEX_KEY);
|
|
126
67
|
});
|
|
127
68
|
|
|
128
|
-
test("
|
|
129
|
-
process.env.
|
|
130
|
-
process.env.GATEWAY_INTERNAL_URL = "http://localhost:19876";
|
|
69
|
+
test("rejects invalid ACTOR_TOKEN_SIGNING_KEY", () => {
|
|
70
|
+
process.env.ACTOR_TOKEN_SIGNING_KEY = "tooshort";
|
|
131
71
|
|
|
132
|
-
|
|
133
|
-
// the gateway returns 403 (bootstrap already completed).
|
|
134
|
-
globalThis.fetch = (async () =>
|
|
135
|
-
new Response(JSON.stringify({ error: "Bootstrap already completed" }), {
|
|
136
|
-
status: 403,
|
|
137
|
-
})) as unknown as typeof fetch;
|
|
138
|
-
|
|
139
|
-
const key = await resolveSigningKey();
|
|
140
|
-
|
|
141
|
-
// Should have loaded the previously persisted key from disk.
|
|
142
|
-
expect(key).toBeInstanceOf(Buffer);
|
|
143
|
-
expect(key.length).toBe(32);
|
|
144
|
-
expect(key.toString("hex")).toBe(VALID_32_BYTE_KEY);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
// Local mode tests — resolveSigningKey() file-based path
|
|
150
|
-
// ---------------------------------------------------------------------------
|
|
151
|
-
|
|
152
|
-
describe("resolveSigningKey — local mode", () => {
|
|
153
|
-
test("uses file-based loadOrCreateSigningKey without calling fetch", async () => {
|
|
154
|
-
// Ensure Docker env vars are unset.
|
|
155
|
-
delete process.env.IS_CONTAINERIZED;
|
|
156
|
-
delete process.env.GATEWAY_INTERNAL_URL;
|
|
157
|
-
|
|
158
|
-
let fetchCalled = false;
|
|
159
|
-
globalThis.fetch = (async () => {
|
|
160
|
-
fetchCalled = true;
|
|
161
|
-
return new Response("should not be called", { status: 500 });
|
|
162
|
-
}) as unknown as typeof fetch;
|
|
163
|
-
|
|
164
|
-
const key = await resolveSigningKey();
|
|
165
|
-
|
|
166
|
-
// Should return a valid 32-byte key (loaded from disk or newly created).
|
|
167
|
-
expect(key).toBeInstanceOf(Buffer);
|
|
168
|
-
expect(key.length).toBe(32);
|
|
169
|
-
|
|
170
|
-
// Crucially, fetch should NOT have been called.
|
|
171
|
-
expect(fetchCalled).toBe(false);
|
|
72
|
+
expect(() => resolveSigningKey()).toThrow("Invalid ACTOR_TOKEN_SIGNING_KEY");
|
|
172
73
|
});
|
|
173
74
|
|
|
174
|
-
test("
|
|
175
|
-
process.env.
|
|
176
|
-
process.env.GATEWAY_INTERNAL_URL = "http://localhost:19876";
|
|
75
|
+
test("falls back to file-based load/create when env var is not set", () => {
|
|
76
|
+
delete process.env.ACTOR_TOKEN_SIGNING_KEY;
|
|
177
77
|
|
|
178
|
-
|
|
179
|
-
globalThis.fetch = (async () => {
|
|
180
|
-
fetchCalled = true;
|
|
181
|
-
return new Response("should not be called", { status: 500 });
|
|
182
|
-
}) as unknown as typeof fetch;
|
|
183
|
-
|
|
184
|
-
const key = await resolveSigningKey();
|
|
78
|
+
const key = resolveSigningKey();
|
|
185
79
|
|
|
186
80
|
expect(key).toBeInstanceOf(Buffer);
|
|
187
81
|
expect(key.length).toBe(32);
|
|
188
|
-
expect(fetchCalled).toBe(false);
|
|
189
82
|
});
|
|
190
83
|
|
|
191
|
-
test("
|
|
192
|
-
process.env.
|
|
193
|
-
delete process.env.GATEWAY_INTERNAL_URL;
|
|
84
|
+
test("env var takes priority over file on disk", () => {
|
|
85
|
+
process.env.ACTOR_TOKEN_SIGNING_KEY = VALID_HEX_KEY;
|
|
194
86
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return new Response("should not be called", { status: 500 });
|
|
199
|
-
}) as unknown as typeof fetch;
|
|
87
|
+
// First call creates a file-based key
|
|
88
|
+
delete process.env.ACTOR_TOKEN_SIGNING_KEY;
|
|
89
|
+
const fileKey = resolveSigningKey();
|
|
200
90
|
|
|
201
|
-
|
|
91
|
+
// Second call with env var should use the env var, not the file
|
|
92
|
+
process.env.ACTOR_TOKEN_SIGNING_KEY = "cd".repeat(32);
|
|
93
|
+
const envKey = resolveSigningKey();
|
|
202
94
|
|
|
203
|
-
expect(
|
|
204
|
-
expect(
|
|
205
|
-
expect(fetchCalled).toBe(false);
|
|
95
|
+
expect(envKey.toString("hex")).toBe("cd".repeat(32));
|
|
96
|
+
expect(envKey.toString("hex")).not.toBe(fileKey.toString("hex"));
|
|
206
97
|
});
|
|
207
98
|
});
|
|
@@ -53,9 +53,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
53
53
|
|
|
54
54
|
mock.module("../config/loader.js", () => ({
|
|
55
55
|
getConfig: () => ({
|
|
56
|
-
assistantFeatureFlagValues: {
|
|
57
|
-
"feature_flags.browser.enabled": true,
|
|
58
|
-
},
|
|
59
56
|
services: {
|
|
60
57
|
inference: {
|
|
61
58
|
mode: "your-own",
|
|
@@ -77,17 +74,22 @@ mock.module("../config/loader.js", () => ({
|
|
|
77
74
|
invalidateConfigCache: () => {},
|
|
78
75
|
getNestedValue: () => undefined,
|
|
79
76
|
setNestedValue: () => {},
|
|
80
|
-
syncConfigToLockfile: () => {},
|
|
81
77
|
}));
|
|
82
78
|
|
|
83
79
|
const { buildSystemPrompt } = await import("../prompts/system-prompt.js");
|
|
80
|
+
const { _setOverridesForTesting } =
|
|
81
|
+
await import("../config/assistant-feature-flags.js");
|
|
84
82
|
|
|
85
83
|
describe("Dynamic Skill Authoring Workflow moved to tool descriptions", () => {
|
|
86
84
|
beforeEach(() => {
|
|
87
85
|
mkdirSync(TEST_DIR, { recursive: true });
|
|
86
|
+
_setOverridesForTesting({
|
|
87
|
+
"feature_flags.browser.enabled": true,
|
|
88
|
+
});
|
|
88
89
|
});
|
|
89
90
|
|
|
90
91
|
afterEach(() => {
|
|
92
|
+
_setOverridesForTesting({});
|
|
91
93
|
if (existsSync(TEST_DIR)) {
|
|
92
94
|
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
93
95
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ChannelDeliveryError,
|
|
5
|
+
deliverChannelReply,
|
|
6
|
+
} from "../runtime/gateway-client.js";
|
|
4
7
|
|
|
5
8
|
type FetchCall = {
|
|
6
9
|
url: string;
|
|
@@ -163,4 +166,79 @@ describe("gateway-client managed outbound lane", () => {
|
|
|
163
166
|
text: "standard gateway callback",
|
|
164
167
|
});
|
|
165
168
|
});
|
|
169
|
+
|
|
170
|
+
test("throws ChannelDeliveryError with userMessage when gateway returns JSON error with userMessage", async () => {
|
|
171
|
+
globalThis.fetch = mock(async () => {
|
|
172
|
+
return new Response(
|
|
173
|
+
JSON.stringify({
|
|
174
|
+
error: "Permission denied",
|
|
175
|
+
userMessage:
|
|
176
|
+
"The bot is not a member of this channel. Please invite it first.",
|
|
177
|
+
}),
|
|
178
|
+
{ status: 403 },
|
|
179
|
+
);
|
|
180
|
+
}) as unknown as typeof globalThis.fetch;
|
|
181
|
+
|
|
182
|
+
let caught: unknown;
|
|
183
|
+
try {
|
|
184
|
+
await deliverChannelReply("https://gateway.test/deliver/slack", {
|
|
185
|
+
chatId: "C123",
|
|
186
|
+
text: "hello",
|
|
187
|
+
});
|
|
188
|
+
} catch (err) {
|
|
189
|
+
caught = err;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
expect(caught).toBeInstanceOf(ChannelDeliveryError);
|
|
193
|
+
const deliveryError = caught as ChannelDeliveryError;
|
|
194
|
+
expect(deliveryError.statusCode).toBe(403);
|
|
195
|
+
expect(deliveryError.userMessage).toBe(
|
|
196
|
+
"The bot is not a member of this channel. Please invite it first.",
|
|
197
|
+
);
|
|
198
|
+
expect(deliveryError.message).toContain("403");
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("throws ChannelDeliveryError without userMessage when gateway returns JSON error without userMessage", async () => {
|
|
202
|
+
globalThis.fetch = mock(async () => {
|
|
203
|
+
return new Response(JSON.stringify({ error: "Delivery failed" }), {
|
|
204
|
+
status: 502,
|
|
205
|
+
});
|
|
206
|
+
}) as unknown as typeof globalThis.fetch;
|
|
207
|
+
|
|
208
|
+
let caught: unknown;
|
|
209
|
+
try {
|
|
210
|
+
await deliverChannelReply("https://gateway.test/deliver/slack", {
|
|
211
|
+
chatId: "C123",
|
|
212
|
+
text: "hello",
|
|
213
|
+
});
|
|
214
|
+
} catch (err) {
|
|
215
|
+
caught = err;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
expect(caught).toBeInstanceOf(ChannelDeliveryError);
|
|
219
|
+
const deliveryError = caught as ChannelDeliveryError;
|
|
220
|
+
expect(deliveryError.statusCode).toBe(502);
|
|
221
|
+
expect(deliveryError.userMessage).toBeUndefined();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("throws ChannelDeliveryError without userMessage when gateway returns non-JSON error", async () => {
|
|
225
|
+
globalThis.fetch = mock(async () => {
|
|
226
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
227
|
+
}) as unknown as typeof globalThis.fetch;
|
|
228
|
+
|
|
229
|
+
let caught: unknown;
|
|
230
|
+
try {
|
|
231
|
+
await deliverChannelReply("https://gateway.test/deliver/slack", {
|
|
232
|
+
chatId: "C123",
|
|
233
|
+
text: "hello",
|
|
234
|
+
});
|
|
235
|
+
} catch (err) {
|
|
236
|
+
caught = err;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
expect(caught).toBeInstanceOf(ChannelDeliveryError);
|
|
240
|
+
const deliveryError = caught as ChannelDeliveryError;
|
|
241
|
+
expect(deliveryError.statusCode).toBe(500);
|
|
242
|
+
expect(deliveryError.userMessage).toBeUndefined();
|
|
243
|
+
});
|
|
166
244
|
});
|
|
@@ -31,11 +31,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
31
31
|
}),
|
|
32
32
|
}));
|
|
33
33
|
|
|
34
|
-
// Mock security check to always pass
|
|
35
|
-
mock.module("../security/secret-ingress.js", () => ({
|
|
36
|
-
checkIngressForSecrets: () => ({ blocked: false }),
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
34
|
import { upsertContact } from "../contacts/contact-store.js";
|
|
40
35
|
import { createGuardianBinding } from "../contacts/contacts-write.js";
|
|
41
36
|
import type { TrustContext } from "../daemon/conversation-runtime-assembly.js";
|
|
@@ -846,12 +846,12 @@ describe("host_bash — proxy delegation", () => {
|
|
|
846
846
|
});
|
|
847
847
|
|
|
848
848
|
test("propagates VELLUM_UNTRUSTED_SHELL env to proxy under CES lockdown", async () => {
|
|
849
|
-
// Enable CES shell lockdown
|
|
850
|
-
const
|
|
851
|
-
.
|
|
852
|
-
(
|
|
849
|
+
// Enable CES shell lockdown via the override cache
|
|
850
|
+
const { _setOverridesForTesting } =
|
|
851
|
+
await import("../config/assistant-feature-flags.js");
|
|
852
|
+
_setOverridesForTesting({
|
|
853
853
|
"feature_flags.ces-shell-lockdown.enabled": true,
|
|
854
|
-
};
|
|
854
|
+
});
|
|
855
855
|
|
|
856
856
|
try {
|
|
857
857
|
const proxyResult: ToolExecutionResult = {
|
|
@@ -875,8 +875,7 @@ describe("host_bash — proxy delegation", () => {
|
|
|
875
875
|
expect(calls.length).toBe(1);
|
|
876
876
|
expect(calls[0].input.env).toEqual({ VELLUM_UNTRUSTED_SHELL: "1" });
|
|
877
877
|
} finally {
|
|
878
|
-
(
|
|
879
|
-
origFlags;
|
|
878
|
+
_setOverridesForTesting({});
|
|
880
879
|
}
|
|
881
880
|
});
|
|
882
881
|
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Tests for HTTP POST /v1/messages behavior after the legacy handleUserMessage
|
|
3
3
|
* legacy entry point was retired.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* through the agent loop.
|
|
5
|
+
* Recording intent interception has been deliberately retired — the HTTP path
|
|
6
|
+
* has dedicated /v1/recording/* endpoints and the model handles
|
|
7
|
+
* recording-related messages through the agent loop.
|
|
9
8
|
*
|
|
10
9
|
* Approval reply interception has parity and is covered by
|
|
11
10
|
* conversation-routes-guardian-reply.test.ts and send-endpoint-busy.test.ts.
|
|
@@ -121,12 +120,10 @@ mock.module("../runtime/trust-context-resolver.js", () => ({
|
|
|
121
120
|
}),
|
|
122
121
|
}));
|
|
123
122
|
|
|
124
|
-
// Mock config to enable secret detection + ingress blocking
|
|
125
123
|
mock.module("../config/loader.js", () => ({
|
|
126
124
|
getConfig: () => ({
|
|
127
125
|
secretDetection: {
|
|
128
126
|
enabled: true,
|
|
129
|
-
blockIngress: true,
|
|
130
127
|
customPatterns: [],
|
|
131
128
|
entropyThreshold: 3.5,
|
|
132
129
|
},
|
|
@@ -238,103 +235,6 @@ async function sendMessage(
|
|
|
238
235
|
);
|
|
239
236
|
}
|
|
240
237
|
|
|
241
|
-
// ============================================================================
|
|
242
|
-
// SECRET INGRESS BLOCKING — now ported to HTTP path
|
|
243
|
-
// ============================================================================
|
|
244
|
-
describe("HTTP POST /v1/messages blocks secret ingress", () => {
|
|
245
|
-
beforeEach(() => {
|
|
246
|
-
routeGuardianReplyMock.mockClear();
|
|
247
|
-
listPendingByDestinationMock.mockClear();
|
|
248
|
-
listCanonicalMock.mockClear();
|
|
249
|
-
addMessageMock.mockClear();
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test("handleSendMessage rejects messages containing Telegram bot token patterns", async () => {
|
|
253
|
-
const secretContent =
|
|
254
|
-
"Set up Telegram with my bot token 123456789:ABCDefGHIJklmnopQRSTuvwxyz012345678";
|
|
255
|
-
const persistUserMessage = mock(async () => "persisted-msg-id");
|
|
256
|
-
const runAgentLoop = mock(async () => undefined);
|
|
257
|
-
const conversation = makeConversation({ persistUserMessage, runAgentLoop });
|
|
258
|
-
|
|
259
|
-
const res = await sendMessage(secretContent, conversation);
|
|
260
|
-
|
|
261
|
-
expect(res.status).toBe(422);
|
|
262
|
-
const body = (await res.json()) as {
|
|
263
|
-
accepted: boolean;
|
|
264
|
-
error: string;
|
|
265
|
-
message: string;
|
|
266
|
-
detectedTypes: string[];
|
|
267
|
-
};
|
|
268
|
-
expect(body.accepted).toBe(false);
|
|
269
|
-
expect(body.error).toBe("secret_blocked");
|
|
270
|
-
expect(body.detectedTypes.length).toBeGreaterThan(0);
|
|
271
|
-
|
|
272
|
-
// The message should NOT reach the agent loop
|
|
273
|
-
expect(persistUserMessage).toHaveBeenCalledTimes(0);
|
|
274
|
-
expect(runAgentLoop).toHaveBeenCalledTimes(0);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
test("handleSendMessage rejects messages containing AWS credentials", async () => {
|
|
278
|
-
const secretContent =
|
|
279
|
-
"Here is my AWS key AKIAQRSTUVWXYZ123456 and secret wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
|
|
280
|
-
const persistUserMessage = mock(async () => "persisted-msg-id");
|
|
281
|
-
const runAgentLoop = mock(async () => undefined);
|
|
282
|
-
const conversation = makeConversation({ persistUserMessage, runAgentLoop });
|
|
283
|
-
|
|
284
|
-
const res = await sendMessage(secretContent, conversation);
|
|
285
|
-
|
|
286
|
-
expect(res.status).toBe(422);
|
|
287
|
-
const body = (await res.json()) as {
|
|
288
|
-
accepted: boolean;
|
|
289
|
-
error: string;
|
|
290
|
-
};
|
|
291
|
-
expect(body.accepted).toBe(false);
|
|
292
|
-
expect(body.error).toBe("secret_blocked");
|
|
293
|
-
|
|
294
|
-
// The message should NOT reach the agent loop
|
|
295
|
-
expect(persistUserMessage).toHaveBeenCalledTimes(0);
|
|
296
|
-
expect(runAgentLoop).toHaveBeenCalledTimes(0);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
test("handleSendMessage rejects messages containing Stripe live API keys", async () => {
|
|
300
|
-
const secretContent = "My Stripe key is sk_live_4eC39HqLyjWDarjtT1zdp7dc";
|
|
301
|
-
const persistUserMessage = mock(async () => "persisted-msg-id");
|
|
302
|
-
const runAgentLoop = mock(async () => undefined);
|
|
303
|
-
const conversation = makeConversation({ persistUserMessage, runAgentLoop });
|
|
304
|
-
|
|
305
|
-
const res = await sendMessage(secretContent, conversation);
|
|
306
|
-
|
|
307
|
-
expect(res.status).toBe(422);
|
|
308
|
-
const body = (await res.json()) as {
|
|
309
|
-
accepted: boolean;
|
|
310
|
-
error: string;
|
|
311
|
-
};
|
|
312
|
-
expect(body.accepted).toBe(false);
|
|
313
|
-
expect(body.error).toBe("secret_blocked");
|
|
314
|
-
|
|
315
|
-
// The message should NOT reach the agent loop
|
|
316
|
-
expect(persistUserMessage).toHaveBeenCalledTimes(0);
|
|
317
|
-
expect(runAgentLoop).toHaveBeenCalledTimes(0);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
test("handleSendMessage allows normal messages without secrets", async () => {
|
|
321
|
-
const normalContent = "What is the weather today?";
|
|
322
|
-
const persistUserMessage = mock(async () => "persisted-msg-id");
|
|
323
|
-
const runAgentLoop = mock(async () => undefined);
|
|
324
|
-
const conversation = makeConversation({ persistUserMessage, runAgentLoop });
|
|
325
|
-
|
|
326
|
-
const res = await sendMessage(normalContent, conversation);
|
|
327
|
-
|
|
328
|
-
expect(res.status).toBe(202);
|
|
329
|
-
const body = (await res.json()) as { accepted: boolean };
|
|
330
|
-
expect(body.accepted).toBe(true);
|
|
331
|
-
|
|
332
|
-
// Normal messages proceed to the agent loop
|
|
333
|
-
expect(persistUserMessage).toHaveBeenCalledTimes(1);
|
|
334
|
-
expect(runAgentLoop).toHaveBeenCalledTimes(1);
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
238
|
// ============================================================================
|
|
339
239
|
// RECORDING INTENT — deliberately NOT intercepted on HTTP path
|
|
340
240
|
// ============================================================================
|
|
@@ -35,10 +35,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
35
35
|
}),
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
|
-
mock.module("../security/secret-ingress.js", () => ({
|
|
39
|
-
checkIngressForSecrets: () => ({ blocked: false }),
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
38
|
mock.module("../config/env.js", () => ({
|
|
43
39
|
isHttpAuthDisabled: () => true,
|
|
44
40
|
getGatewayInternalBaseUrl: () => "http://127.0.0.1:7830",
|
|
@@ -18,6 +18,8 @@ import { tmpdir } from "node:os";
|
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
20
20
|
|
|
21
|
+
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
22
|
+
|
|
21
23
|
// ── Mock setup (must be before any imports from the project) ──────────────
|
|
22
24
|
|
|
23
25
|
const testDir = mkdtempSync(join(tmpdir(), "inline-skill-perm-test-"));
|
|
@@ -46,7 +48,6 @@ interface TestConfig {
|
|
|
46
48
|
permissions: { mode: "strict" | "workspace" };
|
|
47
49
|
skills: { load: { extraDirs: string[] } };
|
|
48
50
|
sandbox: { enabled: boolean };
|
|
49
|
-
assistantFeatureFlagValues?: Record<string, boolean>;
|
|
50
51
|
[key: string]: unknown;
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -54,9 +55,6 @@ const testConfig: TestConfig = {
|
|
|
54
55
|
permissions: { mode: "workspace" },
|
|
55
56
|
skills: { load: { extraDirs: [] } },
|
|
56
57
|
sandbox: { enabled: true },
|
|
57
|
-
assistantFeatureFlagValues: {
|
|
58
|
-
"feature_flags.inline-skill-commands.enabled": true,
|
|
59
|
-
},
|
|
60
58
|
};
|
|
61
59
|
|
|
62
60
|
mock.module("../config/loader.js", () => ({
|
|
@@ -118,9 +116,9 @@ describe("inline-command skill_load permissions", () => {
|
|
|
118
116
|
clearCache();
|
|
119
117
|
testConfig.permissions = { mode: "workspace" };
|
|
120
118
|
testConfig.skills = { load: { extraDirs: [] } };
|
|
121
|
-
|
|
119
|
+
_setOverridesForTesting({
|
|
122
120
|
"feature_flags.inline-skill-commands.enabled": true,
|
|
123
|
-
};
|
|
121
|
+
});
|
|
124
122
|
try {
|
|
125
123
|
rmSync(join(testDir, "protected", "trust.json"));
|
|
126
124
|
} catch {
|
|
@@ -352,9 +350,9 @@ describe("inline-command skill_load permissions", () => {
|
|
|
352
350
|
writeDynamicSkill("dynamic-flag-off", "Dynamic Flag Off Skill");
|
|
353
351
|
|
|
354
352
|
// Disable the feature flag
|
|
355
|
-
|
|
353
|
+
_setOverridesForTesting({
|
|
356
354
|
"feature_flags.inline-skill-commands.enabled": false,
|
|
357
|
-
};
|
|
355
|
+
});
|
|
358
356
|
|
|
359
357
|
const result = await check(
|
|
360
358
|
"skill_load",
|
|
@@ -53,8 +53,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
53
53
|
mock.module("../config/loader.js", () => ({
|
|
54
54
|
getConfig: () => ({
|
|
55
55
|
ui: {},
|
|
56
|
-
|
|
57
|
-
assistantFeatureFlagValues: {},
|
|
58
56
|
services: {
|
|
59
57
|
inference: {
|
|
60
58
|
mode: "your-own",
|
|
@@ -76,7 +74,6 @@ mock.module("../config/loader.js", () => ({
|
|
|
76
74
|
invalidateConfigCache: () => {},
|
|
77
75
|
getNestedValue: () => undefined,
|
|
78
76
|
setNestedValue: () => {},
|
|
79
|
-
syncConfigToLockfile: () => {},
|
|
80
77
|
}));
|
|
81
78
|
|
|
82
79
|
// ── Import after mocks ───────────────────────────────────────────────
|
|
@@ -250,16 +247,6 @@ describe("Activation hints in skills catalog", () => {
|
|
|
250
247
|
expect(line).toContain("voice-setup");
|
|
251
248
|
});
|
|
252
249
|
|
|
253
|
-
test("orchestration skill includes hints and avoid-when in catalog line", () => {
|
|
254
|
-
const prompt = buildSystemPrompt();
|
|
255
|
-
const line = prompt
|
|
256
|
-
.split("\n")
|
|
257
|
-
.find((l) => l.includes("**orchestration**"));
|
|
258
|
-
expect(line).toBeDefined();
|
|
259
|
-
expect(line).toContain("parallel");
|
|
260
|
-
expect(line).toContain("Single-focus");
|
|
261
|
-
});
|
|
262
|
-
|
|
263
250
|
test("browser skill includes hints in catalog line", () => {
|
|
264
251
|
const prompt = buildSystemPrompt();
|
|
265
252
|
const line = prompt.split("\n").find((l) => l.includes("**browser**"));
|