@vellumai/assistant 0.11.6 → 0.11.7-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +31 -19
- package/Dockerfile +1 -0
- package/docs/architecture/security.md +3 -3
- package/docs/flux-turn-detection-spike.md +8 -7
- package/docs/runbook-trusted-contacts.md +14 -0
- package/docs/stt-provider-onboarding.md +8 -4
- package/knip.json +1 -0
- package/node_modules/@vellumai/avatar-manifest/package.json +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/manifest.test.ts +173 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/read.test.ts +114 -0
- package/node_modules/@vellumai/avatar-manifest/src/index.ts +29 -0
- package/node_modules/@vellumai/avatar-manifest/src/layout.ts +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/manifest.ts +156 -0
- package/node_modules/@vellumai/avatar-manifest/src/read.ts +109 -0
- package/node_modules/@vellumai/avatar-manifest/tsconfig.json +20 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +161 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +56 -0
- package/node_modules/@vellumai/environments/src/shell.ts +65 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +32 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +82 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/plugin-admission-denied-contract.test.ts +56 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +18 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -11
- package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +3 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +9 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +75 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +17 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/plugin-admission-denied-contract.ts +47 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/openapi.yaml +419 -55
- package/package.json +4 -1
- package/scripts/sync-llm-catalog.ts +6 -0
- package/src/__tests__/approval-card-edit-inbound-handoff.test.ts +199 -0
- package/src/__tests__/approval-card-edit.test.ts +153 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
- package/src/__tests__/available-skills.test.ts +54 -0
- package/src/__tests__/avatar-identity-sync.test.ts +5 -1
- package/src/__tests__/catalog-install-normalize.test.ts +9 -1
- package/src/__tests__/channel-policy.test.ts +1 -3
- package/src/__tests__/channel-readiness-discord.test.ts +9 -70
- package/src/__tests__/compactor-call-site-logging.test.ts +61 -0
- package/src/__tests__/config-loader-backfill.test.ts +69 -0
- package/src/__tests__/config-schema.test.ts +2 -3
- package/src/__tests__/conversation-agent-loop.test.ts +238 -0
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +44 -0
- package/src/__tests__/conversation-evictor.test.ts +19 -0
- package/src/__tests__/conversation-fork-referential.test.ts +73 -63
- package/src/__tests__/conversation-fork-retrospective.test.ts +99 -74
- package/src/__tests__/conversation-runtime-assembly.test.ts +23 -0
- package/src/__tests__/conversation-slash.test.ts +9 -0
- package/src/__tests__/conversation-title-service.test.ts +97 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +16 -0
- package/src/__tests__/credential-broker-server-use.test.ts +0 -218
- package/src/__tests__/credential-broker.test.ts +43 -420
- package/src/__tests__/credential-record-write-through.test.ts +78 -0
- package/src/__tests__/credential-routes.test.ts +17 -1
- package/src/__tests__/credential-security-invariants.test.ts +8 -9
- package/src/__tests__/default-profile-catalog-fallback.test.ts +289 -0
- package/src/__tests__/delete-propagation.test.ts +92 -2
- package/src/__tests__/discord-callback-round-trip.test.ts +93 -0
- package/src/__tests__/discord-channel-config.test.ts +237 -0
- package/src/__tests__/edit-propagation.test.ts +42 -2
- package/src/__tests__/evict-conversations-for-reload.test.ts +51 -1
- package/src/__tests__/fallback-breaker.test.ts +1335 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +6 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +30 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -2
- package/src/__tests__/image-conversion.test.ts +38 -4
- package/src/__tests__/install-skill-routing.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +4 -0
- package/src/__tests__/llm-resolver.test.ts +74 -0
- package/src/__tests__/llm-schema-fallback-profile.test.ts +359 -0
- package/src/__tests__/managed-fallback-dispatch.test.ts +430 -0
- package/src/__tests__/managed-profile-guard.test.ts +28 -0
- package/src/__tests__/managed-speech-defaults.test.ts +196 -1
- package/src/__tests__/mcp-cli.test.ts +23 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +43 -34
- package/src/__tests__/media-stream-stt-session.test.ts +2 -0
- package/src/__tests__/notification-decision-fallback.test.ts +106 -0
- package/src/__tests__/notification-discord-adapter.test.ts +162 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +95 -0
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +6 -8
- package/src/__tests__/persist-unsendable-image.test.ts +3 -3
- package/src/__tests__/platform.test.ts +19 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/provider-catalog-visibility.test.ts +17 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +8 -1
- package/src/__tests__/provider-usage-tracking.test.ts +56 -0
- package/src/__tests__/require-fresh-approval.test.ts +5 -2
- package/src/__tests__/retry-fallback-escalation.test.ts +1093 -0
- package/src/__tests__/schedule-retry.test.ts +183 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +6 -6
- package/src/__tests__/secret-routes-platform-proxy.test.ts +55 -0
- package/src/__tests__/skill-load-tool.test.ts +34 -0
- package/src/__tests__/skill-tool-factory.test.ts +6 -1
- package/src/__tests__/skill-tool-manifest.test.ts +20 -0
- package/src/__tests__/skills.test.ts +25 -0
- package/src/__tests__/subagent-manager-notify.test.ts +38 -0
- package/src/__tests__/terminal-tools.test.ts +2 -0
- package/src/__tests__/tool-approval-handler.test.ts +146 -2
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +108 -2
- package/src/__tests__/tool-audit.test.ts +111 -40
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +228 -18
- package/src/__tests__/ui-shape-teaching.test.ts +1 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +6 -2
- package/src/__tests__/voice-config-update.test.ts +43 -0
- package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +480 -0
- package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +167 -0
- package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +144 -0
- package/src/agent/loop.ts +31 -2
- package/src/approvals/guardian-card-withdrawal.ts +22 -0
- package/src/avatar/__tests__/ensure-raster.test.ts +291 -0
- package/src/avatar/avatar-manifest.ts +48 -100
- package/src/avatar/avatar-store.ts +7 -7
- package/src/avatar/ensure-raster.ts +146 -0
- package/src/avatar/resvg-lazy.test.ts +0 -1
- package/src/avatar/traits-png-sync.ts +9 -10
- package/src/background-wake/wake-intent-hooks.test.ts +0 -1
- package/src/backup/__tests__/paths.test.ts +6 -2
- package/src/backup/paths.ts +6 -4
- package/src/bundler/app-compiler.ts +2 -2
- package/src/bundler/compiler-tools.test.ts +36 -0
- package/src/bundler/compiler-tools.ts +54 -18
- package/src/calls/__tests__/telephony-synthesis-language.test.ts +81 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +57 -0
- package/src/calls/media-stream-stt-session.ts +2 -1
- package/src/calls/telephony-synthesis-language.ts +13 -5
- package/src/calls/voice-session-bridge.ts +19 -4
- package/src/channels/config.ts +23 -12
- package/src/cli/AGENTS.md +3 -1
- package/src/cli/commands/backup.help.ts +10 -13
- package/src/cli/commands/contacts.help.ts +16 -4
- package/src/cli/commands/contacts.ts +5 -1
- package/src/cli/commands/credentials.help.ts +1 -1
- package/src/cli/commands/inference-providers.ts +18 -53
- package/src/cli/commands/mcp.help.ts +6 -5
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory/memory-retrospective.ts +1 -0
- package/src/cli/commands/stt.help.ts +2 -2
- package/src/config/__tests__/backup-schema.test.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +83 -2
- package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
- package/src/config/__tests__/memory-retrospective-schema.test.ts +12 -15
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +9 -6
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +3 -1
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +16 -15
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -1
- package/src/config/bundled-skills/settings/TOOLS.json +11 -5
- package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +85 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +33 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +54 -3
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +1 -1
- package/src/config/default-profile-catalog.ts +195 -10
- package/src/config/default-profile-names.ts +41 -0
- package/src/config/feature-flag-registry.json +34 -2
- package/src/config/inference-profile-validation.ts +11 -2
- package/src/config/llm-resolver.ts +25 -0
- package/src/config/loader.ts +3 -0
- package/src/config/managed-speech-defaults.ts +160 -10
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +7 -6
- package/src/config/schemas/__tests__/stt.test.ts +94 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/channels.ts +32 -0
- package/src/config/schemas/live-voice.ts +13 -4
- package/src/config/schemas/llm.ts +263 -15
- package/src/config/schemas/mcp.ts +10 -2
- package/src/config/schemas/memory-retrospective.ts +1 -19
- package/src/config/schemas/services.ts +24 -0
- package/src/config/schemas/stt.ts +128 -5
- package/src/config/seed-inference-profiles.ts +32 -3
- package/src/config/skill-state.ts +5 -0
- package/src/config/skills.ts +21 -0
- package/src/contacts/notify-contacts-changed.ts +5 -2
- package/src/context/compactor.ts +74 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +138 -1
- package/src/daemon/config-watcher.ts +2 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -0
- package/src/daemon/conversation-agent-loop.ts +86 -10
- package/src/daemon/conversation-error.ts +25 -0
- package/src/daemon/conversation-evictor.ts +2 -4
- package/src/daemon/conversation-runtime-assembly.ts +19 -7
- package/src/daemon/conversation-skill-tools.ts +5 -1
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-store.ts +8 -1
- package/src/daemon/conversation-tool-setup.ts +37 -0
- package/src/daemon/conversation.ts +0 -4
- package/src/daemon/handlers/channel-config-result.ts +30 -0
- package/src/daemon/handlers/config-discord-channel.ts +301 -0
- package/src/daemon/handlers/config-ingress.ts +9 -0
- package/src/daemon/handlers/config-slack-channel.ts +13 -15
- package/src/daemon/handlers/config-telegram.ts +2 -5
- package/src/daemon/handlers/conversations.ts +0 -2
- package/src/daemon/handlers/skills.ts +25 -7
- package/src/daemon/lifecycle.ts +3 -1
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/tool-setup-types.ts +5 -3
- package/src/daemon/trust-context-types.test.ts +33 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +58 -4
- package/src/live-voice/__tests__/live-voice-managed-speech-fallback.test.ts +8 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +73 -11
- package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +64 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-text-turn.test.ts +391 -0
- package/src/live-voice/__tests__/protocol.test.ts +224 -0
- package/src/live-voice/live-voice-credential-preflight.ts +5 -1
- package/src/live-voice/live-voice-session-manager.ts +39 -2
- package/src/live-voice/live-voice-session.ts +224 -9
- package/src/live-voice/protocol.ts +187 -1
- package/src/messaging/providers/discord/api.ts +2 -1
- package/src/messaging/providers/discord/withdraw.ts +62 -0
- package/src/messaging/read-provider-metadata.ts +32 -0
- package/src/monitoring/__tests__/file-descriptors.test.ts +32 -0
- package/src/monitoring/__tests__/process-memory.test.ts +34 -1
- package/src/monitoring/db-integrity-sample.ts +1 -0
- package/src/monitoring/file-descriptors.ts +39 -6
- package/src/monitoring/process-memory.ts +37 -5
- package/src/monitoring/resource-sampler.ts +25 -8
- package/src/notifications/__tests__/activity-failed-dedupe.test.ts +161 -0
- package/src/notifications/__tests__/background-failure-signal.test.ts +107 -0
- package/src/notifications/__tests__/connected-channels.test.ts +12 -0
- package/src/notifications/__tests__/copy-composer.test.ts +83 -0
- package/src/notifications/__tests__/destination-resolver.test.ts +38 -0
- package/src/notifications/activity-failed-dedupe.ts +95 -0
- package/src/notifications/adapters/discord.ts +132 -0
- package/src/notifications/adapters/shared.ts +16 -0
- package/src/notifications/adapters/slack.ts +6 -1
- package/src/notifications/adapters/telegram.ts +5 -8
- package/src/notifications/approval-card-data.ts +94 -1
- package/src/notifications/background-failure-signal.ts +116 -0
- package/src/notifications/broadcaster.ts +3 -9
- package/src/notifications/copy-composer.ts +41 -8
- package/src/notifications/decision-engine.ts +55 -0
- package/src/notifications/destination-resolver.ts +45 -5
- package/src/notifications/emit-signal.ts +19 -5
- package/src/notifications/guardian-question-mode.ts +57 -0
- package/src/notifications/types.ts +2 -8
- package/src/oauth/__tests__/seed-providers-managed.test.ts +18 -0
- package/src/oauth/connect-orchestrator.ts +16 -0
- package/src/oauth/seed-providers.ts +262 -0
- package/src/permissions/checker.test.ts +21 -0
- package/src/permissions/checker.ts +6 -0
- package/src/permissions/gateway-threshold-reader.test.ts +184 -0
- package/src/permissions/gateway-threshold-reader.ts +144 -10
- package/src/permissions/prompter.ts +0 -6
- package/src/permissions/types.ts +5 -4
- package/src/persistence/__tests__/bulk-write-gate.test.ts +0 -38
- package/src/persistence/bulk-write-gate.ts +9 -10
- package/src/persistence/conversation-crud.ts +88 -134
- package/src/persistence/conversation-title-service.ts +43 -29
- package/src/persistence/embeddings/embedding-local.ts +14 -85
- package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -0
- package/src/persistence/lifecycle-events-store.test.ts +50 -0
- package/src/persistence/lifecycle-events-store.ts +75 -5
- package/src/platform/platform-patch-queue.test.ts +368 -0
- package/src/platform/platform-patch-queue.ts +190 -0
- package/src/platform/sync-avatar.test.ts +527 -0
- package/src/platform/sync-avatar.ts +209 -0
- package/src/platform/sync-identity.test.ts +75 -0
- package/src/platform/sync-identity.ts +17 -110
- package/src/plugin-api/model-profiles.test.ts +2 -2
- package/src/plugin-api/model-profiles.ts +7 -7
- package/src/plugin-api/transcription-session.ts +1 -1
- package/src/plugins/defaults/compaction/window-manager.ts +4 -0
- package/src/plugins/defaults/image-recovery/recover.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +133 -34
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +21 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +13 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +31 -4
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +0 -11
- package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +27 -13
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +183 -113
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +1 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +4 -2
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +9 -42
- package/src/plugins/defaults/memory/v2/rerank-local.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +7 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +55 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +21 -3
- package/src/providers/connection-resolution.ts +2 -17
- package/src/providers/fallback-breaker.ts +389 -0
- package/src/providers/inference/__tests__/adapter-factory-opencode.test.ts +92 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +16 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +12 -0
- package/src/providers/inference/adapter-factory.ts +246 -3
- package/src/providers/inference/auth.ts +15 -14
- package/src/providers/inference/chatgpt-subscription-auth.ts +70 -0
- package/src/providers/inference/chatgpt-subscription-credentials.ts +84 -0
- package/src/providers/inference/resolve-auth.ts +1 -1
- package/src/providers/media-resolve.ts +2 -3
- package/src/providers/model-catalog.ts +100 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +22 -0
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +198 -0
- package/src/providers/openai/api-error-normalization.ts +13 -0
- package/src/providers/openai/chat-completions-provider.ts +84 -0
- package/src/providers/opencode/client.test.ts +150 -0
- package/src/providers/opencode/client.ts +61 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-resolvability.ts +20 -0
- package/src/providers/provider-secret-catalog.ts +3 -2
- package/src/providers/retry.ts +956 -68
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +42 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +136 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +120 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +316 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +83 -3
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +132 -4
- package/src/providers/speech-to-text/provider-catalog.ts +191 -3
- package/src/providers/speech-to-text/resolve.ts +132 -24
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +296 -0
- package/src/providers/types.ts +39 -0
- package/src/providers/usage-tracking.ts +12 -1
- package/src/providers/vellum/client.ts +29 -0
- package/src/providers/vellum-model-routing.test.ts +2 -0
- package/src/providers/vellum-model-routing.ts +3 -3
- package/src/runtime/AGENTS.md +1 -2
- package/src/runtime/__tests__/agent-wake.test.ts +105 -3
- package/src/runtime/__tests__/background-job-runner.test.ts +89 -3
- package/src/runtime/agent-wake.ts +44 -5
- package/src/runtime/background-job-runner.ts +68 -50
- package/src/runtime/channel-readiness-service.ts +0 -39
- package/src/runtime/http-server.ts +12 -4
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +18 -18
- package/src/runtime/routes/__tests__/backup-routes.test.ts +9 -5
- package/src/runtime/routes/__tests__/chatgpt-subscription-auth-routes.test.ts +372 -0
- package/src/runtime/routes/__tests__/contact-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +96 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +37 -0
- package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +2 -1
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +87 -0
- package/src/runtime/routes/acp-claude-auth-routes.ts +25 -54
- package/src/runtime/routes/approval-routes.ts +0 -12
- package/src/runtime/routes/avatar-routes.ts +17 -30
- package/src/runtime/routes/backup-routes.ts +2 -2
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +296 -113
- package/src/runtime/routes/contact-prompt-routes.ts +65 -6
- package/src/runtime/routes/contact-routes.ts +20 -15
- package/src/runtime/routes/conversation-query-routes.ts +98 -10
- package/src/runtime/routes/conversation-routes.ts +2 -2
- package/src/runtime/routes/credential-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +47 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +18 -13
- package/src/runtime/routes/inbound-stages/admission-policy.ts +2 -2
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +20 -2
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +9 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
- package/src/runtime/routes/inference-profiles-routes.ts +12 -7
- package/src/runtime/routes/inference-provider-connection-routes.ts +2 -2
- package/src/runtime/routes/inference-send-routes.ts +2 -2
- package/src/runtime/routes/ingress-status-routes.ts +2 -2
- package/src/runtime/routes/integrations/discord.ts +119 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +12 -6
- package/src/runtime/routes/migration-routes.ts +3 -1
- package/src/runtime/routes/oauth-pending-flows.ts +136 -0
- package/src/runtime/routes/secret-routes.ts +7 -0
- package/src/runtime/routes/stt-routes.ts +38 -6
- package/src/runtime/routes/wake-conversation-routes.ts +8 -1
- package/src/runtime/routes/watch-routes.ts +9 -5
- package/src/runtime/sync/resource-sync-events.ts +2 -0
- package/src/runtime/trust-verdict-consumer.ts +3 -3
- package/src/schedule/__tests__/worker-feature-flags.test.ts +58 -0
- package/src/schedule/retry-policy.ts +8 -8
- package/src/schedule/run-script.ts +14 -23
- package/src/schedule/schedule-recovery.ts +0 -1
- package/src/schedule/scheduler.ts +89 -51
- package/src/schedule/worker.ts +57 -0
- package/src/security/__tests__/openai-device-auth.test.ts +355 -0
- package/src/security/ces-rpc-record-backend.ts +123 -0
- package/src/security/oauth2.ts +7 -0
- package/src/security/openai-device-auth.ts +364 -0
- package/src/security/secure-keys.ts +15 -0
- package/src/skills/available-skills.ts +10 -1
- package/src/skills/catalog-install.ts +19 -1
- package/src/skills/inline-command-runner.ts +6 -2
- package/src/skills/platform-compatibility.test.ts +49 -0
- package/src/skills/platform-compatibility.ts +65 -0
- package/src/skills/tool-manifest.ts +20 -0
- package/src/stt/__tests__/roles.test.ts +152 -0
- package/src/stt/daemon-batch-transcriber.ts +4 -1
- package/src/stt/roles.ts +180 -0
- package/src/stt/stt-stream-session.ts +3 -2
- package/src/stt/types.ts +33 -3
- package/src/subagent/manager.ts +12 -0
- package/src/telemetry/__tests__/live-voice-funnel.test.ts +34 -0
- package/src/telemetry/live-voice-funnel.ts +12 -2
- package/src/telemetry/telemetry-wire.generated.ts +6 -0
- package/src/telemetry/tool-audit.ts +83 -30
- package/src/telemetry/tool-executed-events-store.test.ts +0 -1
- package/src/telemetry/turn-outcome.ts +75 -4
- package/src/tools/client-os.ts +115 -0
- package/src/tools/computer-use/definitions.ts +11 -7
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -2
- package/src/tools/credentials/broker-types.ts +0 -71
- package/src/tools/credentials/broker.ts +6 -201
- package/src/tools/credentials/metadata-store.ts +65 -16
- package/src/tools/credentials/store.ts +2 -0
- package/src/tools/executor.ts +2 -8
- package/src/tools/host-shell.test.ts +75 -0
- package/src/tools/host-shell.ts +24 -0
- package/src/tools/host-terminal/host-shell.ts +15 -44
- package/src/tools/mcp/mcp-tool-factory.ts +44 -9
- package/src/tools/permission-checker.ts +73 -21
- package/src/tools/policy-context.ts +1 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/find-similar-skills.ts +10 -2
- package/src/tools/skills/load.ts +41 -6
- package/src/tools/skills/sandbox-runner.ts +8 -16
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/terminal/__tests__/safe-env.test.ts +64 -1
- package/src/tools/terminal/safe-env.ts +39 -9
- package/src/tools/terminal/shell.ts +12 -31
- package/src/tools/tool-approval-handler.ts +64 -10
- package/src/tools/tool-types.ts +10 -0
- package/src/tools/types.ts +19 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +4 -3
- package/src/tools/workflows/manage-workflows.ts +2 -2
- package/src/tools/workflows/run-workflow.test.ts +2 -1
- package/src/util/__tests__/file-use.test.ts +61 -0
- package/src/util/__tests__/process-table.test.ts +66 -0
- package/src/util/__tests__/process-tree.test.ts +46 -0
- package/src/util/errors.ts +1 -0
- package/src/util/file-use.ts +91 -0
- package/src/util/host-process.test.ts +17 -0
- package/src/util/host-process.ts +75 -0
- package/src/util/image-conversion.ts +39 -7
- package/src/util/platform.ts +32 -13
- package/src/util/process-table.ts +249 -0
- package/src/util/process-tree.ts +85 -129
- package/src/util/provider-error-patterns.ts +20 -0
- package/src/util/spawn.ts +9 -2
- package/src/watch/__tests__/watch-retro.test.ts +48 -1
- package/src/watch/watch-retro.ts +46 -4
- package/src/workspace/git-service.ts +4 -14
- package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +360 -0
- package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +117 -0
- package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +204 -0
- package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +139 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +160 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/permission-types.test.ts +0 -17
- package/src/channels/gateway-discord-admission.ts +0 -32
- package/src/persistence/fork-message-copy.ts +0 -239
- package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +0 -221
- package/src/security/__tests__/oauth2-device-code.test.ts +0 -431
- package/src/security/oauth2-device-code.ts +0 -312
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
import type {
|
|
14
14
|
ConversationStreamingMode,
|
|
15
15
|
SttBoundaryId,
|
|
16
|
+
SttModelFamily,
|
|
16
17
|
SttProviderId,
|
|
17
18
|
SttTurnDetectionMode,
|
|
18
19
|
TelephonySttMode,
|
|
19
20
|
} from "../../stt/types.js";
|
|
20
21
|
import { baseLanguageSubtag } from "../../util/language-subtag.js";
|
|
22
|
+
import { FLUX_MULTILINGUAL_SUBTAGS } from "./deepgram-flux-frames.js";
|
|
21
23
|
|
|
22
24
|
// ---------------------------------------------------------------------------
|
|
23
25
|
// Client display metadata
|
|
@@ -122,6 +124,23 @@ interface SttProviderEntry {
|
|
|
122
124
|
|
|
123
125
|
/** Guide for obtaining API credentials from this provider. */
|
|
124
126
|
readonly credentialsGuide?: SttCredentialsGuide;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Set when this row is a model family of another provider rather than a
|
|
130
|
+
* provider in its own right: the id a user selects, plus the
|
|
131
|
+
* `services.stt.providers.<id>.model` value that reaches this row.
|
|
132
|
+
*
|
|
133
|
+
* Rows carrying this are not separately selectable. They share the parent's
|
|
134
|
+
* credential and appear nowhere in a provider picker.
|
|
135
|
+
*/
|
|
136
|
+
readonly variantOf?: SttProviderId;
|
|
137
|
+
readonly variantModel?: SttModelFamily;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The family this row runs when no `model` is set. Present only on rows that
|
|
141
|
+
* have variants, so the default is nameable in config and in errors.
|
|
142
|
+
*/
|
|
143
|
+
readonly baseModelFamily?: SttModelFamily;
|
|
125
144
|
}
|
|
126
145
|
|
|
127
146
|
// ---------------------------------------------------------------------------
|
|
@@ -156,6 +175,7 @@ const CATALOG: ReadonlyMap<SttProviderId, SttProviderEntry> = new Map<
|
|
|
156
175
|
"deepgram",
|
|
157
176
|
{
|
|
158
177
|
id: "deepgram",
|
|
178
|
+
baseModelFamily: "nova-3",
|
|
159
179
|
displayName: "Deepgram",
|
|
160
180
|
subtitle:
|
|
161
181
|
"Fast, real-time speech-to-text with streaming support. Requires a Deepgram API key.",
|
|
@@ -178,6 +198,8 @@ const CATALOG: ReadonlyMap<SttProviderId, SttProviderEntry> = new Map<
|
|
|
178
198
|
"deepgram-flux",
|
|
179
199
|
{
|
|
180
200
|
id: "deepgram-flux",
|
|
201
|
+
variantOf: "deepgram",
|
|
202
|
+
variantModel: "flux",
|
|
181
203
|
displayName: "Deepgram Flux",
|
|
182
204
|
subtitle:
|
|
183
205
|
"Conversational speech-to-text with model-native turn detection. Uses your Deepgram API key.",
|
|
@@ -198,9 +220,11 @@ const CATALOG: ReadonlyMap<SttProviderId, SttProviderEntry> = new Map<
|
|
|
198
220
|
// them, so a live-voice session may let them commit the turn.
|
|
199
221
|
turnDetection: "provider",
|
|
200
222
|
supportsDiarization: false,
|
|
201
|
-
// "no picker", not native detection:
|
|
202
|
-
//
|
|
203
|
-
// as English
|
|
223
|
+
// "no picker", not native detection: this entry pins the English Flux
|
|
224
|
+
// model and sends no language parameter, so audio in another language
|
|
225
|
+
// transcribes as English. Flux itself has a multilingual model; the
|
|
226
|
+
// managed `vellum-flux` entry reaches it, and a BYOK picker would need
|
|
227
|
+
// the model to follow the selection.
|
|
204
228
|
languageSelection: "auto",
|
|
205
229
|
credentialsGuide: DEEPGRAM_CREDENTIALS_GUIDE,
|
|
206
230
|
},
|
|
@@ -264,6 +288,7 @@ const CATALOG: ReadonlyMap<SttProviderId, SttProviderEntry> = new Map<
|
|
|
264
288
|
"vellum",
|
|
265
289
|
{
|
|
266
290
|
id: "vellum",
|
|
291
|
+
baseModelFamily: "nova-3",
|
|
267
292
|
displayName: "Vellum",
|
|
268
293
|
subtitle:
|
|
269
294
|
"Speech-to-text through your Vellum account — billed to Vellum credits, no separate API key needed.",
|
|
@@ -283,6 +308,39 @@ const CATALOG: ReadonlyMap<SttProviderId, SttProviderEntry> = new Map<
|
|
|
283
308
|
languageSelection: "manual",
|
|
284
309
|
},
|
|
285
310
|
],
|
|
311
|
+
[
|
|
312
|
+
"vellum-flux",
|
|
313
|
+
{
|
|
314
|
+
id: "vellum-flux",
|
|
315
|
+
variantOf: "vellum",
|
|
316
|
+
variantModel: "flux",
|
|
317
|
+
displayName: "Vellum (Flux)",
|
|
318
|
+
subtitle:
|
|
319
|
+
"Conversational speech-to-text with model-native turn detection, through your Vellum account. No separate API key needed.",
|
|
320
|
+
setupMode: "connection",
|
|
321
|
+
setupHint: "Connect your Vellum account to enable managed transcription.",
|
|
322
|
+
// Shared with `vellum`: the platform connection is the credential, and
|
|
323
|
+
// Flux is a different endpoint on the same relay, not a second account.
|
|
324
|
+
credentialProvider: "vellum",
|
|
325
|
+
// Streaming only, same as the BYOK Flux entry: Flux has no batch
|
|
326
|
+
// endpoint, and the relay exposes none.
|
|
327
|
+
supportedBoundaries: new Set<SttBoundaryId>(["daemon-streaming"]),
|
|
328
|
+
// The relay maps `Finalize` onto Flux's `CloseStream`, which ends the
|
|
329
|
+
// session rather than flushing it, and telephony's utterance-boundary
|
|
330
|
+
// finals are a nova-3 concept. Calls stay on `vellum`.
|
|
331
|
+
telephonyMode: "none",
|
|
332
|
+
conversationStreamingMode: "realtime-ws",
|
|
333
|
+
// The relay is dialed with `contract=flux`, so Flux's turn lifecycle
|
|
334
|
+
// events arrive intact and a live-voice session may let them commit
|
|
335
|
+
// the turn. Without that opt-in the relay translates them away and
|
|
336
|
+
// this would be false.
|
|
337
|
+
turnDetection: "provider",
|
|
338
|
+
supportsDiarization: false,
|
|
339
|
+
// The relay selects `flux-general-en` or `flux-general-multi` from the
|
|
340
|
+
// language it is sent, so unlike BYOK Flux the picker is meaningful.
|
|
341
|
+
languageSelection: "manual",
|
|
342
|
+
},
|
|
343
|
+
],
|
|
286
344
|
[
|
|
287
345
|
"xai",
|
|
288
346
|
{
|
|
@@ -440,6 +498,136 @@ export function supportsDiarization(id: SttProviderId): boolean {
|
|
|
440
498
|
* provider, so a new turn-detecting provider is a catalog entry rather than a
|
|
441
499
|
* session change.
|
|
442
500
|
*/
|
|
501
|
+
/**
|
|
502
|
+
* Whether a provider authenticates with the Vellum platform connection rather
|
|
503
|
+
* than a stored API key.
|
|
504
|
+
*
|
|
505
|
+
* Derived from the catalog rather than a hand-kept id list: every check that
|
|
506
|
+
* gates managed speech reads this, so adding a managed provider cannot leave
|
|
507
|
+
* one of them behind on a stale literal.
|
|
508
|
+
*/
|
|
509
|
+
export function isManagedSttProvider(id: SttProviderId): boolean {
|
|
510
|
+
return CATALOG.get(id)?.credentialProvider === "vellum";
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* The catalog row a configured provider plus model family resolves to.
|
|
515
|
+
*
|
|
516
|
+
* Falls back to the provider's own row when it offers no matching variant, so
|
|
517
|
+
* a model setting a provider does not implement is inert rather than fatal.
|
|
518
|
+
* The parameter is structural to keep the catalog free of config imports.
|
|
519
|
+
*/
|
|
520
|
+
export function resolveSttCatalogKey(stt: {
|
|
521
|
+
readonly provider: string;
|
|
522
|
+
readonly providers?:
|
|
523
|
+
| Record<string, { readonly model?: unknown } | undefined>
|
|
524
|
+
| undefined;
|
|
525
|
+
}): SttProviderId {
|
|
526
|
+
const provider = stt.provider as SttProviderId;
|
|
527
|
+
return sttCatalogKeyFor(provider, stt.providers?.[provider]?.model);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* The catalog row a provider and model family pair resolves to.
|
|
532
|
+
*
|
|
533
|
+
* Split out from {@link resolveSttCatalogKey} because a selection does not
|
|
534
|
+
* always come from the top-level config block: a per-consumer role names its
|
|
535
|
+
* own provider and family, and has to reach the same row that pair would
|
|
536
|
+
* reach anywhere else.
|
|
537
|
+
*/
|
|
538
|
+
export function sttCatalogKeyFor(
|
|
539
|
+
provider: SttProviderId,
|
|
540
|
+
model: unknown,
|
|
541
|
+
): SttProviderId {
|
|
542
|
+
if (typeof model !== "string") {
|
|
543
|
+
return provider;
|
|
544
|
+
}
|
|
545
|
+
for (const entry of CATALOG.values()) {
|
|
546
|
+
if (entry.variantOf === provider && entry.variantModel === model) {
|
|
547
|
+
return entry.id;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return provider;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* The model families a provider offers, as `services.stt.providers.<id>.model`
|
|
555
|
+
* values. A provider with a single family returns an empty list, and setting
|
|
556
|
+
* `model` on it is a configuration error rather than a silent no-op.
|
|
557
|
+
*/
|
|
558
|
+
export function listProviderModelFamilies(
|
|
559
|
+
id: SttProviderId,
|
|
560
|
+
): readonly SttModelFamily[] {
|
|
561
|
+
const base = CATALOG.get(id);
|
|
562
|
+
if (!base || base.variantOf !== undefined) {
|
|
563
|
+
return [];
|
|
564
|
+
}
|
|
565
|
+
const families = [...CATALOG.values()]
|
|
566
|
+
.filter((entry) => entry.variantOf === id && entry.variantModel)
|
|
567
|
+
.map((entry) => entry.variantModel as SttModelFamily);
|
|
568
|
+
return families.length > 0
|
|
569
|
+
? [base.baseModelFamily ?? "nova-3", ...families]
|
|
570
|
+
: [];
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* The config that selects a catalog row: the provider id a user sets, plus
|
|
575
|
+
* the model family when the row is a variant.
|
|
576
|
+
*
|
|
577
|
+
* The inverse of {@link resolveSttCatalogKey}. Anything persisting a resolved
|
|
578
|
+
* provider has to write these two fields rather than the key, which is not a
|
|
579
|
+
* valid `services.stt.provider` value for a variant row.
|
|
580
|
+
*/
|
|
581
|
+
export function sttConfigForCatalogKey(id: SttProviderId): {
|
|
582
|
+
provider: SttProviderId;
|
|
583
|
+
model?: SttModelFamily;
|
|
584
|
+
} {
|
|
585
|
+
const entry = CATALOG.get(id);
|
|
586
|
+
if (!entry?.variantOf || !entry.variantModel) {
|
|
587
|
+
return { provider: id };
|
|
588
|
+
}
|
|
589
|
+
return { provider: entry.variantOf, model: entry.variantModel };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* The family a provider runs when no `model` is set, for callers that must
|
|
594
|
+
* write an explicit value rather than leave a stale one in place. Providers
|
|
595
|
+
* with a single family have no name to write and return undefined.
|
|
596
|
+
*/
|
|
597
|
+
/**
|
|
598
|
+
* The spoken languages a provider's turn-detecting model family serves, or
|
|
599
|
+
* undefined when it has no such family.
|
|
600
|
+
*
|
|
601
|
+
* A family that owns the turn boundary does not necessarily cover the
|
|
602
|
+
* provider's whole language roster, and dialing it outside that set fails
|
|
603
|
+
* rather than degrades. Reported from here so the answer has one home.
|
|
604
|
+
*/
|
|
605
|
+
export function turnDetectionLanguagesFor(
|
|
606
|
+
id: SttProviderId,
|
|
607
|
+
): readonly string[] | undefined {
|
|
608
|
+
const variant = [...CATALOG.values()].find(
|
|
609
|
+
(entry) => entry.variantOf === id && entry.turnDetection === "provider",
|
|
610
|
+
);
|
|
611
|
+
return variant ? [...FLUX_MULTILINGUAL_SUBTAGS].sort() : undefined;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export function baseModelFamilyFor(
|
|
615
|
+
id: SttProviderId,
|
|
616
|
+
): SttModelFamily | undefined {
|
|
617
|
+
const entry = CATALOG.get(id);
|
|
618
|
+
return entry?.variantOf === undefined ? entry?.baseModelFamily : undefined;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Provider ids a user may select. Excludes model-family rows, which are
|
|
623
|
+
* reached through `services.stt.providers.<id>.model` instead.
|
|
624
|
+
*/
|
|
625
|
+
export function listSelectableProviderIds(): readonly SttProviderId[] {
|
|
626
|
+
return [...CATALOG.values()]
|
|
627
|
+
.filter((entry) => entry.variantOf === undefined)
|
|
628
|
+
.map((entry) => entry.id);
|
|
629
|
+
}
|
|
630
|
+
|
|
443
631
|
export function supportsProviderTurnDetection(id: SttProviderId): boolean {
|
|
444
632
|
return CATALOG.get(id)?.turnDetection === "provider";
|
|
445
633
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getConfig } from "../../config/loader.js";
|
|
2
2
|
import { getProviderKeyAsync } from "../../security/secure-keys.js";
|
|
3
3
|
import { createDaemonBatchTranscriber } from "../../stt/daemon-batch-transcriber.js";
|
|
4
|
+
import { sttCatalogKeyForRole, type SttRole } from "../../stt/roles.js";
|
|
4
5
|
import type {
|
|
5
6
|
BatchTranscriber,
|
|
6
7
|
StreamingTranscriber,
|
|
@@ -12,6 +13,8 @@ import {
|
|
|
12
13
|
batchBoundaryGapReason,
|
|
13
14
|
getCredentialProvider,
|
|
14
15
|
getProviderEntry,
|
|
16
|
+
isManagedSttProvider,
|
|
17
|
+
resolveSttCatalogKey,
|
|
15
18
|
supportsBoundary,
|
|
16
19
|
supportsDiarization,
|
|
17
20
|
} from "./provider-catalog.js";
|
|
@@ -35,6 +38,10 @@ const log = getLogger("stt-resolver");
|
|
|
35
38
|
const MULTILINGUAL_DEFAULT_PROVIDERS: ReadonlySet<SttProviderId> = new Set([
|
|
36
39
|
"deepgram",
|
|
37
40
|
"vellum",
|
|
41
|
+
// Managed Flux resolves an absent language to `flux-general-en` relay-side,
|
|
42
|
+
// so unset is an English pin here too. With "multi" the relay selects
|
|
43
|
+
// `flux-general-multi` and lets Flux detect and code-switch.
|
|
44
|
+
"vellum-flux",
|
|
38
45
|
] as SttProviderId[]);
|
|
39
46
|
|
|
40
47
|
/**
|
|
@@ -76,6 +83,29 @@ export function effectiveSttLanguage(
|
|
|
76
83
|
: undefined;
|
|
77
84
|
}
|
|
78
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Record which provider a role actually dialed, when that differs from the
|
|
88
|
+
* global setting.
|
|
89
|
+
*
|
|
90
|
+
* `assistant config get` reports what was set, not what resolved, and managed
|
|
91
|
+
* defaulting already substitutes silently. A role override adds a second way
|
|
92
|
+
* for the two to diverge, so the divergence is logged rather than left to be
|
|
93
|
+
* inferred from a provider's behaviour.
|
|
94
|
+
*/
|
|
95
|
+
function logRoleSelection(
|
|
96
|
+
role: SttRole | undefined,
|
|
97
|
+
resolved: SttProviderId,
|
|
98
|
+
base: SttProviderId,
|
|
99
|
+
): void {
|
|
100
|
+
if (role === undefined || resolved === base) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
log.info(
|
|
104
|
+
{ role, providerId: resolved, baseProviderId: base },
|
|
105
|
+
"STT role override selected a provider other than services.stt.provider",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
79
109
|
// ---------------------------------------------------------------------------
|
|
80
110
|
// Batch transcriber resolver (existing public API — unchanged contract)
|
|
81
111
|
// ---------------------------------------------------------------------------
|
|
@@ -98,11 +128,14 @@ export function effectiveSttLanguage(
|
|
|
98
128
|
* "no speech-to-text provider is configured" copy every caller pairs with
|
|
99
129
|
* `null`, which is the opposite of what happened.
|
|
100
130
|
*/
|
|
101
|
-
export async function resolveBatchTranscriber(
|
|
131
|
+
export async function resolveBatchTranscriber(
|
|
132
|
+
options: { role?: SttRole } = {},
|
|
133
|
+
): Promise<BatchTranscriber | null> {
|
|
102
134
|
// Snapshot the stt config once, before any await, so a concurrent config
|
|
103
135
|
// change cannot pair one setting's old value with another's new value.
|
|
104
136
|
const stt = getConfig().services.stt;
|
|
105
|
-
const provider = stt.
|
|
137
|
+
const provider = sttCatalogKeyForRole(stt, options.role);
|
|
138
|
+
logRoleSelection(options.role, provider, resolveSttCatalogKey(stt));
|
|
106
139
|
const language = effectiveSttLanguage(
|
|
107
140
|
provider as SttProviderId,
|
|
108
141
|
stt.language,
|
|
@@ -177,22 +210,27 @@ export type TelephonySttCapability =
|
|
|
177
210
|
};
|
|
178
211
|
|
|
179
212
|
/**
|
|
180
|
-
* Validate whether the
|
|
181
|
-
*
|
|
213
|
+
* Validate whether the STT provider serving telephony is eligible for
|
|
214
|
+
* real-time call ingestion.
|
|
182
215
|
*
|
|
183
|
-
* This resolver does **not** create a live transcriber
|
|
216
|
+
* This resolver does **not** create a live transcriber: it only validates
|
|
184
217
|
* that the configuration, catalog entry, and credentials are all in order.
|
|
185
|
-
*
|
|
218
|
+
*
|
|
219
|
+
* The provider is the telephony role's, which is the one a call actually
|
|
220
|
+
* dials. Reading the global provider instead would answer about a provider
|
|
221
|
+
* no call uses: a credentialed role selection would be turned away for the
|
|
222
|
+
* global's missing key, and the inverse would pass preflight and fail at the
|
|
223
|
+
* dial.
|
|
186
224
|
*
|
|
187
225
|
* Callers can branch on the discriminated `status` field:
|
|
188
|
-
* - `"supported"
|
|
189
|
-
* - `"unsupported"
|
|
190
|
-
* - `"unconfigured"
|
|
191
|
-
* - `"missing-credentials"
|
|
226
|
+
* - `"supported"`: the provider is telephony-eligible and credentials exist.
|
|
227
|
+
* - `"unsupported"`: the provider exists but has `telephonyMode: "none"`.
|
|
228
|
+
* - `"unconfigured"`: the provider is unknown or missing from the catalog.
|
|
229
|
+
* - `"missing-credentials"`: the provider is eligible but has no API key.
|
|
192
230
|
*/
|
|
193
231
|
export async function resolveTelephonySttCapability(): Promise<TelephonySttCapability> {
|
|
194
232
|
const config = getConfig();
|
|
195
|
-
const provider = config.services.stt
|
|
233
|
+
const provider = sttCatalogKeyForRole(config.services.stt, "telephony");
|
|
196
234
|
|
|
197
235
|
const entry = getProviderEntry(provider as SttProviderId);
|
|
198
236
|
if (!entry) {
|
|
@@ -281,7 +319,7 @@ export type ConversationStreamingSttCapability =
|
|
|
281
319
|
*/
|
|
282
320
|
export async function resolveConversationStreamingSttCapability(): Promise<ConversationStreamingSttCapability> {
|
|
283
321
|
const config = getConfig();
|
|
284
|
-
const provider = config.services.stt
|
|
322
|
+
const provider = resolveSttCatalogKey(config.services.stt);
|
|
285
323
|
|
|
286
324
|
const entry = getProviderEntry(provider as SttProviderId);
|
|
287
325
|
if (!entry) {
|
|
@@ -347,6 +385,13 @@ export interface ResolveStreamingTranscriberOptions {
|
|
|
347
385
|
* readiness check approved.
|
|
348
386
|
*/
|
|
349
387
|
providerId?: SttProviderId;
|
|
388
|
+
/**
|
|
389
|
+
* Consumer asking for the transcriber. Selects that role's
|
|
390
|
+
* `services.stt.roles` override; omitted falls back to the global
|
|
391
|
+
* `services.stt.provider`. Ignored when `providerId` is given, since that
|
|
392
|
+
* caller already resolved the provider itself.
|
|
393
|
+
*/
|
|
394
|
+
role?: SttRole;
|
|
350
395
|
/**
|
|
351
396
|
* Speaker diarization preference. Default: `"off"`.
|
|
352
397
|
*
|
|
@@ -409,7 +454,11 @@ export async function resolveStreamingTranscriber(
|
|
|
409
454
|
// change cannot pair one setting's old value with another's new value
|
|
410
455
|
// (e.g. the old provider with the new language).
|
|
411
456
|
const stt = getConfig().services.stt;
|
|
412
|
-
const provider =
|
|
457
|
+
const provider =
|
|
458
|
+
options.providerId ?? sttCatalogKeyForRole(stt, options.role);
|
|
459
|
+
if (options.providerId === undefined) {
|
|
460
|
+
logRoleSelection(options.role, provider, resolveSttCatalogKey(stt));
|
|
461
|
+
}
|
|
413
462
|
// Config-level language applies to every streaming caller (live voice,
|
|
414
463
|
// dictation, telephony) unless one overrides it for a single session, so
|
|
415
464
|
// the setting lands in one place rather than at each call site. An unset
|
|
@@ -466,11 +515,14 @@ export async function resolveStreamingTranscriber(
|
|
|
466
515
|
(diarizePreference === "preferred" || diarizePreference === "required") &&
|
|
467
516
|
providerSupportsDiarization;
|
|
468
517
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
518
|
+
// Both managed entries authenticate with the platform connection, not a
|
|
519
|
+
// stored API key: there is no key to fetch, and readiness is whether the
|
|
520
|
+
// connection resolves.
|
|
521
|
+
const managed = isManagedSttProvider(provider);
|
|
522
|
+
const apiKey = managed
|
|
523
|
+
? null
|
|
524
|
+
: await getProviderKeyAsync(credentialProviderName);
|
|
525
|
+
if (managed) {
|
|
474
526
|
if (!(await sttProviderKeyResolves("vellum"))) {
|
|
475
527
|
return null;
|
|
476
528
|
}
|
|
@@ -641,18 +693,74 @@ async function createStreamingTranscriber(
|
|
|
641
693
|
: {}),
|
|
642
694
|
});
|
|
643
695
|
}
|
|
696
|
+
case "vellum-flux": {
|
|
697
|
+
// Managed Flux: same relay as `vellum`, but the STT v2 endpoint with
|
|
698
|
+
// `contract=flux` so the turn events arrive intact instead of being
|
|
699
|
+
// translated into the released v1 Deepgram dialect. Gated on the local
|
|
700
|
+
// platform connection for the same reason as `vellum` above.
|
|
701
|
+
const { vellumManagedSpeechAvailable } =
|
|
702
|
+
await import("./vellum-managed.js");
|
|
703
|
+
if (!(await vellumManagedSpeechAvailable())) {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
// The relay maps the language onto a Flux model and refuses the dial
|
|
707
|
+
// when there is none, so a language outside Flux's roster fails as a
|
|
708
|
+
// relay param error the caller cannot explain. Refuse here instead, on
|
|
709
|
+
// the same rule the BYOK twin above applies, so the reason is named
|
|
710
|
+
// where it can be read.
|
|
711
|
+
const { fluxModelForLanguage: managedFluxModelForLanguage } =
|
|
712
|
+
await import("./deepgram-flux-frames.js");
|
|
713
|
+
if (managedFluxModelForLanguage(options.language) === null) {
|
|
714
|
+
log.warn(
|
|
715
|
+
{ providerId, language: options.language },
|
|
716
|
+
"Managed Flux has no model for the configured language; refusing rather than transcribing it as another",
|
|
717
|
+
);
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
const { resolveSpeechRelayConnection } =
|
|
721
|
+
await import("./vellum-speech-relay-connection.js");
|
|
722
|
+
const connection = await resolveSpeechRelayConnection();
|
|
723
|
+
if (!connection) {
|
|
724
|
+
return null;
|
|
725
|
+
}
|
|
726
|
+
const { VellumManagedFluxRealtimeTranscriber } =
|
|
727
|
+
await import("./vellum-managed-flux-realtime.js");
|
|
728
|
+
return new VellumManagedFluxRealtimeTranscriber(connection, {
|
|
729
|
+
sampleRate: options.sampleRate,
|
|
730
|
+
// The relay picks `flux-general-en` or `flux-general-multi` from
|
|
731
|
+
// this, so it is the only lever over the Flux model from here.
|
|
732
|
+
// `utteranceBoundaryFinals` is a nova-3 concept and the catalog
|
|
733
|
+
// keeps this provider off telephony, so it never arrives.
|
|
734
|
+
...(options.language ? { language: options.language } : {}),
|
|
735
|
+
});
|
|
736
|
+
}
|
|
644
737
|
case "deepgram-flux": {
|
|
645
738
|
// Flux is streaming-only and dials Deepgram's /v2/listen conversational
|
|
646
|
-
// endpoint. Turn-detection tuning comes from `liveVoice.flux`, which
|
|
647
|
-
//
|
|
648
|
-
//
|
|
649
|
-
// English
|
|
650
|
-
//
|
|
651
|
-
//
|
|
739
|
+
// endpoint. Turn-detection tuning comes from `liveVoice.flux`, which the
|
|
740
|
+
// adapter reads itself. The language picks the model, so a language Flux
|
|
741
|
+
// has no model for resolves to nothing rather than being transcribed by
|
|
742
|
+
// the English one, which returns fluent-looking nonsense the transcript
|
|
743
|
+
// gives no sign of. Diarization is off in the catalog, so a `"required"`
|
|
744
|
+
// caller never reaches this case.
|
|
745
|
+
const { fluxModelForLanguage } =
|
|
746
|
+
await import("./deepgram-flux-frames.js");
|
|
747
|
+
// A pinned model is the operator saying which one to run, so the
|
|
748
|
+
// language check only guards the derived case.
|
|
749
|
+
if (
|
|
750
|
+
getConfig().liveVoice.flux.model === undefined &&
|
|
751
|
+
fluxModelForLanguage(options.language) === null
|
|
752
|
+
) {
|
|
753
|
+
log.warn(
|
|
754
|
+
{ providerId, language: options.language },
|
|
755
|
+
"Deepgram Flux has no model for the configured language; refusing rather than transcribing it as another",
|
|
756
|
+
);
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
652
759
|
const { DeepgramFluxRealtimeTranscriber } =
|
|
653
760
|
await import("./deepgram-flux-realtime.js");
|
|
654
761
|
return new DeepgramFluxRealtimeTranscriber(apiKey, {
|
|
655
762
|
sampleRate: options.sampleRate,
|
|
763
|
+
...(options.language ? { language: options.language } : {}),
|
|
656
764
|
});
|
|
657
765
|
}
|
|
658
766
|
default: {
|