@vellumai/assistant 0.6.3 → 0.6.4
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 +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +5 -13
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +11 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +2 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +99 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -61
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +38 -14
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +54 -10
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -33,6 +33,10 @@ const inflight = new Map<string, Promise<string | null>>();
|
|
|
33
33
|
|
|
34
34
|
/** Where all cached packages live on disk. */
|
|
35
35
|
export function getCacheDir(): string {
|
|
36
|
+
// Package cache is intentionally shared across all local assistants to
|
|
37
|
+
// avoid re-downloading the same bundler deps per instance. Resolved
|
|
38
|
+
// against the real home directory so the cache is a single host-wide
|
|
39
|
+
// location regardless of BASE_DATA_DIR / per-instance containers.
|
|
36
40
|
return join(homedir(), ".vellum", "package-cache");
|
|
37
41
|
}
|
|
38
42
|
|
package/src/calls/audio-store.ts
CHANGED
|
@@ -24,7 +24,7 @@ let currentBytes = 0;
|
|
|
24
24
|
|
|
25
25
|
export function storeAudio(
|
|
26
26
|
buffer: Buffer,
|
|
27
|
-
format: "mp3" | "wav" | "opus",
|
|
27
|
+
format: "mp3" | "wav" | "opus" | "pcm",
|
|
28
28
|
): string {
|
|
29
29
|
evictExpired();
|
|
30
30
|
// Evict oldest if over capacity
|
|
@@ -50,7 +50,7 @@ export interface StreamingAudioHandle {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export function createStreamingEntry(
|
|
53
|
-
format: "mp3" | "wav" | "opus",
|
|
53
|
+
format: "mp3" | "wav" | "opus" | "pcm",
|
|
54
54
|
): StreamingAudioHandle {
|
|
55
55
|
evictExpired();
|
|
56
56
|
const id = randomUUID();
|
|
@@ -151,19 +151,25 @@ export function getAudio(id: string): AudioResult | null {
|
|
|
151
151
|
removeEntry(id);
|
|
152
152
|
return null;
|
|
153
153
|
}
|
|
154
|
-
return {
|
|
154
|
+
return {
|
|
155
|
+
type: "buffer",
|
|
156
|
+
buffer: entry.buffer,
|
|
157
|
+
contentType: entry.contentType,
|
|
158
|
+
};
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
// ---------------------------------------------------------------------------
|
|
158
162
|
// Internal helpers
|
|
159
163
|
// ---------------------------------------------------------------------------
|
|
160
164
|
|
|
161
|
-
function contentTypeForFormat(format: "mp3" | "wav" | "opus"): string {
|
|
165
|
+
function contentTypeForFormat(format: "mp3" | "wav" | "opus" | "pcm"): string {
|
|
162
166
|
return format === "mp3"
|
|
163
167
|
? "audio/mpeg"
|
|
164
168
|
: format === "wav"
|
|
165
169
|
? "audio/wav"
|
|
166
|
-
: "
|
|
170
|
+
: format === "pcm"
|
|
171
|
+
? "audio/pcm"
|
|
172
|
+
: "audio/opus";
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
function mergeChunks(chunks: Uint8Array[]): Uint8Array {
|
|
@@ -23,6 +23,8 @@ import { revokeScopedApprovalGrantsForContext } from "../memory/scoped-approval-
|
|
|
23
23
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
24
24
|
import { mintDaemonDeliveryToken } from "../runtime/auth/token-service.js";
|
|
25
25
|
import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
|
|
26
|
+
import { getCatalogProvider } from "../tts/provider-catalog.js";
|
|
27
|
+
import type { TtsProvider, TtsProviderId } from "../tts/types.js";
|
|
26
28
|
import { getLogger } from "../util/logger.js";
|
|
27
29
|
import { createStreamingEntry } from "./audio-store.js";
|
|
28
30
|
import {
|
|
@@ -44,11 +46,11 @@ import {
|
|
|
44
46
|
recordCallEvent,
|
|
45
47
|
updateCallSession,
|
|
46
48
|
} from "./call-store.js";
|
|
49
|
+
import type { CallTransport } from "./call-transport.js";
|
|
47
50
|
import { finalizeCall } from "./finalize-call.js";
|
|
48
|
-
import { synthesizeWithFishAudio } from "./fish-audio-client.js";
|
|
49
51
|
import { sendGuardianExpiryNotices } from "./guardian-action-sweep.js";
|
|
50
52
|
import { dispatchGuardianQuestion } from "./guardian-dispatch.js";
|
|
51
|
-
import
|
|
53
|
+
import { resolveCallTtsProvider } from "./resolve-call-tts-provider.js";
|
|
52
54
|
import type { PromptSpeakerContext } from "./speaker-identification.js";
|
|
53
55
|
import { sanitizeForTts } from "./tts-text-sanitizer.js";
|
|
54
56
|
import {
|
|
@@ -61,7 +63,6 @@ import {
|
|
|
61
63
|
extractBalancedJson,
|
|
62
64
|
stripInternalSpeechMarkers,
|
|
63
65
|
} from "./voice-control-protocol.js";
|
|
64
|
-
import { isFishAudioTts } from "./voice-quality.js";
|
|
65
66
|
import {
|
|
66
67
|
startVoiceTurn,
|
|
67
68
|
type VoiceTurnHandle,
|
|
@@ -87,7 +88,7 @@ interface PendingGuardianInput {
|
|
|
87
88
|
|
|
88
89
|
export class CallController {
|
|
89
90
|
private callSessionId: string;
|
|
90
|
-
private
|
|
91
|
+
private transport: CallTransport;
|
|
91
92
|
private state: ControllerState = "idle";
|
|
92
93
|
private abortController: AbortController = new AbortController();
|
|
93
94
|
private currentTurnHandle: VoiceTurnHandle | null = null;
|
|
@@ -139,12 +140,12 @@ export class CallController {
|
|
|
139
140
|
* without blocking the caller.
|
|
140
141
|
*/
|
|
141
142
|
private guardianUnavailableForCall = false;
|
|
142
|
-
/** Active
|
|
143
|
-
private
|
|
143
|
+
/** Active synthesized-TTS session — tracked so interrupt handling can close it. */
|
|
144
|
+
private activeSynthesisAbort: AbortController | null = null;
|
|
144
145
|
|
|
145
146
|
constructor(
|
|
146
147
|
callSessionId: string,
|
|
147
|
-
|
|
148
|
+
transport: CallTransport,
|
|
148
149
|
task: string | null,
|
|
149
150
|
opts?: {
|
|
150
151
|
broadcast?: (msg: ServerMessage) => void;
|
|
@@ -153,7 +154,7 @@ export class CallController {
|
|
|
153
154
|
},
|
|
154
155
|
) {
|
|
155
156
|
this.callSessionId = callSessionId;
|
|
156
|
-
this.
|
|
157
|
+
this.transport = transport;
|
|
157
158
|
this.task = task;
|
|
158
159
|
this.isInbound = !task;
|
|
159
160
|
this.broadcast = opts?.broadcast;
|
|
@@ -344,22 +345,58 @@ export class CallController {
|
|
|
344
345
|
await this.runTurn(`[USER_INSTRUCTION: ${instructionText}]`);
|
|
345
346
|
}
|
|
346
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Handle a barge-in attempt from inbound caller audio.
|
|
350
|
+
*
|
|
351
|
+
* Only interrupts the in-flight turn when the assistant is actively
|
|
352
|
+
* speaking. When the controller is idle or still processing (no TTS
|
|
353
|
+
* output yet), the barge-in is ignored — this prevents false
|
|
354
|
+
* interruption on initial inbound media frames that arrive before
|
|
355
|
+
* the assistant has had a chance to produce its first response.
|
|
356
|
+
*
|
|
357
|
+
* @returns `true` if the barge-in was accepted (assistant was speaking),
|
|
358
|
+
* `false` if it was ignored (assistant idle or processing).
|
|
359
|
+
*/
|
|
360
|
+
handleBargeIn(): boolean {
|
|
361
|
+
if (this.state !== "speaking") {
|
|
362
|
+
log.debug(
|
|
363
|
+
{
|
|
364
|
+
callSessionId: this.callSessionId,
|
|
365
|
+
state: this.state,
|
|
366
|
+
},
|
|
367
|
+
"Barge-in ignored — assistant not speaking",
|
|
368
|
+
);
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
log.info(
|
|
373
|
+
{ callSessionId: this.callSessionId },
|
|
374
|
+
"Barge-in accepted — interrupting assistant speech",
|
|
375
|
+
);
|
|
376
|
+
this.handleInterrupt();
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
|
|
347
380
|
/**
|
|
348
381
|
* Handle caller interrupting the assistant's speech.
|
|
382
|
+
*
|
|
383
|
+
* This is the hard interrupt path used for explicit teardown and
|
|
384
|
+
* internal abort scenarios. For barge-in from inbound audio, prefer
|
|
385
|
+
* {@link handleBargeIn} which gates on the speaking state.
|
|
349
386
|
*/
|
|
350
387
|
handleInterrupt(): void {
|
|
351
388
|
const wasSpeaking = this.state === "speaking";
|
|
352
389
|
this.abortCurrentTurn();
|
|
353
390
|
this.llmRunVersion++;
|
|
354
|
-
// Cancel in-flight
|
|
355
|
-
if (this.
|
|
356
|
-
this.
|
|
357
|
-
this.
|
|
391
|
+
// Cancel in-flight synthesized TTS on barge-in
|
|
392
|
+
if (this.activeSynthesisAbort) {
|
|
393
|
+
this.activeSynthesisAbort.abort();
|
|
394
|
+
this.activeSynthesisAbort = null;
|
|
358
395
|
}
|
|
359
396
|
// Explicitly terminate the in-progress TTS turn so the relay can
|
|
360
397
|
// immediately hand control back to the caller after barge-in.
|
|
361
398
|
if (wasSpeaking) {
|
|
362
|
-
this.
|
|
399
|
+
this.transport.sendTextToken("", true);
|
|
363
400
|
}
|
|
364
401
|
this.state = "idle";
|
|
365
402
|
// Restart silence detection so a barge-in that never yields a
|
|
@@ -386,9 +423,9 @@ export class CallController {
|
|
|
386
423
|
this.pendingInstructions = [];
|
|
387
424
|
this.llmRunVersion++;
|
|
388
425
|
this.abortCurrentTurn();
|
|
389
|
-
if (this.
|
|
390
|
-
this.
|
|
391
|
-
this.
|
|
426
|
+
if (this.activeSynthesisAbort) {
|
|
427
|
+
this.activeSynthesisAbort.abort();
|
|
428
|
+
this.activeSynthesisAbort = null;
|
|
392
429
|
}
|
|
393
430
|
this.currentTurnPromise = null;
|
|
394
431
|
unregisterCallController(this.callSessionId);
|
|
@@ -516,7 +553,7 @@ export class CallController {
|
|
|
516
553
|
return;
|
|
517
554
|
}
|
|
518
555
|
log.error({ err, callSessionId: this.callSessionId }, "Voice turn error");
|
|
519
|
-
this.
|
|
556
|
+
this.transport.sendTextToken(
|
|
520
557
|
"I'm sorry, I encountered a technical issue. Could you repeat that?",
|
|
521
558
|
true,
|
|
522
559
|
);
|
|
@@ -536,11 +573,19 @@ export class CallController {
|
|
|
536
573
|
runVersion: number,
|
|
537
574
|
runSignal: AbortSignal,
|
|
538
575
|
): Promise<string> {
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
//
|
|
542
|
-
|
|
543
|
-
|
|
576
|
+
// Resolve the active TTS provider through the global abstraction.
|
|
577
|
+
// The catalog's callMode determines the call path: synthesized-play
|
|
578
|
+
// providers buffer text, synthesize via provider API, and stream
|
|
579
|
+
// audio chunks to Twilio via play-URL. Native-twilio providers
|
|
580
|
+
// stream text tokens to the relay for Twilio's built-in TTS.
|
|
581
|
+
//
|
|
582
|
+
// When the transport requires WAV (media-stream), request WAV so
|
|
583
|
+
// the audio store entry and any downstream fetch/transcode receives
|
|
584
|
+
// PCM that audioBufferToFrames can convert to mu-law.
|
|
585
|
+
const { provider, useSynthesizedPath, audioFormat } =
|
|
586
|
+
resolveCallTtsProvider({
|
|
587
|
+
preferWav: this.transport.requiresWavAudio,
|
|
588
|
+
});
|
|
544
589
|
|
|
545
590
|
// Buffer incoming tokens so we can strip control markers ([ASK_GUARDIAN:...], [END_CALL])
|
|
546
591
|
// before they reach TTS. We hold text whenever an unmatched '[' appears, since it
|
|
@@ -548,18 +593,18 @@ export class CallController {
|
|
|
548
593
|
let ttsBuffer = "";
|
|
549
594
|
let fullResponseText = "";
|
|
550
595
|
|
|
551
|
-
// When using
|
|
596
|
+
// When using the synthesized path, we accumulate all text and synthesize
|
|
552
597
|
// the complete response at the end of the turn (better prosody).
|
|
553
|
-
let
|
|
598
|
+
let synthesizedTextBuffer = "";
|
|
554
599
|
|
|
555
600
|
/** Emit a chunk of safe text to the appropriate TTS backend. */
|
|
556
601
|
const emitSafeChunk = (safeText: string): void => {
|
|
557
602
|
const cleaned = sanitizeForTts(safeText);
|
|
558
603
|
if (cleaned.length === 0) return;
|
|
559
|
-
if (
|
|
560
|
-
|
|
604
|
+
if (useSynthesizedPath) {
|
|
605
|
+
synthesizedTextBuffer += cleaned;
|
|
561
606
|
} else {
|
|
562
|
-
this.
|
|
607
|
+
this.transport.sendTextToken(cleaned, false);
|
|
563
608
|
}
|
|
564
609
|
};
|
|
565
610
|
|
|
@@ -670,48 +715,29 @@ export class CallController {
|
|
|
670
715
|
emitSafeChunk(ttsBuffer);
|
|
671
716
|
}
|
|
672
717
|
|
|
673
|
-
//
|
|
674
|
-
//
|
|
675
|
-
//
|
|
676
|
-
//
|
|
677
|
-
|
|
678
|
-
|
|
718
|
+
// Synthesized-play path: when the active provider supports streaming,
|
|
719
|
+
// synthesize the complete response text via the provider's streaming
|
|
720
|
+
// API. The full text gives the provider better context for prosody
|
|
721
|
+
// and intonation. Audio streams back via chunked transfer encoding
|
|
722
|
+
// and is forwarded to Twilio as it arrives.
|
|
723
|
+
const sanitizedSynthText = sanitizeForTts(synthesizedTextBuffer.trim());
|
|
724
|
+
if (useSynthesizedPath && provider && sanitizedSynthText.length > 0) {
|
|
679
725
|
if (!this.isCurrentRun(runVersion)) return fullResponseText;
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
this.relay.sendPlayUrl(url);
|
|
687
|
-
const abortController = new AbortController();
|
|
688
|
-
this.activeFishAbort = abortController;
|
|
689
|
-
await synthesizeWithFishAudio(
|
|
690
|
-
sanitizedFishText,
|
|
691
|
-
config.fishAudio,
|
|
692
|
-
{
|
|
693
|
-
onChunk: (chunk) => handle!.push(chunk),
|
|
694
|
-
signal: abortController.signal,
|
|
695
|
-
},
|
|
696
|
-
);
|
|
697
|
-
} catch (err) {
|
|
698
|
-
if (err instanceof DOMException && err.name === "AbortError") {
|
|
699
|
-
log.debug("Fish Audio synthesis aborted (barge-in)");
|
|
700
|
-
} else {
|
|
701
|
-
log.error({ err }, "Fish Audio synthesis failed — skipping");
|
|
702
|
-
}
|
|
703
|
-
} finally {
|
|
704
|
-
this.activeFishAbort = null;
|
|
705
|
-
handle?.finalize();
|
|
706
|
-
}
|
|
726
|
+
await this.synthesizeAndStreamAudio(
|
|
727
|
+
provider,
|
|
728
|
+
sanitizedSynthText,
|
|
729
|
+
runVersion,
|
|
730
|
+
audioFormat,
|
|
731
|
+
);
|
|
707
732
|
}
|
|
708
733
|
|
|
709
734
|
// Signal end of this turn's speech. An empty token with `last: true`
|
|
710
735
|
// tells ConversationRelay to start listening — it does NOT trigger TTS
|
|
711
|
-
// synthesis. This is required even when
|
|
712
|
-
// playback, because ConversationRelay still needs the
|
|
713
|
-
// to transition from "assistant speaking" to
|
|
714
|
-
|
|
736
|
+
// synthesis. This is required even when a synthesized provider handled
|
|
737
|
+
// all audio playback, because ConversationRelay still needs the
|
|
738
|
+
// end-of-turn signal to transition from "assistant speaking" to
|
|
739
|
+
// "caller speaking" state.
|
|
740
|
+
this.transport.sendTextToken("", true);
|
|
715
741
|
|
|
716
742
|
// Mark the greeting's first response as awaiting ack
|
|
717
743
|
if (this.lastSentWasOpener && fullResponseText.length > 0) {
|
|
@@ -722,6 +748,133 @@ export class CallController {
|
|
|
722
748
|
return fullResponseText;
|
|
723
749
|
}
|
|
724
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Synthesize text via a streaming TTS provider and forward audio chunks
|
|
753
|
+
* to Twilio through the audio store / play-URL mechanism.
|
|
754
|
+
*/
|
|
755
|
+
private async synthesizeAndStreamAudio(
|
|
756
|
+
provider: TtsProvider,
|
|
757
|
+
text: string,
|
|
758
|
+
_runVersion: number,
|
|
759
|
+
format: "mp3" | "wav" | "opus" = "mp3",
|
|
760
|
+
): Promise<void> {
|
|
761
|
+
let handle: ReturnType<typeof createStreamingEntry> | null = null;
|
|
762
|
+
let playUrlSent = false;
|
|
763
|
+
try {
|
|
764
|
+
// When format is WAV (media-stream transport), request raw PCM from
|
|
765
|
+
// the provider so the audio bytes match the store's content-type.
|
|
766
|
+
// Without this, providers like Fish Audio still return mp3 and the
|
|
767
|
+
// downstream mu-law transcoder fails on the format mismatch.
|
|
768
|
+
const outputFormat = format === "wav" ? ("pcm" as const) : undefined;
|
|
769
|
+
|
|
770
|
+
// Use "pcm" as the store format when requesting PCM output so the
|
|
771
|
+
// audio store entry's content-type (audio/pcm) matches the raw PCM
|
|
772
|
+
// bytes providers return. Without this, the store says "audio/wav"
|
|
773
|
+
// but the bytes have no RIFF header, causing audioBufferToFrames to
|
|
774
|
+
// fall through to the wrong decode path.
|
|
775
|
+
const storeFormat = outputFormat ? "pcm" : format;
|
|
776
|
+
handle = createStreamingEntry(storeFormat);
|
|
777
|
+
const config = loadConfig();
|
|
778
|
+
const baseUrl = getPublicBaseUrl(config);
|
|
779
|
+
const url = `${baseUrl}/v1/audio/${handle.audioId}`;
|
|
780
|
+
const sendPlayUrlOnce = (): void => {
|
|
781
|
+
if (playUrlSent) return;
|
|
782
|
+
this.transport.sendPlayUrl(url);
|
|
783
|
+
playUrlSent = true;
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
const abortController = new AbortController();
|
|
787
|
+
this.activeSynthesisAbort = abortController;
|
|
788
|
+
|
|
789
|
+
if (provider.synthesizeStream) {
|
|
790
|
+
let streamedChunk = false;
|
|
791
|
+
await provider.synthesizeStream(
|
|
792
|
+
{
|
|
793
|
+
text,
|
|
794
|
+
useCase: "phone-call",
|
|
795
|
+
outputFormat,
|
|
796
|
+
signal: abortController.signal,
|
|
797
|
+
},
|
|
798
|
+
(chunk) => {
|
|
799
|
+
if (chunk.byteLength === 0) return;
|
|
800
|
+
if (!streamedChunk) {
|
|
801
|
+
sendPlayUrlOnce();
|
|
802
|
+
streamedChunk = true;
|
|
803
|
+
}
|
|
804
|
+
handle!.push(chunk);
|
|
805
|
+
},
|
|
806
|
+
);
|
|
807
|
+
|
|
808
|
+
// Some provider adapters may return a buffer without invoking
|
|
809
|
+
// onChunk. If that happens, do not leave a dangling unspeakable
|
|
810
|
+
// turn; degrade to native token TTS below by treating it as no-audio.
|
|
811
|
+
if (!streamedChunk) {
|
|
812
|
+
throw new Error("Streaming TTS returned no audio chunks");
|
|
813
|
+
}
|
|
814
|
+
} else {
|
|
815
|
+
// Fallback: buffer-oriented synthesis for providers that don't
|
|
816
|
+
// implement streaming (shouldn't normally reach here since
|
|
817
|
+
// useSynthesizedPath is gated on catalog callMode).
|
|
818
|
+
const result = await provider.synthesize({
|
|
819
|
+
text,
|
|
820
|
+
useCase: "phone-call",
|
|
821
|
+
outputFormat,
|
|
822
|
+
signal: abortController.signal,
|
|
823
|
+
});
|
|
824
|
+
if (result.audio.byteLength === 0) {
|
|
825
|
+
throw new Error("Buffer TTS returned an empty audio payload");
|
|
826
|
+
}
|
|
827
|
+
sendPlayUrlOnce();
|
|
828
|
+
handle.push(result.audio);
|
|
829
|
+
}
|
|
830
|
+
} catch (err) {
|
|
831
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
832
|
+
log.debug(
|
|
833
|
+
{ provider: provider.id },
|
|
834
|
+
"TTS synthesis aborted (barge-in)",
|
|
835
|
+
);
|
|
836
|
+
} else {
|
|
837
|
+
// Extract error class and code for diagnosable log entries.
|
|
838
|
+
const errName = err instanceof Error ? err.name : String(err);
|
|
839
|
+
const errCode =
|
|
840
|
+
err instanceof Error && "code" in err
|
|
841
|
+
? (err as Error & { code?: string }).code
|
|
842
|
+
: undefined;
|
|
843
|
+
|
|
844
|
+
// `allowNativeFallback` controls whether the LLM's original
|
|
845
|
+
// response text should be sent via native Twilio token-based
|
|
846
|
+
// TTS when synthesis fails. When false (e.g. Deepgram), the
|
|
847
|
+
// error is re-thrown so the outer catch handler sends a
|
|
848
|
+
// generic recovery message via native TTS instead — the
|
|
849
|
+
// caller still hears *something*, but not the LLM's text
|
|
850
|
+
// rendered in a mismatched voice.
|
|
851
|
+
const catalogEntry = getCatalogProvider(provider.id as TtsProviderId);
|
|
852
|
+
if (!catalogEntry.allowNativeFallback) {
|
|
853
|
+
log.error(
|
|
854
|
+
{ err, provider: provider.id, errName, errCode },
|
|
855
|
+
"TTS synthesis failed — native fallback disabled for this provider",
|
|
856
|
+
);
|
|
857
|
+
throw err;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
log.error(
|
|
861
|
+
{ err, provider: provider.id, errName, errCode },
|
|
862
|
+
"TTS synthesis failed — falling back to native token TTS",
|
|
863
|
+
);
|
|
864
|
+
// If synthesis fails before any audio has started, degrade to
|
|
865
|
+
// token-based speech on ConversationRelay so the caller still
|
|
866
|
+
// hears a response instead of silence. This fallback is only
|
|
867
|
+
// used for providers whose catalog entry allows native fallback.
|
|
868
|
+
if (!playUrlSent && !this.transport.requiresWavAudio) {
|
|
869
|
+
this.transport.sendTextToken(text, false);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
} finally {
|
|
873
|
+
this.activeSynthesisAbort = null;
|
|
874
|
+
handle?.finalize();
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
725
878
|
/**
|
|
726
879
|
* Handle post-turn marker detection and dispatch: guardian consultation
|
|
727
880
|
* (ASK_GUARDIAN_APPROVAL / ASK_GUARDIAN), call finalization (END_CALL),
|
|
@@ -734,7 +887,9 @@ export class CallController {
|
|
|
734
887
|
recordCallEvent(this.callSessionId, "assistant_spoke", {
|
|
735
888
|
text: responseText,
|
|
736
889
|
});
|
|
737
|
-
const spokenText = sanitizeForTts(
|
|
890
|
+
const spokenText = sanitizeForTts(
|
|
891
|
+
stripInternalSpeechMarkers(responseText),
|
|
892
|
+
).trim();
|
|
738
893
|
if (spokenText.length > 0) {
|
|
739
894
|
const session = getCallSession(this.callSessionId);
|
|
740
895
|
if (session) {
|
|
@@ -952,7 +1107,7 @@ export class CallController {
|
|
|
952
1107
|
currentSession.status !== "cancelled"
|
|
953
1108
|
: false;
|
|
954
1109
|
|
|
955
|
-
this.
|
|
1110
|
+
this.transport.endSession("Call completed");
|
|
956
1111
|
updateCallSession(this.callSessionId, {
|
|
957
1112
|
status: "completed",
|
|
958
1113
|
endedAt: Date.now(),
|
|
@@ -1200,7 +1355,7 @@ export class CallController {
|
|
|
1200
1355
|
{ callSessionId: this.callSessionId },
|
|
1201
1356
|
"Call duration warning",
|
|
1202
1357
|
);
|
|
1203
|
-
this.
|
|
1358
|
+
this.transport.sendTextToken(
|
|
1204
1359
|
"Just to let you know, we're running low on time for this call.",
|
|
1205
1360
|
true,
|
|
1206
1361
|
);
|
|
@@ -1212,7 +1367,7 @@ export class CallController {
|
|
|
1212
1367
|
{ callSessionId: this.callSessionId },
|
|
1213
1368
|
"Call duration limit reached",
|
|
1214
1369
|
);
|
|
1215
|
-
this.
|
|
1370
|
+
this.transport.sendTextToken(
|
|
1216
1371
|
"I'm sorry, but we've reached the maximum time for this call. Thank you for your time. Goodbye!",
|
|
1217
1372
|
true,
|
|
1218
1373
|
);
|
|
@@ -1225,7 +1380,7 @@ export class CallController {
|
|
|
1225
1380
|
currentSession.status !== "cancelled"
|
|
1226
1381
|
: false;
|
|
1227
1382
|
|
|
1228
|
-
this.
|
|
1383
|
+
this.transport.endSession("Maximum call duration reached");
|
|
1229
1384
|
updateCallSession(this.callSessionId, {
|
|
1230
1385
|
status: "completed",
|
|
1231
1386
|
endedAt: Date.now(),
|
|
@@ -1274,7 +1429,7 @@ export class CallController {
|
|
|
1274
1429
|
// inbound access-request wait (relay state).
|
|
1275
1430
|
if (
|
|
1276
1431
|
this.pendingGuardianInput ||
|
|
1277
|
-
this.
|
|
1432
|
+
this.transport.getConnectionState() === "awaiting_guardian_decision"
|
|
1278
1433
|
) {
|
|
1279
1434
|
log.debug(
|
|
1280
1435
|
{ callSessionId: this.callSessionId },
|
|
@@ -1286,7 +1441,7 @@ export class CallController {
|
|
|
1286
1441
|
{ callSessionId: this.callSessionId },
|
|
1287
1442
|
"Silence timeout triggered",
|
|
1288
1443
|
);
|
|
1289
|
-
this.
|
|
1444
|
+
this.transport.sendTextToken("Are you still there?", true);
|
|
1290
1445
|
}, getSilenceTimeoutMs());
|
|
1291
1446
|
}
|
|
1292
1447
|
}
|
package/src/calls/call-domain.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
getPendingQuestion,
|
|
39
39
|
updateCallSession,
|
|
40
40
|
} from "./call-store.js";
|
|
41
|
+
import { activeMediaStreamSessions } from "./media-stream-server.js";
|
|
41
42
|
import { activeRelayConnections } from "./relay-server.js";
|
|
42
43
|
import { getTwilioConfig } from "./twilio-config.js";
|
|
43
44
|
import { TwilioConversationRelayProvider } from "./twilio-provider.js";
|
|
@@ -679,6 +680,14 @@ export async function cancelCall(
|
|
|
679
680
|
activeRelayConnections.delete(callSessionId);
|
|
680
681
|
}
|
|
681
682
|
|
|
683
|
+
// End the media-stream session if active
|
|
684
|
+
const mediaStreamSession = activeMediaStreamSessions.get(callSessionId);
|
|
685
|
+
if (mediaStreamSession) {
|
|
686
|
+
mediaStreamSession.getOutput().endSession(reason);
|
|
687
|
+
mediaStreamSession.destroy();
|
|
688
|
+
activeMediaStreamSessions.delete(callSessionId);
|
|
689
|
+
}
|
|
690
|
+
|
|
682
691
|
// Clean up controller
|
|
683
692
|
const controller = getCallController(callSessionId);
|
|
684
693
|
if (controller) {
|