@vellumai/assistant 0.5.5 → 0.5.7
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 +4 -5
- package/README.md +0 -2
- package/bun.lock +0 -414
- package/docs/architecture/keychain-broker.md +45 -240
- 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/rpc.ts +119 -0
- 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 +1 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
- package/src/__tests__/browser-skill-endstate.test.ts +6 -5
- package/src/__tests__/btw-routes.test.ts +0 -39
- package/src/__tests__/call-domain.test.ts +0 -128
- package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -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 -1
- package/src/__tests__/config-schema.test.ts +3 -3
- package/src/__tests__/context-window-manager.test.ts +78 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-skill-tools.test.ts +0 -54
- package/src/__tests__/conversation-title-service.test.ts +117 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
- package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
- package/src/__tests__/credential-security-e2e.test.ts +0 -66
- package/src/__tests__/credential-security-invariants.test.ts +4 -45
- package/src/__tests__/credentials-cli.test.ts +78 -0
- package/src/__tests__/db-migration-rollback.test.ts +2015 -1
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
- 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__/keychain-broker-client.test.ts +161 -22
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
- package/src/__tests__/memory-regressions.test.ts +8 -30
- 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 +0 -5
- package/src/__tests__/notification-decision-fallback.test.ts +4 -0
- package/src/__tests__/notification-decision-identity.test.ts +4 -0
- package/src/__tests__/permission-types.test.ts +1 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
- package/src/__tests__/qdrant-manager.test.ts +28 -2
- package/src/__tests__/registry.test.ts +0 -6
- package/src/__tests__/require-fresh-approval.test.ts +4 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
- package/src/__tests__/secure-keys.test.ts +83 -263
- 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-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__/suggestion-routes.test.ts +1 -32
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
- package/src/__tests__/tool-executor.test.ts +4 -0
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
- 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-scoped-grant-consumer.test.ts +0 -6
- 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 +218 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
- package/src/calls/audio-store.test.ts +97 -0
- package/src/calls/audio-store.ts +205 -0
- package/src/calls/call-controller.ts +85 -7
- package/src/calls/call-domain.ts +3 -0
- package/src/calls/call-store.ts +10 -3
- package/src/calls/fish-audio-client.ts +117 -0
- package/src/calls/relay-server.ts +27 -0
- package/src/calls/twilio-routes.ts +2 -1
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-ingress-preflight.ts +0 -42
- package/src/calls/voice-quality.ts +26 -5
- package/src/calls/voice-session-bridge.ts +6 -12
- package/src/cli/commands/config.ts +1 -4
- package/src/cli/commands/conversations.ts +0 -18
- package/src/cli/commands/credentials.ts +34 -4
- package/src/cli/commands/oauth/index.ts +7 -0
- package/src/cli/commands/oauth/platform.ts +179 -0
- package/src/cli/commands/platform.ts +3 -3
- package/src/config/assistant-feature-flags.ts +186 -5
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
- package/src/config/bundled-tool-registry.ts +1 -11
- package/src/config/env-registry.ts +1 -1
- package/src/config/env.ts +16 -16
- package/src/config/feature-flag-registry.json +48 -16
- package/src/config/loader.ts +98 -31
- package/src/config/schema.ts +4 -25
- package/src/config/schemas/calls.ts +13 -0
- package/src/config/schemas/fish-audio.ts +39 -0
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/platform.ts +1 -1
- package/src/config/schemas/security.ts +4 -4
- package/src/config/types.ts +0 -1
- package/src/contacts/contact-store.ts +39 -0
- package/src/contacts/types.ts +2 -0
- package/src/context/window-manager.ts +53 -2
- 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/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/config-watcher.ts +6 -4
- package/src/daemon/conversation-agent-loop.ts +0 -60
- package/src/daemon/conversation-memory.ts +0 -117
- package/src/daemon/conversation-runtime-assembly.ts +0 -2
- package/src/daemon/conversation-tool-setup.ts +0 -105
- package/src/daemon/conversation.ts +10 -1
- package/src/daemon/handlers/config-vercel.ts +92 -0
- package/src/daemon/handlers/conversations.ts +0 -11
- package/src/daemon/handlers/skills.ts +2 -15
- package/src/daemon/install-symlink.ts +195 -0
- package/src/daemon/lifecycle.ts +229 -96
- package/src/daemon/message-types/conversations.ts +3 -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 +30 -92
- package/src/events/domain-events.ts +2 -1
- package/src/followups/followup-store.ts +5 -2
- package/src/inbound/platform-callback-registration.ts +3 -3
- package/src/instrument.ts +8 -5
- package/src/memory/conversation-crud.ts +0 -236
- package/src/memory/conversation-title-service.ts +76 -11
- package/src/memory/db-init.ts +15 -11
- package/src/memory/indexer.ts +15 -106
- package/src/memory/items-extractor.ts +15 -1
- package/src/memory/job-handlers/conversation-starters.ts +4 -1
- package/src/memory/job-handlers/embedding.ts +0 -79
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +30 -13
- package/src/memory/jobs-worker.ts +31 -27
- 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/189-drop-simplified-memory.ts +42 -0
- 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/index.ts +5 -3
- package/src/memory/migrations/registry.ts +90 -0
- package/src/memory/migrations/validate-migration-state.ts +137 -11
- package/src/memory/qdrant-circuit-breaker.ts +9 -0
- package/src/memory/qdrant-client.ts +4 -6
- package/src/memory/qdrant-manager.ts +64 -7
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/conversations.ts +0 -3
- package/src/memory/schema/index.ts +0 -2
- package/src/messaging/draft-store.ts +2 -2
- package/src/notifications/decision-engine.ts +4 -1
- package/src/oauth/connection-resolver.ts +6 -4
- package/src/permissions/checker.ts +0 -38
- package/src/permissions/defaults.ts +3 -3
- package/src/permissions/shell-identity.ts +76 -22
- package/src/permissions/trust-client.ts +2 -13
- package/src/permissions/trust-store.ts +8 -3
- package/src/permissions/types.ts +4 -2
- package/src/platform/client.ts +35 -7
- package/src/prompts/persona-resolver.ts +138 -0
- package/src/prompts/system-prompt.ts +36 -4
- package/src/prompts/templates/users/default.md +1 -0
- package/src/providers/registry.ts +27 -40
- 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/external-assistant-id.ts +13 -59
- package/src/runtime/auth/route-policy.ts +29 -1
- package/src/runtime/auth/token-service.ts +53 -15
- package/src/runtime/channel-readiness-service.ts +1 -16
- package/src/runtime/http-server.ts +29 -2
- package/src/runtime/middleware/error-handler.ts +1 -9
- package/src/runtime/routes/audio-routes.ts +40 -0
- package/src/runtime/routes/btw-routes.ts +0 -17
- package/src/runtime/routes/conversation-management-routes.ts +0 -36
- package/src/runtime/routes/conversation-query-routes.ts +106 -2
- package/src/runtime/routes/conversation-routes.ts +4 -43
- package/src/runtime/routes/diagnostics-routes.ts +1 -477
- package/src/runtime/routes/identity-routes.ts +18 -29
- 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/vercel.ts +89 -0
- package/src/runtime/routes/log-export-routes.ts +5 -0
- package/src/runtime/routes/memory-item-routes.test.ts +221 -3
- package/src/runtime/routes/memory-item-routes.ts +144 -4
- 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/settings-routes.ts +41 -1
- package/src/runtime/routes/tts-routes.ts +86 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
- 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/schedule/schedule-store.ts +0 -21
- package/src/security/ces-credential-client.ts +59 -22
- package/src/security/ces-rpc-credential-backend.ts +85 -0
- package/src/security/credential-backend.ts +12 -88
- package/src/security/keychain-broker-client.ts +10 -2
- package/src/security/secure-keys.ts +94 -113
- package/src/skills/catalog-install.ts +13 -7
- package/src/skills/inline-command-render.ts +5 -1
- package/src/skills/inline-command-runner.ts +30 -2
- package/src/telemetry/usage-telemetry-reporter.ts +4 -2
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/executor.ts +0 -4
- package/src/tools/memory/handlers.ts +1 -129
- package/src/tools/network/script-proxy/session-manager.ts +19 -4
- package/src/tools/network/web-fetch.ts +3 -1
- package/src/tools/permission-checker.ts +18 -0
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +9 -2
- package/src/tools/types.ts +0 -8
- package/src/util/errors.ts +0 -12
- package/src/util/platform.ts +8 -55
- package/src/util/xml.ts +8 -0
- package/src/workspace/git-service.ts +5 -2
- package/src/workspace/heartbeat-service.ts +5 -24
- 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 +95 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +106 -2
- package/src/workspace/migrations/types.ts +4 -0
- package/src/__tests__/archive-recall.test.ts +0 -560
- 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__/conversation-memory-dirty-tail.test.ts +0 -150
- package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
- package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
- package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
- package/src/__tests__/diagnostics-export.test.ts +0 -288
- package/src/__tests__/local-gateway-health.test.ts +0 -209
- package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
- package/src/__tests__/memory-brief-time.test.ts +0 -285
- package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
- package/src/__tests__/memory-chunk-archive.test.ts +0 -400
- package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
- package/src/__tests__/memory-episode-archive.test.ts +0 -370
- package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
- package/src/__tests__/memory-observation-archive.test.ts +0 -375
- package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
- package/src/__tests__/memory-reducer-job.test.ts +0 -538
- package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
- package/src/__tests__/memory-reducer-store.test.ts +0 -728
- package/src/__tests__/memory-reducer-types.test.ts +0 -707
- package/src/__tests__/memory-reducer.test.ts +0 -704
- package/src/__tests__/memory-simplified-config.test.ts +0 -281
- package/src/__tests__/secret-ingress-handler.test.ts +0 -120
- package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
- package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
- 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/memory-simplified.ts +0 -101
- package/src/config/schemas/swarm.ts +0 -82
- package/src/logfire.ts +0 -135
- package/src/memory/archive-recall.ts +0 -516
- package/src/memory/archive-store.ts +0 -400
- package/src/memory/brief-formatting.ts +0 -33
- package/src/memory/brief-open-loops.ts +0 -266
- package/src/memory/brief-time.ts +0 -162
- package/src/memory/brief.ts +0 -75
- package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
- package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
- package/src/memory/migrations/185-memory-brief-state.ts +0 -52
- package/src/memory/migrations/186-memory-archive.ts +0 -109
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
- package/src/memory/reducer-scheduler.ts +0 -242
- package/src/memory/reducer-store.ts +0 -271
- package/src/memory/reducer-types.ts +0 -106
- package/src/memory/reducer.ts +0 -467
- package/src/memory/schema/memory-archive.ts +0 -121
- package/src/memory/schema/memory-brief.ts +0 -55
- 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,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
|
});
|
|
@@ -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;
|
|
@@ -176,6 +176,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
176
176
|
|
|
177
177
|
// Settings / integrations / identity
|
|
178
178
|
{ endpoint: "identity", scopes: ["settings.read"] },
|
|
179
|
+
{ endpoint: "identity/intro", scopes: ["settings.read"] },
|
|
179
180
|
{ endpoint: "brain-graph", scopes: ["settings.read"] },
|
|
180
181
|
{ endpoint: "brain-graph-ui", scopes: ["settings.read"] },
|
|
181
182
|
{ endpoint: "contacts", scopes: ["settings.read"] },
|
|
@@ -347,6 +348,14 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
347
348
|
{ endpoint: "config/embeddings:GET", scopes: ["settings.read"] },
|
|
348
349
|
{ endpoint: "config/embeddings:PUT", scopes: ["settings.write"] },
|
|
349
350
|
|
|
351
|
+
// Permissions config
|
|
352
|
+
{ endpoint: "config/permissions/skip:GET", scopes: ["settings.read"] },
|
|
353
|
+
{ endpoint: "config/permissions/skip:PUT", scopes: ["settings.write"] },
|
|
354
|
+
|
|
355
|
+
// Generic config read/patch
|
|
356
|
+
{ endpoint: "config:GET", scopes: ["settings.read"] },
|
|
357
|
+
{ endpoint: "config:PATCH", scopes: ["settings.write"] },
|
|
358
|
+
|
|
350
359
|
// Conversation management
|
|
351
360
|
{ endpoint: "conversations:DELETE", scopes: ["chat.write"] },
|
|
352
361
|
{ endpoint: "conversations/wipe", scopes: ["chat.write"] },
|
|
@@ -355,9 +364,13 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
355
364
|
// Conversation search
|
|
356
365
|
{ endpoint: "conversations/search", scopes: ["chat.read"] },
|
|
357
366
|
|
|
367
|
+
// Conversation starters
|
|
368
|
+
{ endpoint: "conversation-starters", scopes: ["chat.read"] },
|
|
369
|
+
|
|
358
370
|
// Message content
|
|
359
371
|
{ endpoint: "messages/content", scopes: ["chat.read"] },
|
|
360
372
|
{ endpoint: "messages/llm-context", scopes: ["chat.read"] },
|
|
373
|
+
{ endpoint: "messages/tts", scopes: ["chat.read"] },
|
|
361
374
|
|
|
362
375
|
// Queued message deletion
|
|
363
376
|
{ endpoint: "messages/queued", scopes: ["chat.write"] },
|
|
@@ -435,7 +448,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
435
448
|
|
|
436
449
|
// Diagnostics
|
|
437
450
|
{ endpoint: "export", scopes: ["settings.read"] },
|
|
438
|
-
{ endpoint: "diagnostics/export", scopes: ["settings.read"] },
|
|
439
451
|
{ endpoint: "diagnostics/env-vars", scopes: ["settings.read"] },
|
|
440
452
|
|
|
441
453
|
// Dictation
|
|
@@ -498,3 +510,19 @@ for (const endpoint of INTERNAL_ENDPOINTS) {
|
|
|
498
510
|
allowedPrincipalTypes: ["svc_gateway"],
|
|
499
511
|
});
|
|
500
512
|
}
|
|
513
|
+
|
|
514
|
+
// Admin control-plane endpoints: gateway-only
|
|
515
|
+
registerPolicy("admin/upgrade-broadcast", {
|
|
516
|
+
requiredScopes: ["internal.write"],
|
|
517
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
registerPolicy("admin/workspace-commit", {
|
|
521
|
+
requiredScopes: ["internal.write"],
|
|
522
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
registerPolicy("admin/rollback-migrations", {
|
|
526
|
+
requiredScopes: ["internal.write"],
|
|
527
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
528
|
+
});
|
|
@@ -42,28 +42,44 @@ function getSigningKeyPath(): string {
|
|
|
42
42
|
return join(getRootDir(), "protected", "actor-token-signing-key");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Load a signing key from disk. Returns the key buffer if found and valid,
|
|
47
|
+
* or undefined if the file does not exist or is invalid.
|
|
48
|
+
*
|
|
49
|
+
* Used in the Docker 403-fallback path where generating a new key would
|
|
50
|
+
* create a mismatch with the gateway's already-bootstrapped key.
|
|
51
|
+
*/
|
|
52
|
+
export function loadSigningKey(): Buffer | undefined {
|
|
53
|
+
const keyPath = getSigningKeyPath();
|
|
54
|
+
if (!existsSync(keyPath)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const raw = readFileSync(keyPath);
|
|
59
|
+
if (raw.length === 32) {
|
|
60
|
+
log.info("Auth signing key loaded from disk");
|
|
61
|
+
return raw;
|
|
62
|
+
}
|
|
63
|
+
log.warn("Signing key file has unexpected length");
|
|
64
|
+
return undefined;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.warn({ err }, "Failed to read signing key file");
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
45
71
|
/**
|
|
46
72
|
* Load a signing key from disk or generate and persist a new one.
|
|
47
73
|
* Uses atomic-write + chmod 0o600 for safe persistence.
|
|
48
74
|
*/
|
|
49
75
|
export function loadOrCreateSigningKey(): Buffer {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (existsSync(keyPath)) {
|
|
54
|
-
try {
|
|
55
|
-
const raw = readFileSync(keyPath);
|
|
56
|
-
if (raw.length === 32) {
|
|
57
|
-
log.info("Auth signing key loaded from disk");
|
|
58
|
-
return raw;
|
|
59
|
-
}
|
|
60
|
-
log.warn("Signing key file has unexpected length, regenerating");
|
|
61
|
-
} catch (err) {
|
|
62
|
-
log.warn({ err }, "Failed to read signing key file, regenerating");
|
|
63
|
-
}
|
|
76
|
+
const existing = loadSigningKey();
|
|
77
|
+
if (existing) {
|
|
78
|
+
return existing;
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
// Generate and persist a new key
|
|
82
|
+
const keyPath = getSigningKeyPath();
|
|
67
83
|
const newKey = randomBytes(32);
|
|
68
84
|
const dir = dirname(keyPath);
|
|
69
85
|
if (!existsSync(dir)) {
|
|
@@ -78,6 +94,28 @@ export function loadOrCreateSigningKey(): Buffer {
|
|
|
78
94
|
return newKey;
|
|
79
95
|
}
|
|
80
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the signing key for the current environment.
|
|
99
|
+
*
|
|
100
|
+
* Resolution order:
|
|
101
|
+
* 1. ACTOR_TOKEN_SIGNING_KEY env var (hex-encoded, set by CLI for Docker)
|
|
102
|
+
* 2. File-based load/create (~/.vellum/protected/actor-token-signing-key)
|
|
103
|
+
*/
|
|
104
|
+
export function resolveSigningKey(): Buffer {
|
|
105
|
+
const envKey = process.env.ACTOR_TOKEN_SIGNING_KEY;
|
|
106
|
+
if (envKey) {
|
|
107
|
+
if (!/^[0-9a-f]{64}$/i.test(envKey)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Invalid ACTOR_TOKEN_SIGNING_KEY: expected 64 hex characters, got ${envKey.length} chars`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
log.info("Signing key loaded from ACTOR_TOKEN_SIGNING_KEY env var");
|
|
113
|
+
return Buffer.from(envKey, "hex");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return loadOrCreateSigningKey();
|
|
117
|
+
}
|
|
118
|
+
|
|
81
119
|
function getSigningKey(): Buffer {
|
|
82
120
|
if (!_authSigningKey) {
|
|
83
121
|
if (process.env.NODE_ENV === "test") {
|
|
@@ -113,7 +151,7 @@ export function isSigningKeyInitialized(): boolean {
|
|
|
113
151
|
|
|
114
152
|
/**
|
|
115
153
|
* Returns a short hex fingerprint of the current signing key.
|
|
116
|
-
* Used by
|
|
154
|
+
* Used by assistant_status to let clients detect instance switches.
|
|
117
155
|
*/
|
|
118
156
|
export function getSigningKeyFingerprint(): string {
|
|
119
157
|
return createHash("sha256")
|
|
@@ -15,7 +15,6 @@ import type {
|
|
|
15
15
|
ReadinessCheckResult,
|
|
16
16
|
SetupStatus,
|
|
17
17
|
} from "./channel-readiness-types.js";
|
|
18
|
-
import { probeLocalGatewayHealth } from "./local-gateway-health.js";
|
|
19
18
|
|
|
20
19
|
/** Remote check results are cached for 5 minutes before being considered stale. */
|
|
21
20
|
export const REMOTE_TTL_MS = 5 * 60 * 1000;
|
|
@@ -82,7 +81,7 @@ const voiceProbe: ChannelProbe = {
|
|
|
82
81
|
const hasPhone = !!resolveTwilioPhoneNumber();
|
|
83
82
|
const ingress = checkIngress();
|
|
84
83
|
|
|
85
|
-
|
|
84
|
+
return [
|
|
86
85
|
check(
|
|
87
86
|
"twilio_credentials",
|
|
88
87
|
hasCreds,
|
|
@@ -97,20 +96,6 @@ const voiceProbe: ChannelProbe = {
|
|
|
97
96
|
),
|
|
98
97
|
ingress,
|
|
99
98
|
];
|
|
100
|
-
|
|
101
|
-
if (ingress.passed) {
|
|
102
|
-
const gw = await probeLocalGatewayHealth();
|
|
103
|
-
checks.push(
|
|
104
|
-
check(
|
|
105
|
-
"gateway_health",
|
|
106
|
-
gw.healthy,
|
|
107
|
-
`Local gateway is serving requests at ${gw.target}`,
|
|
108
|
-
`Local gateway is not serving requests at ${gw.target}${gw.error ? `: ${gw.error}` : ""}`,
|
|
109
|
-
),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return checks;
|
|
114
99
|
},
|
|
115
100
|
};
|
|
116
101
|
|
|
@@ -106,6 +106,7 @@ import { handleServePage } from "./routes/app-routes.js";
|
|
|
106
106
|
import { appRouteDefinitions } from "./routes/app-routes.js";
|
|
107
107
|
import { approvalRouteDefinitions } from "./routes/approval-routes.js";
|
|
108
108
|
import { attachmentRouteDefinitions } from "./routes/attachment-routes.js";
|
|
109
|
+
import { handleGetAudio } from "./routes/audio-routes.js";
|
|
109
110
|
import { avatarRouteDefinitions } from "./routes/avatar-routes.js";
|
|
110
111
|
import { brainGraphRouteDefinitions } from "./routes/brain-graph-routes.js";
|
|
111
112
|
import { btwRouteDefinitions } from "./routes/btw-routes.js";
|
|
@@ -144,16 +145,19 @@ import { handleGuardianRefresh } from "./routes/guardian-refresh-routes.js";
|
|
|
144
145
|
import { hostBashRouteDefinitions } from "./routes/host-bash-routes.js";
|
|
145
146
|
import { hostCuRouteDefinitions } from "./routes/host-cu-routes.js";
|
|
146
147
|
import { hostFileRouteDefinitions } from "./routes/host-file-routes.js";
|
|
147
|
-
import { handleHealth } from "./routes/identity-routes.js";
|
|
148
|
+
import { handleHealth, handleReadyz } from "./routes/identity-routes.js";
|
|
148
149
|
import { identityRouteDefinitions } from "./routes/identity-routes.js";
|
|
149
150
|
import { slackChannelRouteDefinitions } from "./routes/integrations/slack/channel.js";
|
|
150
151
|
import { slackShareRouteDefinitions } from "./routes/integrations/slack/share.js";
|
|
151
152
|
import { telegramRouteDefinitions } from "./routes/integrations/telegram.js";
|
|
152
153
|
import { twilioRouteDefinitions } from "./routes/integrations/twilio.js";
|
|
154
|
+
import { vercelRouteDefinitions } from "./routes/integrations/vercel.js";
|
|
153
155
|
import { inviteRouteDefinitions } from "./routes/invite-routes.js";
|
|
154
156
|
import { logExportRouteDefinitions } from "./routes/log-export-routes.js";
|
|
155
157
|
import { memoryItemRouteDefinitions } from "./routes/memory-item-routes.js";
|
|
158
|
+
import { migrationRollbackRouteDefinitions } from "./routes/migration-rollback-routes.js";
|
|
156
159
|
import { migrationRouteDefinitions } from "./routes/migration-routes.js";
|
|
160
|
+
import { notificationRouteDefinitions } from "./routes/notification-routes.js";
|
|
157
161
|
import { oauthAppsRouteDefinitions } from "./routes/oauth-apps.js";
|
|
158
162
|
import type { PairingHandlerContext } from "./routes/pairing-routes.js";
|
|
159
163
|
import {
|
|
@@ -172,9 +176,12 @@ import { surfaceContentRouteDefinitions } from "./routes/surface-content-routes.
|
|
|
172
176
|
import { telemetryRouteDefinitions } from "./routes/telemetry-routes.js";
|
|
173
177
|
import { traceEventRouteDefinitions } from "./routes/trace-event-routes.js";
|
|
174
178
|
import { trustRulesRouteDefinitions } from "./routes/trust-rules-routes.js";
|
|
179
|
+
import { ttsRouteDefinitions } from "./routes/tts-routes.js";
|
|
180
|
+
import { upgradeBroadcastRouteDefinitions } from "./routes/upgrade-broadcast-routes.js";
|
|
175
181
|
import { usageRouteDefinitions } from "./routes/usage-routes.js";
|
|
176
182
|
import { watchRouteDefinitions } from "./routes/watch-routes.js";
|
|
177
183
|
import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
|
|
184
|
+
import { workspaceCommitRouteDefinitions } from "./routes/workspace-commit-routes.js";
|
|
178
185
|
import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
|
|
179
186
|
|
|
180
187
|
// Re-export for consumers
|
|
@@ -463,7 +470,10 @@ export class RuntimeHttpServer {
|
|
|
463
470
|
server.timeout(req, 1800);
|
|
464
471
|
// Skip request logging for health-check probes to reduce log noise.
|
|
465
472
|
const url = new URL(req.url);
|
|
466
|
-
if (
|
|
473
|
+
if (
|
|
474
|
+
(url.pathname === "/healthz" || url.pathname === "/readyz") &&
|
|
475
|
+
req.method === "GET"
|
|
476
|
+
) {
|
|
467
477
|
return this.routeRequest(req, server);
|
|
468
478
|
}
|
|
469
479
|
return withRequestLogging(req, () => this.routeRequest(req, server));
|
|
@@ -480,6 +490,10 @@ export class RuntimeHttpServer {
|
|
|
480
490
|
return handleHealth();
|
|
481
491
|
}
|
|
482
492
|
|
|
493
|
+
if (path === "/readyz" && req.method === "GET") {
|
|
494
|
+
return handleReadyz();
|
|
495
|
+
}
|
|
496
|
+
|
|
483
497
|
// WebSocket upgrade for the Chrome extension browser relay.
|
|
484
498
|
if (
|
|
485
499
|
path === "/v1/browser-relay" &&
|
|
@@ -502,6 +516,13 @@ export class RuntimeHttpServer {
|
|
|
502
516
|
const twilioResponse = await this.handleTwilioWebhook(req, path);
|
|
503
517
|
if (twilioResponse) return twilioResponse;
|
|
504
518
|
|
|
519
|
+
// Audio serving endpoint — before auth check because Twilio
|
|
520
|
+
// fetches these URLs directly. The audioId is an unguessable UUID.
|
|
521
|
+
const audioMatch = path.match(/^\/v1\/audio\/([^/]+)$/);
|
|
522
|
+
if (audioMatch && req.method === "GET") {
|
|
523
|
+
return handleGetAudio(audioMatch[1]);
|
|
524
|
+
}
|
|
525
|
+
|
|
505
526
|
// Pairing endpoints (unauthenticated, secret-gated)
|
|
506
527
|
if (path === "/v1/pairing/request" && req.method === "POST") {
|
|
507
528
|
return await handlePairingRequest(req, this.pairingContext);
|
|
@@ -918,6 +939,9 @@ export class RuntimeHttpServer {
|
|
|
918
939
|
getCesClient: this.getCesClient,
|
|
919
940
|
}),
|
|
920
941
|
...identityRouteDefinitions(),
|
|
942
|
+
...upgradeBroadcastRouteDefinitions(),
|
|
943
|
+
...workspaceCommitRouteDefinitions(),
|
|
944
|
+
...migrationRollbackRouteDefinitions(),
|
|
921
945
|
...debugRouteDefinitions(),
|
|
922
946
|
...usageRouteDefinitions(),
|
|
923
947
|
...telemetryRouteDefinitions(),
|
|
@@ -929,6 +953,7 @@ export class RuntimeHttpServer {
|
|
|
929
953
|
...scheduleRouteDefinitions({
|
|
930
954
|
sendMessageDeps: this.sendMessageDeps,
|
|
931
955
|
}),
|
|
956
|
+
...notificationRouteDefinitions(),
|
|
932
957
|
...diagnosticsRouteDefinitions(),
|
|
933
958
|
...logExportRouteDefinitions(),
|
|
934
959
|
...documentRouteDefinitions(),
|
|
@@ -959,6 +984,7 @@ export class RuntimeHttpServer {
|
|
|
959
984
|
}
|
|
960
985
|
: undefined,
|
|
961
986
|
}),
|
|
987
|
+
...ttsRouteDefinitions(),
|
|
962
988
|
|
|
963
989
|
// Browser relay — not extracted into a domain module because
|
|
964
990
|
// these two routes depend on the in-process extensionRelayServer
|
|
@@ -1163,6 +1189,7 @@ export class RuntimeHttpServer {
|
|
|
1163
1189
|
...slackChannelRouteDefinitions(),
|
|
1164
1190
|
...slackShareRouteDefinitions(),
|
|
1165
1191
|
...twilioRouteDefinitions(),
|
|
1192
|
+
...vercelRouteDefinitions(),
|
|
1166
1193
|
...channelReadinessRouteDefinitions(),
|
|
1167
1194
|
...oauthAppsRouteDefinitions(),
|
|
1168
1195
|
...attachmentRouteDefinitions(),
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
ConfigError,
|
|
7
|
-
IngressBlockedError,
|
|
8
7
|
ProviderNotConfiguredError,
|
|
9
8
|
} from "../../util/errors.js";
|
|
10
9
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -14,7 +13,7 @@ const log = getLogger("runtime-http");
|
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Wrap an async endpoint handler with standard error handling.
|
|
17
|
-
* Catches
|
|
16
|
+
* Catches ConfigError (422) and generic errors (500).
|
|
18
17
|
*/
|
|
19
18
|
export async function withErrorHandling(
|
|
20
19
|
endpoint: string,
|
|
@@ -23,13 +22,6 @@ export async function withErrorHandling(
|
|
|
23
22
|
try {
|
|
24
23
|
return await handler();
|
|
25
24
|
} catch (err) {
|
|
26
|
-
if (err instanceof IngressBlockedError) {
|
|
27
|
-
log.warn(
|
|
28
|
-
{ endpoint, detectedTypes: err.detectedTypes },
|
|
29
|
-
"Blocked HTTP request containing secrets",
|
|
30
|
-
);
|
|
31
|
-
return httpError("UNPROCESSABLE_ENTITY", err.message, 422);
|
|
32
|
-
}
|
|
33
25
|
if (err instanceof ProviderNotConfiguredError) {
|
|
34
26
|
log.warn({ err, endpoint }, "No LLM provider configured");
|
|
35
27
|
return httpError(
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP route handler for serving synthesized TTS audio.
|
|
3
|
+
*
|
|
4
|
+
* GET /v1/audio/:audioId — retrieve a previously stored audio segment.
|
|
5
|
+
*
|
|
6
|
+
* This endpoint is unauthenticated because Twilio fetches audio URLs
|
|
7
|
+
* directly; the audioId itself is an unguessable UUID that acts as a
|
|
8
|
+
* capability token.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { getAudio } from "../../calls/audio-store.js";
|
|
12
|
+
import { httpError } from "../http-errors.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Handle GET /v1/audio/:audioId.
|
|
16
|
+
*
|
|
17
|
+
* Returns the audio with its stored Content-Type. For complete audio,
|
|
18
|
+
* includes Content-Length for efficient playback. For in-progress
|
|
19
|
+
* streaming entries, uses chunked transfer encoding.
|
|
20
|
+
*/
|
|
21
|
+
export function handleGetAudio(audioId: string): Response {
|
|
22
|
+
const entry = getAudio(audioId);
|
|
23
|
+
if (!entry) {
|
|
24
|
+
return httpError("NOT_FOUND", "Audio not found", 404);
|
|
25
|
+
}
|
|
26
|
+
if (entry.type === "buffer") {
|
|
27
|
+
return new Response(new Uint8Array(entry.buffer), {
|
|
28
|
+
status: 200,
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": entry.contentType,
|
|
31
|
+
"Content-Length": entry.buffer.length.toString(),
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Streaming — Content-Length unknown, chunked transfer encoding
|
|
36
|
+
return new Response(entry.stream, {
|
|
37
|
+
status: 200,
|
|
38
|
+
headers: { "Content-Type": entry.contentType },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
import { existsSync, readFileSync } from "node:fs";
|
|
16
16
|
|
|
17
17
|
import { getConversationByKey } from "../../memory/conversation-key-store.js";
|
|
18
|
-
import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
19
18
|
import { getLogger } from "../../util/logger.js";
|
|
20
19
|
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
21
20
|
import type { AuthContext } from "../auth/types.js";
|
|
@@ -89,22 +88,6 @@ async function handleBtw(
|
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
const trimmedContent = content.trim();
|
|
92
|
-
const ingressCheck = checkIngressForSecrets(trimmedContent);
|
|
93
|
-
if (ingressCheck.blocked) {
|
|
94
|
-
log.warn(
|
|
95
|
-
{ detectedTypes: ingressCheck.detectedTypes },
|
|
96
|
-
"Blocked /v1/btw message containing secrets",
|
|
97
|
-
);
|
|
98
|
-
return Response.json(
|
|
99
|
-
{
|
|
100
|
-
accepted: false,
|
|
101
|
-
error: "secret_blocked",
|
|
102
|
-
message: ingressCheck.userNotice,
|
|
103
|
-
detectedTypes: ingressCheck.detectedTypes,
|
|
104
|
-
},
|
|
105
|
-
{ status: 422 },
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
91
|
|
|
109
92
|
// ----- Identity intro fast-path -----
|
|
110
93
|
// When the client requests the identity intro, check SOUL.md first (persisted
|
|
@@ -275,24 +275,6 @@ export function conversationManagementRouteDefinitions(
|
|
|
275
275
|
targetId: summaryId,
|
|
276
276
|
});
|
|
277
277
|
}
|
|
278
|
-
for (const obsId of result.deletedObservationIds) {
|
|
279
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
280
|
-
targetType: "observation",
|
|
281
|
-
targetId: obsId,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
for (const chunkId of result.deletedChunkIds) {
|
|
285
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
286
|
-
targetType: "chunk",
|
|
287
|
-
targetId: chunkId,
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
for (const episodeId of result.deletedEpisodeIds) {
|
|
291
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
292
|
-
targetType: "episode",
|
|
293
|
-
targetId: episodeId,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
278
|
log.info(
|
|
297
279
|
{
|
|
298
280
|
conversationId: resolvedId,
|
|
@@ -349,24 +331,6 @@ export function conversationManagementRouteDefinitions(
|
|
|
349
331
|
targetId: summaryId,
|
|
350
332
|
});
|
|
351
333
|
}
|
|
352
|
-
for (const obsId of deleted.deletedObservationIds) {
|
|
353
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
354
|
-
targetType: "observation",
|
|
355
|
-
targetId: obsId,
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
for (const chunkId of deleted.deletedChunkIds) {
|
|
359
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
360
|
-
targetType: "chunk",
|
|
361
|
-
targetId: chunkId,
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
for (const episodeId of deleted.deletedEpisodeIds) {
|
|
365
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
366
|
-
targetType: "episode",
|
|
367
|
-
targetId: episodeId,
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
334
|
log.info({ conversationId: resolvedId }, "Deleted conversation");
|
|
371
335
|
return new Response(null, { status: 204 });
|
|
372
336
|
},
|