@absolutejs/voice 0.0.22-beta.51 → 0.0.22-beta.511
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/README.md +4556 -603
- package/dist/agent.d.ts +79 -5
- package/dist/agentSquadContract.d.ts +98 -0
- package/dist/agentState.d.ts +12 -0
- package/dist/agentTools.d.ts +133 -0
- package/dist/aiVoiceModel.d.ts +15 -0
- package/dist/amdDetector.d.ts +25 -0
- package/dist/angular/index.d.ts +36 -5
- package/dist/angular/index.js +4004 -338
- package/dist/angular/voice-agent-squad-status.service.d.ts +12 -0
- package/dist/angular/voice-call-debugger.service.d.ts +12 -0
- package/dist/angular/voice-call-player.service.d.ts +19 -0
- package/dist/angular/voice-campaign-dialer-proof.service.d.ts +14 -0
- package/dist/angular/voice-controller.service.d.ts +3 -1
- package/dist/angular/voice-cost-dashboard.service.d.ts +15 -0
- package/dist/angular/voice-delivery-runtime.component.d.ts +17 -0
- package/dist/angular/voice-delivery-runtime.service.d.ts +16 -0
- package/dist/angular/voice-live-agent-console.service.d.ts +16 -0
- package/dist/angular/voice-live-call-viewer.service.d.ts +16 -0
- package/dist/angular/voice-live-ops.service.d.ts +11 -0
- package/dist/angular/voice-ops-action-center.service.d.ts +13 -0
- package/dist/angular/voice-ops-status.component.d.ts +15 -0
- package/dist/angular/voice-ops-status.service.d.ts +12 -0
- package/dist/angular/voice-platform-coverage.service.d.ts +12 -0
- package/dist/angular/voice-profile-comparison.service.d.ts +12 -0
- package/dist/angular/voice-proof-trends.service.d.ts +12 -0
- package/dist/angular/voice-provider-capabilities.service.d.ts +12 -0
- package/dist/angular/voice-provider-contracts.service.d.ts +12 -0
- package/dist/angular/voice-provider-status.service.d.ts +2 -2
- package/dist/angular/voice-readiness-failures.service.d.ts +13 -0
- package/dist/angular/voice-reconnect-profile-evidence.service.d.ts +12 -0
- package/dist/angular/voice-replay-timeline.service.d.ts +13 -0
- package/dist/angular/voice-routing-status.service.d.ts +11 -0
- package/dist/angular/voice-session-observability.service.d.ts +12 -0
- package/dist/angular/voice-session-snapshot.service.d.ts +13 -0
- package/dist/angular/voice-stream.service.d.ts +4 -1
- package/dist/angular/voice-trace-timeline.service.d.ts +12 -0
- package/dist/angular/voice-turn-latency.service.d.ts +13 -0
- package/dist/angular/voice-turn-quality.service.d.ts +12 -0
- package/dist/angular/voice-widget.service.d.ts +18 -0
- package/dist/angular/voice-workflow-status.service.d.ts +2 -2
- package/dist/assistant.d.ts +12 -13
- package/dist/assistantExperiment.d.ts +41 -0
- package/dist/assistantHealth.d.ts +6 -6
- package/dist/assistantMemory.d.ts +3 -3
- package/dist/assistantMode.d.ts +22 -0
- package/dist/audioConditioning.d.ts +1 -1
- package/dist/audit.d.ts +131 -0
- package/dist/auditDeliveryRoutes.d.ts +85 -0
- package/dist/auditExport.d.ts +34 -0
- package/dist/auditRoutes.d.ts +66 -0
- package/dist/auditSinks.d.ts +151 -0
- package/dist/backchannel.d.ts +18 -0
- package/dist/bargeInRoutes.d.ts +56 -0
- package/dist/browserCallProfiles.d.ts +120 -0
- package/dist/browserMediaRoutes.d.ts +62 -0
- package/dist/callDebugger.d.ts +66 -0
- package/dist/callDisposition.d.ts +38 -0
- package/dist/callQuota.d.ts +54 -0
- package/dist/callerMemory.d.ts +37 -0
- package/dist/callingWindow.d.ts +26 -0
- package/dist/campaign.d.ts +794 -0
- package/dist/campaignControls.d.ts +37 -0
- package/dist/campaignDialers.d.ts +111 -0
- package/dist/campaignTemplate.d.ts +16 -0
- package/dist/client/actions.d.ts +95 -1
- package/dist/client/agentSquadStatus.d.ts +37 -0
- package/dist/client/agentSquadStatusWidget.d.ts +24 -0
- package/dist/client/audioPlayer.d.ts +2 -2
- package/dist/client/bargeInMonitor.d.ts +7 -0
- package/dist/client/browserMedia.d.ts +8 -0
- package/dist/client/browserNoiseSuppression.d.ts +42 -0
- package/dist/client/browserVoiceSupport.d.ts +22 -0
- package/dist/client/callDebugger.d.ts +19 -0
- package/dist/client/callDebuggerWidget.d.ts +30 -0
- package/dist/client/callPlayer.d.ts +41 -0
- package/dist/client/campaignDialerProof.d.ts +23 -0
- package/dist/client/connection.d.ts +4 -3
- package/dist/client/controller.d.ts +1 -1
- package/dist/client/conversationAnalytics.d.ts +29 -0
- package/dist/client/costDashboard.d.ts +27 -0
- package/dist/client/createVoiceStream.d.ts +1 -1
- package/dist/client/deliveryRuntime.d.ts +34 -0
- package/dist/client/deliveryRuntimeWidget.d.ts +37 -0
- package/dist/client/duplex.d.ts +2 -2
- package/dist/client/htmx.d.ts +1 -1
- package/dist/client/htmxAttributes.d.ts +28 -0
- package/dist/client/htmxBootstrap.js +967 -14
- package/dist/client/htmxDashboardRenderers.d.ts +72 -0
- package/dist/client/index.d.ts +104 -13
- package/dist/client/index.js +10142 -26
- package/dist/client/liveAgentConsole.d.ts +28 -0
- package/dist/client/liveCallViewer.d.ts +42 -0
- package/dist/client/liveOps.d.ts +22 -0
- package/dist/client/liveOpsWidget.d.ts +23 -0
- package/dist/client/liveTurnLatency.d.ts +41 -0
- package/dist/client/microphone.d.ts +4 -4
- package/dist/client/opsActionCenter.d.ts +54 -0
- package/dist/client/opsActionCenterWidget.d.ts +29 -0
- package/dist/client/opsActionHistory.d.ts +19 -0
- package/dist/client/opsActionHistoryWidget.d.ts +11 -0
- package/dist/client/opsStatus.d.ts +19 -0
- package/dist/client/opsStatusWidget.d.ts +40 -0
- package/dist/client/platformCoverage.d.ts +19 -0
- package/dist/client/platformCoverageWidget.d.ts +37 -0
- package/dist/client/profileComparison.d.ts +19 -0
- package/dist/client/profileComparisonWidget.d.ts +41 -0
- package/dist/client/profileSwitchRecommendation.d.ts +19 -0
- package/dist/client/profileSwitchRecommendationWidget.d.ts +12 -0
- package/dist/client/proofTrends.d.ts +19 -0
- package/dist/client/proofTrendsWidget.d.ts +37 -0
- package/dist/client/providerCapabilities.d.ts +19 -0
- package/dist/client/providerCapabilitiesWidget.d.ts +32 -0
- package/dist/client/providerContracts.d.ts +19 -0
- package/dist/client/providerContractsWidget.d.ts +37 -0
- package/dist/client/providerSimulationControls.d.ts +33 -0
- package/dist/client/providerSimulationControlsWidget.d.ts +20 -0
- package/dist/client/providerStatus.d.ts +1 -1
- package/dist/client/providerStatusWidget.d.ts +32 -0
- package/dist/client/readinessFailures.d.ts +19 -0
- package/dist/client/readinessFailuresWidget.d.ts +42 -0
- package/dist/client/reconnectProfileEvidence.d.ts +19 -0
- package/dist/client/reconnectProfileEvidenceWidget.d.ts +39 -0
- package/dist/client/replayTimeline.d.ts +26 -0
- package/dist/client/routingStatus.d.ts +19 -0
- package/dist/client/routingStatusWidget.d.ts +32 -0
- package/dist/client/sessionObservability.d.ts +19 -0
- package/dist/client/sessionObservabilityWidget.d.ts +31 -0
- package/dist/client/sessionSnapshot.d.ts +21 -0
- package/dist/client/sessionSnapshotWidget.d.ts +33 -0
- package/dist/client/store.d.ts +1 -1
- package/dist/client/traceTimeline.d.ts +19 -0
- package/dist/client/traceTimelineWidget.d.ts +36 -0
- package/dist/client/turnLatency.d.ts +22 -0
- package/dist/client/turnLatencyWidget.d.ts +33 -0
- package/dist/client/turnQuality.d.ts +19 -0
- package/dist/client/turnQualityWidget.d.ts +32 -0
- package/dist/client/voiceWidgetView.d.ts +50 -0
- package/dist/client/workflowStatus.d.ts +1 -1
- package/dist/competitiveCoverage.d.ts +141 -0
- package/dist/correction.d.ts +2 -2
- package/dist/costAccounting.d.ts +76 -0
- package/dist/costPredictor.d.ts +74 -0
- package/dist/dataControl.d.ts +180 -0
- package/dist/defineVoiceAssistant.d.ts +68 -0
- package/dist/deliveryRuntime.d.ts +158 -0
- package/dist/deliverySinkRoutes.d.ts +117 -0
- package/dist/demoReadyRoutes.d.ts +98 -0
- package/dist/diagnosticsRoutes.d.ts +2 -2
- package/dist/dncRegistry.d.ts +38 -0
- package/dist/dtmfCollector.d.ts +37 -0
- package/dist/evalRoutes.d.ts +10 -4
- package/dist/fileStore.d.ts +21 -7
- package/dist/generated/htmxBootstrapBundle.d.ts +1 -0
- package/dist/guardrails.d.ts +128 -0
- package/dist/handoff.d.ts +6 -6
- package/dist/handoffHealth.d.ts +5 -5
- package/dist/holdAudio.d.ts +23 -0
- package/dist/htmx.d.ts +1 -1
- package/dist/htmxDashboardRoutes.d.ts +249 -0
- package/dist/iceServers.d.ts +34 -0
- package/dist/incidentBundle.d.ts +119 -0
- package/dist/incidentTimeline.d.ts +260 -0
- package/dist/index.d.ts +324 -74
- package/dist/index.js +42843 -6521
- package/dist/ivrPlan.d.ts +40 -0
- package/dist/latencySlo.d.ts +56 -0
- package/dist/liveCoach.d.ts +43 -0
- package/dist/liveLatency.d.ts +78 -0
- package/dist/liveOps.d.ts +190 -0
- package/dist/llmJudge.d.ts +45 -0
- package/dist/logger.d.ts +1 -1
- package/dist/mediaPipelineRoutes.d.ts +171 -0
- package/dist/mediaPipelineSurfaces.d.ts +48 -0
- package/dist/memoryStore.d.ts +1 -1
- package/dist/midCallSummary.d.ts +27 -0
- package/dist/modelAdapters.d.ts +59 -7
- package/dist/monitor.d.ts +148 -0
- package/dist/multilingualProof.d.ts +77 -0
- package/dist/oauth2TokenSource.d.ts +21 -0
- package/dist/observabilityExport.d.ts +501 -0
- package/dist/openaiTTS.d.ts +18 -0
- package/dist/operationalStatus.d.ts +87 -0
- package/dist/operationsRecord.d.ts +370 -0
- package/dist/ops.d.ts +12 -12
- package/dist/opsActionAuditRoutes.d.ts +99 -0
- package/dist/opsConsoleRoutes.d.ts +8 -5
- package/dist/opsPresets.d.ts +2 -2
- package/dist/opsRecovery.d.ts +137 -0
- package/dist/opsRuntime.d.ts +6 -6
- package/dist/opsSinks.d.ts +13 -13
- package/dist/opsStatus.d.ts +76 -0
- package/dist/opsStatusRoutes.d.ts +33 -0
- package/dist/opsWebhook.d.ts +6 -6
- package/dist/otelExporter.d.ts +83 -0
- package/dist/outcomeContract.d.ts +146 -0
- package/dist/outcomeRecipes.d.ts +4 -4
- package/dist/phoneAgent.d.ts +139 -0
- package/dist/phoneAgentProductionSmoke.d.ts +115 -0
- package/dist/phoneProvisioning.d.ts +29 -0
- package/dist/platformCoverage.d.ts +91 -0
- package/dist/plugin.d.ts +2 -2
- package/dist/postCallAnalysis.d.ts +98 -0
- package/dist/postCallSurvey.d.ts +41 -0
- package/dist/postgresStore.d.ts +17 -6
- package/dist/presets.d.ts +3 -3
- package/dist/productionReadiness.d.ts +756 -0
- package/dist/profileSwitchRecommendation.d.ts +350 -0
- package/dist/promptInjectionGuard.d.ts +30 -0
- package/dist/proofAssertions.d.ts +32 -0
- package/dist/proofPack.d.ts +211 -0
- package/dist/proofRunner.d.ts +79 -0
- package/dist/proofTrends.d.ts +966 -0
- package/dist/providerAdapters.d.ts +16 -5
- package/dist/providerCapabilities.d.ts +92 -0
- package/dist/providerDecisionTraces.d.ts +130 -0
- package/dist/providerHealth.d.ts +3 -3
- package/dist/providerOrchestration.d.ts +109 -0
- package/dist/providerRouterTraces.d.ts +35 -0
- package/dist/providerRoutingContract.d.ts +71 -0
- package/dist/providerSlo.d.ts +142 -0
- package/dist/providerStackRecommendations.d.ts +187 -0
- package/dist/qualityRoutes.d.ts +4 -4
- package/dist/queue.d.ts +23 -14
- package/dist/ragTool.d.ts +57 -0
- package/dist/react/VoiceAgentSquadStatus.d.ts +5 -0
- package/dist/react/VoiceCallDebuggerLaunch.d.ts +6 -0
- package/dist/react/VoiceCallPlayer.d.ts +11 -0
- package/dist/react/VoiceCostDashboard.d.ts +10 -0
- package/dist/react/VoiceDeliveryRuntime.d.ts +7 -0
- package/dist/react/VoiceLiveAgentConsole.d.ts +11 -0
- package/dist/react/VoiceLiveCallViewer.d.ts +9 -0
- package/dist/react/VoiceOpsActionCenter.d.ts +5 -0
- package/dist/react/VoiceOpsStatus.d.ts +6 -0
- package/dist/react/VoicePlatformCoverage.d.ts +6 -0
- package/dist/react/VoiceProfileComparison.d.ts +6 -0
- package/dist/react/VoiceProfileSwitchRecommendation.d.ts +6 -0
- package/dist/react/VoiceProofTrends.d.ts +6 -0
- package/dist/react/VoiceProviderCapabilities.d.ts +6 -0
- package/dist/react/VoiceProviderContracts.d.ts +6 -0
- package/dist/react/VoiceProviderSimulationControls.d.ts +5 -0
- package/dist/react/VoiceProviderStatus.d.ts +6 -0
- package/dist/react/VoiceReadinessFailures.d.ts +6 -0
- package/dist/react/VoiceReconnectProfileEvidence.d.ts +6 -0
- package/dist/react/VoiceReplayTimeline.d.ts +6 -0
- package/dist/react/VoiceRoutingStatus.d.ts +6 -0
- package/dist/react/VoiceSessionObservability.d.ts +6 -0
- package/dist/react/VoiceSessionSnapshot.d.ts +6 -0
- package/dist/react/VoiceTraceTimeline.d.ts +6 -0
- package/dist/react/VoiceTurnLatency.d.ts +6 -0
- package/dist/react/VoiceTurnQuality.d.ts +6 -0
- package/dist/react/VoiceWidget.d.ts +13 -0
- package/dist/react/index.d.ts +59 -5
- package/dist/react/index.js +12733 -168
- package/dist/react/useVoiceAgentSquadStatus.d.ts +8 -0
- package/dist/react/useVoiceCallDebugger.d.ts +8 -0
- package/dist/react/useVoiceCampaignDialerProof.d.ts +10 -0
- package/dist/react/useVoiceController.d.ts +4 -1
- package/dist/react/useVoiceDeliveryRuntime.d.ts +13 -0
- package/dist/react/useVoiceLiveOps.d.ts +9 -0
- package/dist/react/useVoiceOpsActionCenter.d.ts +11 -0
- package/dist/react/useVoiceOpsStatus.d.ts +8 -0
- package/dist/react/useVoicePlatformCoverage.d.ts +8 -0
- package/dist/react/useVoiceProfileComparison.d.ts +8 -0
- package/dist/react/useVoiceProfileSwitchRecommendation.d.ts +8 -0
- package/dist/react/useVoiceProofTrends.d.ts +8 -0
- package/dist/react/useVoiceProviderCapabilities.d.ts +8 -0
- package/dist/react/useVoiceProviderContracts.d.ts +8 -0
- package/dist/react/useVoiceProviderSimulationControls.d.ts +10 -0
- package/dist/react/useVoiceProviderStatus.d.ts +1 -1
- package/dist/react/useVoiceReadinessFailures.d.ts +8 -0
- package/dist/react/useVoiceReconnectProfileEvidence.d.ts +8 -0
- package/dist/react/useVoiceRoutingStatus.d.ts +8 -0
- package/dist/react/useVoiceSessionObservability.d.ts +8 -0
- package/dist/react/useVoiceSessionSnapshot.d.ts +9 -0
- package/dist/react/useVoiceStream.d.ts +4 -1
- package/dist/react/useVoiceTraceTimeline.d.ts +8 -0
- package/dist/react/useVoiceTurnLatency.d.ts +9 -0
- package/dist/react/useVoiceTurnQuality.d.ts +8 -0
- package/dist/react/useVoiceWorkflowStatus.d.ts +1 -1
- package/dist/readinessProfiles.d.ts +45 -0
- package/dist/realtimeChannel.d.ts +136 -0
- package/dist/realtimeProviderContracts.d.ts +133 -0
- package/dist/reconnectContract.d.ts +176 -0
- package/dist/recordingRedaction.d.ts +18 -0
- package/dist/recordingStore.d.ts +60 -0
- package/dist/redaction.d.ts +13 -0
- package/dist/resilienceRoutes.d.ts +45 -5
- package/dist/retention.d.ts +37 -0
- package/dist/retryPolicy.d.ts +38 -0
- package/dist/routeAuth.d.ts +58 -0
- package/dist/routing.d.ts +1 -1
- package/dist/runtimeOps.d.ts +3 -3
- package/dist/s3Store.d.ts +18 -3
- package/dist/semanticTurn.d.ts +27 -0
- package/dist/session.d.ts +1 -1
- package/dist/sessionObservability.d.ts +145 -0
- package/dist/sessionReplay.d.ts +19 -7
- package/dist/sessionSnapshot.d.ts +109 -0
- package/dist/simulationSuite.d.ts +143 -0
- package/dist/sloCalibration.d.ts +185 -0
- package/dist/sqliteStore.d.ts +17 -6
- package/dist/store.d.ts +1 -1
- package/dist/supervisorPermissions.d.ts +33 -0
- package/dist/supervisorPresence.d.ts +49 -0
- package/dist/svelte/createVoiceAgentSquadStatus.d.ts +9 -0
- package/dist/svelte/createVoiceCallDebugger.d.ts +12 -0
- package/dist/svelte/createVoiceCallPlayer.d.ts +33 -0
- package/dist/svelte/createVoiceCampaignDialerProof.d.ts +9 -0
- package/dist/svelte/createVoiceCostDashboard.d.ts +13 -0
- package/dist/svelte/createVoiceDeliveryRuntime.d.ts +11 -0
- package/dist/svelte/createVoiceLiveAgentConsole.d.ts +23 -0
- package/dist/svelte/createVoiceLiveCallViewer.d.ts +26 -0
- package/dist/svelte/createVoiceLiveOps.d.ts +13 -0
- package/dist/svelte/createVoiceOpsActionCenter.d.ts +10 -0
- package/dist/svelte/createVoiceOpsStatus.d.ts +9 -0
- package/dist/svelte/createVoicePlatformCoverage.d.ts +7 -0
- package/dist/svelte/createVoiceProfileComparison.d.ts +7 -0
- package/dist/svelte/createVoiceProofTrends.d.ts +7 -0
- package/dist/svelte/createVoiceProviderCapabilities.d.ts +10 -0
- package/dist/svelte/createVoiceProviderContracts.d.ts +10 -0
- package/dist/svelte/createVoiceProviderSimulationControls.d.ts +11 -0
- package/dist/svelte/createVoiceProviderStatus.d.ts +4 -2
- package/dist/svelte/createVoiceReadinessFailures.d.ts +7 -0
- package/dist/svelte/createVoiceReconnectProfileEvidence.d.ts +7 -0
- package/dist/svelte/createVoiceReplayTimeline.d.ts +13 -0
- package/dist/svelte/createVoiceRoutingStatus.d.ts +10 -0
- package/dist/svelte/createVoiceSessionObservability.d.ts +10 -0
- package/dist/svelte/createVoiceSessionSnapshot.d.ts +13 -0
- package/dist/svelte/createVoiceStream.d.ts +1 -1
- package/dist/svelte/createVoiceTraceTimeline.d.ts +10 -0
- package/dist/svelte/createVoiceTurnLatency.d.ts +11 -0
- package/dist/svelte/createVoiceTurnQuality.d.ts +10 -0
- package/dist/svelte/createVoiceWidget.d.ts +19 -0
- package/dist/svelte/createVoiceWorkflowStatus.d.ts +1 -1
- package/dist/svelte/index.d.ts +37 -5
- package/dist/svelte/index.js +6931 -684
- package/dist/telephony/contract.d.ts +61 -0
- package/dist/telephony/matrix.d.ts +97 -0
- package/dist/telephony/plivo.d.ts +303 -0
- package/dist/telephony/response.d.ts +1 -1
- package/dist/telephony/security.d.ts +182 -0
- package/dist/telephony/telnyx.d.ts +291 -0
- package/dist/telephony/twilio.d.ts +147 -13
- package/dist/telephonyMediaRoutes.d.ts +72 -0
- package/dist/telephonyOutcome.d.ts +273 -0
- package/dist/testing/accuracy.d.ts +1 -1
- package/dist/testing/benchmark.d.ts +9 -9
- package/dist/testing/corrected.d.ts +5 -5
- package/dist/testing/duplex.d.ts +3 -3
- package/dist/testing/fixtures.d.ts +3 -3
- package/dist/testing/index.d.ts +13 -13
- package/dist/testing/index.js +5223 -159
- package/dist/testing/ioProviderSimulator.d.ts +5 -5
- package/dist/testing/providerSimulator.d.ts +5 -5
- package/dist/testing/review.d.ts +4 -4
- package/dist/testing/sessionBenchmark.d.ts +3 -3
- package/dist/testing/stt.d.ts +3 -3
- package/dist/testing/telephony.d.ts +25 -0
- package/dist/testing/tts.d.ts +1 -1
- package/dist/toolContract.d.ts +161 -0
- package/dist/toolRuntime.d.ts +50 -0
- package/dist/trace.d.ts +46 -7
- package/dist/traceDeliveryRoutes.d.ts +86 -0
- package/dist/traceTimeline.d.ts +97 -0
- package/dist/transcriptAnnotator.d.ts +41 -0
- package/dist/turnDetection.d.ts +1 -1
- package/dist/turnLatency.d.ts +95 -0
- package/dist/turnProfiles.d.ts +2 -2
- package/dist/turnQuality.d.ts +94 -0
- package/dist/types.d.ts +293 -80
- package/dist/vapiAdapter.d.ts +160 -0
- package/dist/voiceMonitoring.d.ts +444 -0
- package/dist/vue/VoiceCallDebuggerLaunch.d.ts +68 -0
- package/dist/vue/VoiceCallPlayer.d.ts +40 -0
- package/dist/vue/VoiceCostDashboard.d.ts +57 -0
- package/dist/vue/VoiceDeliveryRuntime.d.ts +30 -0
- package/dist/vue/VoiceLiveAgentConsole.d.ts +50 -0
- package/dist/vue/VoiceLiveCallViewer.d.ts +35 -0
- package/dist/vue/VoiceOpsActionCenter.d.ts +13 -0
- package/dist/vue/VoiceOpsStatus.d.ts +30 -0
- package/dist/vue/VoicePlatformCoverage.d.ts +23 -0
- package/dist/vue/VoiceProofTrends.d.ts +21 -0
- package/dist/vue/VoiceProviderCapabilities.d.ts +51 -0
- package/dist/vue/VoiceProviderContracts.d.ts +21 -0
- package/dist/vue/VoiceProviderSimulationControls.d.ts +88 -0
- package/dist/vue/VoiceProviderStatus.d.ts +51 -0
- package/dist/vue/VoiceReadinessFailures.d.ts +21 -0
- package/dist/vue/VoiceReconnectProfileEvidence.d.ts +21 -0
- package/dist/vue/VoiceReplayTimeline.d.ts +17 -0
- package/dist/vue/VoiceRoutingStatus.d.ts +51 -0
- package/dist/vue/VoiceSessionObservability.d.ts +23 -0
- package/dist/vue/VoiceSessionSnapshot.d.ts +68 -0
- package/dist/vue/VoiceTurnLatency.d.ts +69 -0
- package/dist/vue/VoiceTurnQuality.d.ts +51 -0
- package/dist/vue/VoiceWidget.d.ts +77 -0
- package/dist/vue/index.d.ts +49 -5
- package/dist/vue/index.js +11954 -226
- package/dist/vue/useVoiceAgentSquadStatus.d.ts +9 -0
- package/dist/vue/useVoiceCallDebugger.d.ts +10 -0
- package/dist/vue/useVoiceCampaignDialerProof.d.ts +11 -0
- package/dist/vue/useVoiceController.d.ts +4 -2
- package/dist/vue/useVoiceDeliveryRuntime.d.ts +13 -0
- package/dist/vue/useVoiceLiveOps.d.ts +9 -0
- package/dist/vue/useVoiceOpsActionCenter.d.ts +11 -0
- package/dist/vue/useVoiceOpsStatus.d.ts +9 -0
- package/dist/vue/useVoicePlatformCoverage.d.ts +9 -0
- package/dist/vue/useVoiceProfileComparison.d.ts +9 -0
- package/dist/vue/useVoiceProofTrends.d.ts +9 -0
- package/dist/vue/useVoiceProviderCapabilities.d.ts +9 -0
- package/dist/vue/useVoiceProviderContracts.d.ts +9 -0
- package/dist/vue/useVoiceProviderSimulationControls.d.ts +24 -0
- package/dist/vue/useVoiceProviderStatus.d.ts +3 -3
- package/dist/vue/useVoiceReadinessFailures.d.ts +959 -0
- package/dist/vue/useVoiceReconnectProfileEvidence.d.ts +9 -0
- package/dist/vue/useVoiceRoutingStatus.d.ts +8 -0
- package/dist/vue/useVoiceSessionObservability.d.ts +9 -0
- package/dist/vue/useVoiceSessionSnapshot.d.ts +10 -0
- package/dist/vue/useVoiceStream.d.ts +5 -2
- package/dist/vue/useVoiceTraceTimeline.d.ts +9 -0
- package/dist/vue/useVoiceTurnLatency.d.ts +10 -0
- package/dist/vue/useVoiceTurnQuality.d.ts +9 -0
- package/dist/vue/useVoiceWorkflowStatus.d.ts +3 -3
- package/dist/webhookFanout.d.ts +48 -0
- package/dist/webhookVerification.d.ts +27 -0
- package/dist/whisperChannel.d.ts +50 -0
- package/dist/workflowContract.d.ts +8 -8
- package/fixtures/manifest.json +356 -197
- package/package.json +265 -256
- package/dist/angular/voice-app-kit-status.service.d.ts +0 -12
- package/dist/appKit.d.ts +0 -92
- package/dist/client/appKitStatus.d.ts +0 -19
- package/dist/react/useVoiceAppKitStatus.d.ts +0 -8
- package/dist/svelte/createVoiceAppKitStatus.d.ts +0 -8
- package/dist/vue/useVoiceAppKitStatus.d.ts +0 -9
package/dist/angular/index.js
CHANGED
|
@@ -68,20 +68,21 @@ var __decorateElement = (array, flags, name, decorators, target, extra) => {
|
|
|
68
68
|
}
|
|
69
69
|
return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
|
|
70
70
|
};
|
|
71
|
+
var __require = import.meta.require;
|
|
71
72
|
|
|
72
|
-
// src/angular/voice-
|
|
73
|
+
// src/angular/voice-ops-status.service.ts
|
|
73
74
|
import { computed, Injectable, signal } from "@angular/core";
|
|
74
75
|
|
|
75
|
-
// src/client/
|
|
76
|
-
var
|
|
76
|
+
// src/client/opsStatus.ts
|
|
77
|
+
var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
|
|
77
78
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
78
79
|
const response = await fetchImpl(path);
|
|
79
80
|
if (!response.ok) {
|
|
80
|
-
throw new Error(`Voice
|
|
81
|
+
throw new Error(`Voice ops status failed: HTTP ${response.status}`);
|
|
81
82
|
}
|
|
82
83
|
return await response.json();
|
|
83
84
|
};
|
|
84
|
-
var
|
|
85
|
+
var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) => {
|
|
85
86
|
const listeners = new Set;
|
|
86
87
|
let closed = false;
|
|
87
88
|
let timer;
|
|
@@ -105,7 +106,7 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
|
|
|
105
106
|
};
|
|
106
107
|
emit();
|
|
107
108
|
try {
|
|
108
|
-
const report = await
|
|
109
|
+
const report = await fetchVoiceOpsStatus(path, options);
|
|
109
110
|
snapshot = {
|
|
110
111
|
error: null,
|
|
111
112
|
isLoading: false,
|
|
@@ -151,15 +152,15 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
|
|
|
151
152
|
};
|
|
152
153
|
};
|
|
153
154
|
|
|
154
|
-
// src/angular/voice-
|
|
155
|
+
// src/angular/voice-ops-status.service.ts
|
|
155
156
|
var _dec = [
|
|
156
157
|
Injectable({ providedIn: "root" })
|
|
157
158
|
];
|
|
158
159
|
var _init = __decoratorStart(undefined);
|
|
159
160
|
|
|
160
|
-
class
|
|
161
|
-
connect(path = "/
|
|
162
|
-
const store =
|
|
161
|
+
class VoiceOpsStatusService {
|
|
162
|
+
connect(path = "/api/voice/ops-status", options = {}) {
|
|
163
|
+
const store = createVoiceOpsStatusStore(path, options);
|
|
163
164
|
const errorSignal = signal(null);
|
|
164
165
|
const isLoadingSignal = signal(false);
|
|
165
166
|
const reportSignal = signal(undefined);
|
|
@@ -189,13 +190,155 @@ class VoiceAppKitStatusService {
|
|
|
189
190
|
};
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
|
-
|
|
193
|
-
__runInitializers(_init, 1,
|
|
194
|
-
__decoratorMetadata(_init,
|
|
195
|
-
let
|
|
196
|
-
// src/angular/voice-
|
|
193
|
+
VoiceOpsStatusService = __decorateElement(_init, 0, "VoiceOpsStatusService", _dec, VoiceOpsStatusService);
|
|
194
|
+
__runInitializers(_init, 1, VoiceOpsStatusService);
|
|
195
|
+
__decoratorMetadata(_init, VoiceOpsStatusService);
|
|
196
|
+
let _VoiceOpsStatusService = VoiceOpsStatusService;
|
|
197
|
+
// src/angular/voice-widget.service.ts
|
|
197
198
|
import { computed as computed2, Injectable as Injectable2, signal as signal2 } from "@angular/core";
|
|
198
199
|
|
|
200
|
+
// src/client/htmx.ts
|
|
201
|
+
var DEFAULT_EVENT_NAME = "voice-refresh";
|
|
202
|
+
var DEFAULT_QUERY_PARAM = "sessionId";
|
|
203
|
+
var resolveElement = (input) => {
|
|
204
|
+
if (typeof input !== "string") {
|
|
205
|
+
return input;
|
|
206
|
+
}
|
|
207
|
+
return document.querySelector(input);
|
|
208
|
+
};
|
|
209
|
+
var buildRoute = (element, route, queryParam, sessionId) => {
|
|
210
|
+
const baseRoute = route ?? element.getAttribute("hx-get") ?? "";
|
|
211
|
+
if (!baseRoute) {
|
|
212
|
+
return "";
|
|
213
|
+
}
|
|
214
|
+
const url = new URL(baseRoute, window.location.origin);
|
|
215
|
+
if (sessionId) {
|
|
216
|
+
url.searchParams.set(queryParam, sessionId);
|
|
217
|
+
} else {
|
|
218
|
+
url.searchParams.delete(queryParam);
|
|
219
|
+
}
|
|
220
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
221
|
+
};
|
|
222
|
+
var bindVoiceHTMX = (stream, options) => {
|
|
223
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
224
|
+
return () => {};
|
|
225
|
+
}
|
|
226
|
+
const element = resolveElement(options.element);
|
|
227
|
+
if (!element) {
|
|
228
|
+
return () => {};
|
|
229
|
+
}
|
|
230
|
+
const eventName = options.eventName ?? DEFAULT_EVENT_NAME;
|
|
231
|
+
const queryParam = options.sessionQueryParam ?? DEFAULT_QUERY_PARAM;
|
|
232
|
+
const sync = () => {
|
|
233
|
+
const htmxWindow = window;
|
|
234
|
+
const nextRoute = buildRoute(element, options.route, queryParam, stream.sessionId);
|
|
235
|
+
if (nextRoute) {
|
|
236
|
+
element.setAttribute("hx-get", nextRoute);
|
|
237
|
+
}
|
|
238
|
+
htmxWindow.htmx?.process?.(element);
|
|
239
|
+
htmxWindow.htmx?.trigger?.(element, eventName);
|
|
240
|
+
};
|
|
241
|
+
const unsubscribe = stream.subscribe(sync);
|
|
242
|
+
sync();
|
|
243
|
+
return () => {
|
|
244
|
+
unsubscribe();
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// src/client/microphone.ts
|
|
249
|
+
var clampSample = (value) => Math.max(-1, Math.min(1, value));
|
|
250
|
+
var floatTo16BitPCM = (input) => {
|
|
251
|
+
const output = new Int16Array(input.length);
|
|
252
|
+
for (let index = 0;index < input.length; index += 1) {
|
|
253
|
+
const sample = clampSample(input[index] ?? 0);
|
|
254
|
+
output[index] = sample < 0 ? sample * 32768 : sample * 32767;
|
|
255
|
+
}
|
|
256
|
+
return new Uint8Array(output.buffer);
|
|
257
|
+
};
|
|
258
|
+
var getPcmLevel = (audio) => {
|
|
259
|
+
const bytes = audio instanceof Uint8Array ? audio : new Uint8Array(audio);
|
|
260
|
+
if (bytes.byteLength < 2) {
|
|
261
|
+
return 0;
|
|
262
|
+
}
|
|
263
|
+
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
264
|
+
if (samples.length === 0) {
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
let sumSquares = 0;
|
|
268
|
+
for (const sample of samples) {
|
|
269
|
+
const normalized = sample / 32768;
|
|
270
|
+
sumSquares += normalized * normalized;
|
|
271
|
+
}
|
|
272
|
+
return Math.min(1, Math.max(0, Math.sqrt(sumSquares / samples.length) * 5.5));
|
|
273
|
+
};
|
|
274
|
+
var downsampleBuffer = (input, sourceRate, targetRate) => {
|
|
275
|
+
if (sourceRate === targetRate) {
|
|
276
|
+
return input;
|
|
277
|
+
}
|
|
278
|
+
const ratio = sourceRate / targetRate;
|
|
279
|
+
const length = Math.round(input.length / ratio);
|
|
280
|
+
const output = new Float32Array(length);
|
|
281
|
+
let offsetResult = 0;
|
|
282
|
+
let offsetBuffer = 0;
|
|
283
|
+
while (offsetResult < output.length) {
|
|
284
|
+
const nextOffsetBuffer = Math.round((offsetResult + 1) * ratio);
|
|
285
|
+
let accum = 0;
|
|
286
|
+
let count = 0;
|
|
287
|
+
for (let index = offsetBuffer;index < nextOffsetBuffer && index < input.length; index += 1) {
|
|
288
|
+
accum += input[index] ?? 0;
|
|
289
|
+
count += 1;
|
|
290
|
+
}
|
|
291
|
+
output[offsetResult] = count > 0 ? accum / count : 0;
|
|
292
|
+
offsetResult += 1;
|
|
293
|
+
offsetBuffer = nextOffsetBuffer;
|
|
294
|
+
}
|
|
295
|
+
return output;
|
|
296
|
+
};
|
|
297
|
+
var createMicrophoneCapture = (options) => {
|
|
298
|
+
let audioContext = null;
|
|
299
|
+
let sourceNode = null;
|
|
300
|
+
let processorNode = null;
|
|
301
|
+
let mediaStream = null;
|
|
302
|
+
const start = async () => {
|
|
303
|
+
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
304
|
+
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
305
|
+
}
|
|
306
|
+
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
307
|
+
if (!AudioContextCtor) {
|
|
308
|
+
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
309
|
+
}
|
|
310
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
311
|
+
audio: {
|
|
312
|
+
channelCount: options.channelCount ?? 1
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
audioContext = new AudioContextCtor;
|
|
316
|
+
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
317
|
+
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
318
|
+
processorNode.onaudioprocess = (event) => {
|
|
319
|
+
const channel = event.inputBuffer.getChannelData(0);
|
|
320
|
+
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
321
|
+
const pcm = floatTo16BitPCM(downsampled);
|
|
322
|
+
options.onLevel?.(getPcmLevel(pcm));
|
|
323
|
+
options.onAudio(pcm);
|
|
324
|
+
};
|
|
325
|
+
sourceNode.connect(processorNode);
|
|
326
|
+
processorNode.connect(audioContext.destination);
|
|
327
|
+
};
|
|
328
|
+
const stop = () => {
|
|
329
|
+
processorNode?.disconnect();
|
|
330
|
+
sourceNode?.disconnect();
|
|
331
|
+
mediaStream?.getTracks().forEach((track) => track.stop());
|
|
332
|
+
audioContext?.close();
|
|
333
|
+
options.onLevel?.(0);
|
|
334
|
+
audioContext = null;
|
|
335
|
+
mediaStream = null;
|
|
336
|
+
processorNode = null;
|
|
337
|
+
sourceNode = null;
|
|
338
|
+
};
|
|
339
|
+
return { start, stop };
|
|
340
|
+
};
|
|
341
|
+
|
|
199
342
|
// src/client/actions.ts
|
|
200
343
|
var normalizeErrorMessage = (value) => {
|
|
201
344
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -244,6 +387,11 @@ var serverMessageToAction = (message) => {
|
|
|
244
387
|
sessionId: message.sessionId,
|
|
245
388
|
type: "complete"
|
|
246
389
|
};
|
|
390
|
+
case "connection":
|
|
391
|
+
return {
|
|
392
|
+
reconnect: message.reconnect,
|
|
393
|
+
type: "connection"
|
|
394
|
+
};
|
|
247
395
|
case "call_lifecycle":
|
|
248
396
|
return {
|
|
249
397
|
event: message.event,
|
|
@@ -265,9 +413,22 @@ var serverMessageToAction = (message) => {
|
|
|
265
413
|
transcript: message.transcript,
|
|
266
414
|
type: "partial"
|
|
267
415
|
};
|
|
416
|
+
case "replay":
|
|
417
|
+
return {
|
|
418
|
+
assistantTexts: message.assistantTexts,
|
|
419
|
+
call: message.call,
|
|
420
|
+
partial: message.partial,
|
|
421
|
+
scenarioId: message.scenarioId,
|
|
422
|
+
sessionId: message.sessionId,
|
|
423
|
+
sessionMetadata: message.sessionMetadata,
|
|
424
|
+
status: message.status,
|
|
425
|
+
turns: message.turns,
|
|
426
|
+
type: "replay"
|
|
427
|
+
};
|
|
268
428
|
case "session":
|
|
269
429
|
return {
|
|
270
430
|
sessionId: message.sessionId,
|
|
431
|
+
sessionMetadata: message.sessionMetadata,
|
|
271
432
|
scenarioId: message.scenarioId,
|
|
272
433
|
status: message.status,
|
|
273
434
|
type: "session"
|
|
@@ -282,6 +443,84 @@ var serverMessageToAction = (message) => {
|
|
|
282
443
|
}
|
|
283
444
|
};
|
|
284
445
|
|
|
446
|
+
// src/client/browserMedia.ts
|
|
447
|
+
import {
|
|
448
|
+
buildMediaWebRTCStatsReport,
|
|
449
|
+
buildMediaWebRTCStreamContinuityReport,
|
|
450
|
+
collectMediaWebRTCStats
|
|
451
|
+
} from "@absolutejs/media";
|
|
452
|
+
var DEFAULT_BROWSER_MEDIA_PATH = "/api/voice/browser-media";
|
|
453
|
+
var DEFAULT_BROWSER_MEDIA_INTERVAL_MS = 5000;
|
|
454
|
+
var resolvePeerConnection = async (options) => options.peerConnection ?? await options.getPeerConnection?.() ?? null;
|
|
455
|
+
var postBrowserMediaReport = async (payload, options) => {
|
|
456
|
+
const requestFetch = options.fetch ?? globalThis.fetch;
|
|
457
|
+
if (!requestFetch) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
await requestFetch(options.path ?? DEFAULT_BROWSER_MEDIA_PATH, {
|
|
461
|
+
body: JSON.stringify(payload),
|
|
462
|
+
headers: {
|
|
463
|
+
"Content-Type": "application/json"
|
|
464
|
+
},
|
|
465
|
+
keepalive: true,
|
|
466
|
+
method: "POST"
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
var createVoiceBrowserMediaReporter = (options) => {
|
|
470
|
+
let interval = null;
|
|
471
|
+
let previousStats = [];
|
|
472
|
+
const reportOnce = async () => {
|
|
473
|
+
const peerConnection = await resolvePeerConnection(options);
|
|
474
|
+
if (!peerConnection) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
const stats = await collectMediaWebRTCStats({ peerConnection });
|
|
478
|
+
const report = buildMediaWebRTCStatsReport({
|
|
479
|
+
...options,
|
|
480
|
+
stats
|
|
481
|
+
});
|
|
482
|
+
const continuity = options.continuity === false ? undefined : buildMediaWebRTCStreamContinuityReport({
|
|
483
|
+
...options.continuity,
|
|
484
|
+
previousStats,
|
|
485
|
+
stats
|
|
486
|
+
});
|
|
487
|
+
const payload = {
|
|
488
|
+
at: Date.now(),
|
|
489
|
+
continuity,
|
|
490
|
+
report,
|
|
491
|
+
scenarioId: options.getScenarioId?.() ?? null,
|
|
492
|
+
sessionId: options.getSessionId?.() ?? null
|
|
493
|
+
};
|
|
494
|
+
previousStats = stats;
|
|
495
|
+
options.onReport?.(payload);
|
|
496
|
+
await postBrowserMediaReport(payload, options);
|
|
497
|
+
return payload;
|
|
498
|
+
};
|
|
499
|
+
const run = () => {
|
|
500
|
+
reportOnce().catch((error) => {
|
|
501
|
+
options.onError?.(error);
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
const stop = () => {
|
|
505
|
+
if (interval) {
|
|
506
|
+
clearInterval(interval);
|
|
507
|
+
interval = null;
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
return {
|
|
511
|
+
close: stop,
|
|
512
|
+
reportOnce,
|
|
513
|
+
start: () => {
|
|
514
|
+
if (interval) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
run();
|
|
518
|
+
interval = setInterval(run, options.intervalMs ?? DEFAULT_BROWSER_MEDIA_INTERVAL_MS);
|
|
519
|
+
},
|
|
520
|
+
stop
|
|
521
|
+
};
|
|
522
|
+
};
|
|
523
|
+
|
|
285
524
|
// src/client/connection.ts
|
|
286
525
|
var WS_OPEN = 1;
|
|
287
526
|
var WS_CLOSED = 3;
|
|
@@ -301,6 +540,7 @@ var NOOP_CONNECTION = {
|
|
|
301
540
|
getSessionId: () => "",
|
|
302
541
|
send: noop,
|
|
303
542
|
sendAudio: noop,
|
|
543
|
+
simulateDisconnect: noop,
|
|
304
544
|
start: () => {},
|
|
305
545
|
subscribe: noopUnsubscribe
|
|
306
546
|
};
|
|
@@ -325,10 +565,12 @@ var isVoiceServerMessage = (value) => {
|
|
|
325
565
|
case "assistant":
|
|
326
566
|
case "call_lifecycle":
|
|
327
567
|
case "complete":
|
|
568
|
+
case "connection":
|
|
328
569
|
case "error":
|
|
329
570
|
case "final":
|
|
330
571
|
case "partial":
|
|
331
572
|
case "pong":
|
|
573
|
+
case "replay":
|
|
332
574
|
case "session":
|
|
333
575
|
case "turn":
|
|
334
576
|
return true;
|
|
@@ -365,6 +607,9 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
365
607
|
sessionId: options.sessionId ?? createSessionId(),
|
|
366
608
|
ws: null
|
|
367
609
|
};
|
|
610
|
+
const emitConnection = (reconnect) => {
|
|
611
|
+
listeners.forEach((listener) => listener(reconnect));
|
|
612
|
+
};
|
|
368
613
|
const clearTimers = () => {
|
|
369
614
|
if (state.pingInterval) {
|
|
370
615
|
clearInterval(state.pingInterval);
|
|
@@ -387,9 +632,28 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
387
632
|
}
|
|
388
633
|
};
|
|
389
634
|
const scheduleReconnect = () => {
|
|
635
|
+
const nextAttemptAt = Date.now() + RECONNECT_DELAY_MS;
|
|
390
636
|
state.reconnectAttempts += 1;
|
|
637
|
+
emitConnection({
|
|
638
|
+
reconnect: {
|
|
639
|
+
attempts: state.reconnectAttempts,
|
|
640
|
+
lastDisconnectAt: Date.now(),
|
|
641
|
+
maxAttempts: maxReconnectAttempts,
|
|
642
|
+
nextAttemptAt,
|
|
643
|
+
status: "reconnecting"
|
|
644
|
+
},
|
|
645
|
+
type: "connection"
|
|
646
|
+
});
|
|
391
647
|
state.reconnectTimeout = setTimeout(() => {
|
|
392
648
|
if (state.reconnectAttempts > maxReconnectAttempts) {
|
|
649
|
+
emitConnection({
|
|
650
|
+
reconnect: {
|
|
651
|
+
attempts: state.reconnectAttempts,
|
|
652
|
+
maxAttempts: maxReconnectAttempts,
|
|
653
|
+
status: "exhausted"
|
|
654
|
+
},
|
|
655
|
+
type: "connection"
|
|
656
|
+
});
|
|
393
657
|
return;
|
|
394
658
|
}
|
|
395
659
|
connect();
|
|
@@ -399,9 +663,21 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
399
663
|
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
400
664
|
ws.binaryType = "arraybuffer";
|
|
401
665
|
ws.onopen = () => {
|
|
666
|
+
const wasReconnecting = state.reconnectAttempts > 0;
|
|
402
667
|
state.isConnected = true;
|
|
403
|
-
state.reconnectAttempts = 0;
|
|
404
668
|
flushPendingMessages();
|
|
669
|
+
if (wasReconnecting) {
|
|
670
|
+
emitConnection({
|
|
671
|
+
reconnect: {
|
|
672
|
+
attempts: state.reconnectAttempts,
|
|
673
|
+
lastResumedAt: Date.now(),
|
|
674
|
+
maxAttempts: maxReconnectAttempts,
|
|
675
|
+
status: "resumed"
|
|
676
|
+
},
|
|
677
|
+
type: "connection"
|
|
678
|
+
});
|
|
679
|
+
state.reconnectAttempts = 0;
|
|
680
|
+
}
|
|
405
681
|
listeners.forEach((listener) => listener({
|
|
406
682
|
scenarioId: state.scenarioId ?? undefined,
|
|
407
683
|
sessionId: state.sessionId,
|
|
@@ -431,6 +707,16 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
431
707
|
const reconnectable = shouldReconnect && event.code !== WS_NORMAL_CLOSURE && state.reconnectAttempts < maxReconnectAttempts;
|
|
432
708
|
if (reconnectable) {
|
|
433
709
|
scheduleReconnect();
|
|
710
|
+
} else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
|
|
711
|
+
emitConnection({
|
|
712
|
+
reconnect: {
|
|
713
|
+
attempts: state.reconnectAttempts,
|
|
714
|
+
lastDisconnectAt: Date.now(),
|
|
715
|
+
maxAttempts: maxReconnectAttempts,
|
|
716
|
+
status: "exhausted"
|
|
717
|
+
},
|
|
718
|
+
type: "connection"
|
|
719
|
+
});
|
|
434
720
|
}
|
|
435
721
|
};
|
|
436
722
|
state.ws = ws;
|
|
@@ -479,6 +765,11 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
479
765
|
state.isConnected = false;
|
|
480
766
|
listeners.clear();
|
|
481
767
|
};
|
|
768
|
+
const simulateDisconnect = () => {
|
|
769
|
+
if (state.ws?.readyState === WS_OPEN) {
|
|
770
|
+
state.ws.close(4000, "absolutejs-voice-reconnect-proof");
|
|
771
|
+
}
|
|
772
|
+
};
|
|
482
773
|
const subscribe = (callback) => {
|
|
483
774
|
listeners.add(callback);
|
|
484
775
|
return () => {
|
|
@@ -495,20 +786,28 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
495
786
|
getSessionId: () => state.sessionId,
|
|
496
787
|
send,
|
|
497
788
|
sendAudio,
|
|
789
|
+
simulateDisconnect,
|
|
498
790
|
start,
|
|
499
791
|
subscribe
|
|
500
792
|
};
|
|
501
793
|
};
|
|
502
794
|
|
|
503
795
|
// src/client/store.ts
|
|
796
|
+
var createInitialReconnectState = () => ({
|
|
797
|
+
attempts: 0,
|
|
798
|
+
maxAttempts: 0,
|
|
799
|
+
status: "idle"
|
|
800
|
+
});
|
|
504
801
|
var createInitialState = () => ({
|
|
505
802
|
assistantAudio: [],
|
|
506
803
|
assistantTexts: [],
|
|
507
804
|
call: null,
|
|
508
805
|
error: null,
|
|
509
806
|
isConnected: false,
|
|
807
|
+
sessionMetadata: null,
|
|
510
808
|
scenarioId: null,
|
|
511
809
|
partial: "",
|
|
810
|
+
reconnect: createInitialReconnectState(),
|
|
512
811
|
sessionId: null,
|
|
513
812
|
status: "idle",
|
|
514
813
|
turns: []
|
|
@@ -565,7 +864,19 @@ var createVoiceStreamStore = () => {
|
|
|
565
864
|
case "connected":
|
|
566
865
|
state = {
|
|
567
866
|
...state,
|
|
568
|
-
isConnected: true
|
|
867
|
+
isConnected: true,
|
|
868
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
869
|
+
...state.reconnect,
|
|
870
|
+
lastResumedAt: Date.now(),
|
|
871
|
+
nextAttemptAt: undefined,
|
|
872
|
+
status: "resumed"
|
|
873
|
+
} : state.reconnect
|
|
874
|
+
};
|
|
875
|
+
break;
|
|
876
|
+
case "connection":
|
|
877
|
+
state = {
|
|
878
|
+
...state,
|
|
879
|
+
reconnect: action.reconnect
|
|
569
880
|
};
|
|
570
881
|
break;
|
|
571
882
|
case "disconnected":
|
|
@@ -593,6 +904,27 @@ var createVoiceStreamStore = () => {
|
|
|
593
904
|
partial: action.transcript.text
|
|
594
905
|
};
|
|
595
906
|
break;
|
|
907
|
+
case "replay":
|
|
908
|
+
state = {
|
|
909
|
+
...state,
|
|
910
|
+
assistantTexts: [...action.assistantTexts],
|
|
911
|
+
call: action.call ?? null,
|
|
912
|
+
error: null,
|
|
913
|
+
isConnected: action.status === "active",
|
|
914
|
+
partial: action.partial,
|
|
915
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
916
|
+
...state.reconnect,
|
|
917
|
+
lastResumedAt: Date.now(),
|
|
918
|
+
nextAttemptAt: undefined,
|
|
919
|
+
status: "resumed"
|
|
920
|
+
} : state.reconnect,
|
|
921
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
922
|
+
sessionId: action.sessionId,
|
|
923
|
+
sessionMetadata: action.sessionMetadata ?? state.sessionMetadata,
|
|
924
|
+
status: action.status,
|
|
925
|
+
turns: [...action.turns]
|
|
926
|
+
};
|
|
927
|
+
break;
|
|
596
928
|
case "session":
|
|
597
929
|
state = {
|
|
598
930
|
...state,
|
|
@@ -600,6 +932,7 @@ var createVoiceStreamStore = () => {
|
|
|
600
932
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
601
933
|
isConnected: action.status === "active",
|
|
602
934
|
sessionId: action.sessionId,
|
|
935
|
+
sessionMetadata: action.sessionMetadata ?? state.sessionMetadata,
|
|
603
936
|
status: action.status
|
|
604
937
|
};
|
|
605
938
|
break;
|
|
@@ -630,20 +963,50 @@ var createVoiceStreamStore = () => {
|
|
|
630
963
|
var createVoiceStream = (path, options = {}) => {
|
|
631
964
|
const connection = createVoiceConnection(path, options);
|
|
632
965
|
const store = createVoiceStreamStore();
|
|
966
|
+
const browserMediaReporter = options.browserMedia && typeof window !== "undefined" ? createVoiceBrowserMediaReporter({
|
|
967
|
+
...options.browserMedia,
|
|
968
|
+
getScenarioId: () => options.browserMedia ? options.browserMedia.getScenarioId?.() ?? connection.getScenarioId() : connection.getScenarioId(),
|
|
969
|
+
getSessionId: () => options.browserMedia ? options.browserMedia.getSessionId?.() ?? connection.getSessionId() : connection.getSessionId()
|
|
970
|
+
}) : null;
|
|
633
971
|
const subscribers = new Set;
|
|
634
972
|
const start = (input) => Promise.resolve().then(() => {
|
|
635
973
|
if (!input?.sessionId && !input?.scenarioId) {
|
|
636
974
|
return;
|
|
637
975
|
}
|
|
638
976
|
connection.start(input);
|
|
977
|
+
browserMediaReporter?.start();
|
|
639
978
|
});
|
|
640
979
|
const notify = () => {
|
|
641
980
|
subscribers.forEach((subscriber) => subscriber());
|
|
642
981
|
};
|
|
982
|
+
const reportReconnect = () => {
|
|
983
|
+
if (!options.reconnectReportPath || typeof fetch === "undefined") {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
const snapshot = store.getSnapshot();
|
|
987
|
+
const body = JSON.stringify({
|
|
988
|
+
at: Date.now(),
|
|
989
|
+
reconnect: snapshot.reconnect,
|
|
990
|
+
scenarioId: snapshot.scenarioId,
|
|
991
|
+
sessionId: connection.getSessionId(),
|
|
992
|
+
turnIds: snapshot.turns.map((turn) => turn.id)
|
|
993
|
+
});
|
|
994
|
+
fetch(options.reconnectReportPath, {
|
|
995
|
+
body,
|
|
996
|
+
headers: {
|
|
997
|
+
"Content-Type": "application/json"
|
|
998
|
+
},
|
|
999
|
+
keepalive: true,
|
|
1000
|
+
method: "POST"
|
|
1001
|
+
}).catch(() => {});
|
|
1002
|
+
};
|
|
643
1003
|
const unsubscribeConnection = connection.subscribe((message) => {
|
|
644
1004
|
const action = serverMessageToAction(message);
|
|
645
1005
|
if (action) {
|
|
646
1006
|
store.dispatch(action);
|
|
1007
|
+
if (message.type === "connection") {
|
|
1008
|
+
reportReconnect();
|
|
1009
|
+
}
|
|
647
1010
|
notify();
|
|
648
1011
|
}
|
|
649
1012
|
});
|
|
@@ -653,6 +1016,7 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
653
1016
|
},
|
|
654
1017
|
close() {
|
|
655
1018
|
unsubscribeConnection();
|
|
1019
|
+
browserMediaReporter?.close();
|
|
656
1020
|
connection.close();
|
|
657
1021
|
store.dispatch({ type: "disconnected" });
|
|
658
1022
|
notify();
|
|
@@ -675,10 +1039,16 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
675
1039
|
get scenarioId() {
|
|
676
1040
|
return store.getSnapshot().scenarioId;
|
|
677
1041
|
},
|
|
1042
|
+
get sessionMetadata() {
|
|
1043
|
+
return store.getSnapshot().sessionMetadata;
|
|
1044
|
+
},
|
|
678
1045
|
start,
|
|
679
1046
|
get partial() {
|
|
680
1047
|
return store.getSnapshot().partial;
|
|
681
1048
|
},
|
|
1049
|
+
get reconnect() {
|
|
1050
|
+
return store.getSnapshot().reconnect;
|
|
1051
|
+
},
|
|
682
1052
|
get sessionId() {
|
|
683
1053
|
return connection.getSessionId();
|
|
684
1054
|
},
|
|
@@ -700,6 +1070,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
700
1070
|
sendAudio(audio) {
|
|
701
1071
|
connection.sendAudio(audio);
|
|
702
1072
|
},
|
|
1073
|
+
simulateDisconnect() {
|
|
1074
|
+
connection.simulateDisconnect();
|
|
1075
|
+
},
|
|
703
1076
|
subscribe(subscriber) {
|
|
704
1077
|
subscribers.add(subscriber);
|
|
705
1078
|
return () => {
|
|
@@ -709,214 +1082,14 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
709
1082
|
};
|
|
710
1083
|
};
|
|
711
1084
|
|
|
712
|
-
// src/
|
|
713
|
-
var
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
var
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const stream = createVoiceStream(path, options);
|
|
721
|
-
const assistantAudioSignal = signal2([]);
|
|
722
|
-
const assistantTextsSignal = signal2([]);
|
|
723
|
-
const callSignal = signal2(null);
|
|
724
|
-
const errorSignal = signal2(null);
|
|
725
|
-
const isConnectedSignal = signal2(false);
|
|
726
|
-
const partialSignal = signal2("");
|
|
727
|
-
const sessionIdSignal = signal2(stream.sessionId);
|
|
728
|
-
const statusSignal = signal2(stream.status);
|
|
729
|
-
const turnsSignal = signal2([]);
|
|
730
|
-
const sync = () => {
|
|
731
|
-
assistantAudioSignal.set([...stream.assistantAudio]);
|
|
732
|
-
assistantTextsSignal.set([...stream.assistantTexts]);
|
|
733
|
-
callSignal.set(stream.call);
|
|
734
|
-
errorSignal.set(stream.error);
|
|
735
|
-
isConnectedSignal.set(stream.isConnected);
|
|
736
|
-
partialSignal.set(stream.partial);
|
|
737
|
-
sessionIdSignal.set(stream.sessionId);
|
|
738
|
-
statusSignal.set(stream.status);
|
|
739
|
-
turnsSignal.set([...stream.turns]);
|
|
740
|
-
};
|
|
741
|
-
const unsubscribe = stream.subscribe(sync);
|
|
742
|
-
sync();
|
|
743
|
-
return {
|
|
744
|
-
assistantAudio: computed2(() => assistantAudioSignal()),
|
|
745
|
-
assistantTexts: computed2(() => assistantTextsSignal()),
|
|
746
|
-
call: computed2(() => callSignal()),
|
|
747
|
-
callControl: (message) => stream.callControl(message),
|
|
748
|
-
close: () => {
|
|
749
|
-
unsubscribe();
|
|
750
|
-
stream.close();
|
|
751
|
-
},
|
|
752
|
-
endTurn: () => stream.endTurn(),
|
|
753
|
-
error: computed2(() => errorSignal()),
|
|
754
|
-
isConnected: computed2(() => isConnectedSignal()),
|
|
755
|
-
partial: computed2(() => partialSignal()),
|
|
756
|
-
sendAudio: (audio) => stream.sendAudio(audio),
|
|
757
|
-
sessionId: computed2(() => sessionIdSignal()),
|
|
758
|
-
status: computed2(() => statusSignal()),
|
|
759
|
-
turns: computed2(() => turnsSignal())
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
VoiceStreamService = __decorateElement(_init, 0, "VoiceStreamService", _dec, VoiceStreamService);
|
|
764
|
-
__runInitializers(_init, 1, VoiceStreamService);
|
|
765
|
-
__decoratorMetadata(_init, VoiceStreamService);
|
|
766
|
-
let _VoiceStreamService = VoiceStreamService;
|
|
767
|
-
// src/angular/voice-controller.service.ts
|
|
768
|
-
import { computed as computed3, Injectable as Injectable3, signal as signal3 } from "@angular/core";
|
|
769
|
-
|
|
770
|
-
// src/client/htmx.ts
|
|
771
|
-
var DEFAULT_EVENT_NAME = "voice-refresh";
|
|
772
|
-
var DEFAULT_QUERY_PARAM = "sessionId";
|
|
773
|
-
var resolveElement = (input) => {
|
|
774
|
-
if (typeof input !== "string") {
|
|
775
|
-
return input;
|
|
776
|
-
}
|
|
777
|
-
return document.querySelector(input);
|
|
778
|
-
};
|
|
779
|
-
var buildRoute = (element, route, queryParam, sessionId) => {
|
|
780
|
-
const baseRoute = route ?? element.getAttribute("hx-get") ?? "";
|
|
781
|
-
if (!baseRoute) {
|
|
782
|
-
return "";
|
|
783
|
-
}
|
|
784
|
-
const url = new URL(baseRoute, window.location.origin);
|
|
785
|
-
if (sessionId) {
|
|
786
|
-
url.searchParams.set(queryParam, sessionId);
|
|
787
|
-
} else {
|
|
788
|
-
url.searchParams.delete(queryParam);
|
|
789
|
-
}
|
|
790
|
-
return `${url.pathname}${url.search}${url.hash}`;
|
|
791
|
-
};
|
|
792
|
-
var bindVoiceHTMX = (stream, options) => {
|
|
793
|
-
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
794
|
-
return () => {};
|
|
795
|
-
}
|
|
796
|
-
const element = resolveElement(options.element);
|
|
797
|
-
if (!element) {
|
|
798
|
-
return () => {};
|
|
799
|
-
}
|
|
800
|
-
const eventName = options.eventName ?? DEFAULT_EVENT_NAME;
|
|
801
|
-
const queryParam = options.sessionQueryParam ?? DEFAULT_QUERY_PARAM;
|
|
802
|
-
const sync = () => {
|
|
803
|
-
const htmxWindow = window;
|
|
804
|
-
const nextRoute = buildRoute(element, options.route, queryParam, stream.sessionId);
|
|
805
|
-
if (nextRoute) {
|
|
806
|
-
element.setAttribute("hx-get", nextRoute);
|
|
807
|
-
}
|
|
808
|
-
htmxWindow.htmx?.process?.(element);
|
|
809
|
-
htmxWindow.htmx?.trigger?.(element, eventName);
|
|
810
|
-
};
|
|
811
|
-
const unsubscribe = stream.subscribe(sync);
|
|
812
|
-
sync();
|
|
813
|
-
return () => {
|
|
814
|
-
unsubscribe();
|
|
815
|
-
};
|
|
816
|
-
};
|
|
817
|
-
|
|
818
|
-
// src/client/microphone.ts
|
|
819
|
-
var clampSample = (value) => Math.max(-1, Math.min(1, value));
|
|
820
|
-
var floatTo16BitPCM = (input) => {
|
|
821
|
-
const output = new Int16Array(input.length);
|
|
822
|
-
for (let index = 0;index < input.length; index += 1) {
|
|
823
|
-
const sample = clampSample(input[index] ?? 0);
|
|
824
|
-
output[index] = sample < 0 ? sample * 32768 : sample * 32767;
|
|
825
|
-
}
|
|
826
|
-
return new Uint8Array(output.buffer);
|
|
827
|
-
};
|
|
828
|
-
var getPcmLevel = (audio) => {
|
|
829
|
-
const bytes = audio instanceof Uint8Array ? audio : new Uint8Array(audio);
|
|
830
|
-
if (bytes.byteLength < 2) {
|
|
831
|
-
return 0;
|
|
832
|
-
}
|
|
833
|
-
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
834
|
-
if (samples.length === 0) {
|
|
835
|
-
return 0;
|
|
836
|
-
}
|
|
837
|
-
let sumSquares = 0;
|
|
838
|
-
for (const sample of samples) {
|
|
839
|
-
const normalized = sample / 32768;
|
|
840
|
-
sumSquares += normalized * normalized;
|
|
841
|
-
}
|
|
842
|
-
return Math.min(1, Math.max(0, Math.sqrt(sumSquares / samples.length) * 5.5));
|
|
843
|
-
};
|
|
844
|
-
var downsampleBuffer = (input, sourceRate, targetRate) => {
|
|
845
|
-
if (sourceRate === targetRate) {
|
|
846
|
-
return input;
|
|
847
|
-
}
|
|
848
|
-
const ratio = sourceRate / targetRate;
|
|
849
|
-
const length = Math.round(input.length / ratio);
|
|
850
|
-
const output = new Float32Array(length);
|
|
851
|
-
let offsetResult = 0;
|
|
852
|
-
let offsetBuffer = 0;
|
|
853
|
-
while (offsetResult < output.length) {
|
|
854
|
-
const nextOffsetBuffer = Math.round((offsetResult + 1) * ratio);
|
|
855
|
-
let accum = 0;
|
|
856
|
-
let count = 0;
|
|
857
|
-
for (let index = offsetBuffer;index < nextOffsetBuffer && index < input.length; index += 1) {
|
|
858
|
-
accum += input[index] ?? 0;
|
|
859
|
-
count += 1;
|
|
860
|
-
}
|
|
861
|
-
output[offsetResult] = count > 0 ? accum / count : 0;
|
|
862
|
-
offsetResult += 1;
|
|
863
|
-
offsetBuffer = nextOffsetBuffer;
|
|
864
|
-
}
|
|
865
|
-
return output;
|
|
866
|
-
};
|
|
867
|
-
var createMicrophoneCapture = (options) => {
|
|
868
|
-
let audioContext = null;
|
|
869
|
-
let sourceNode = null;
|
|
870
|
-
let processorNode = null;
|
|
871
|
-
let mediaStream = null;
|
|
872
|
-
const start = async () => {
|
|
873
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
874
|
-
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
875
|
-
}
|
|
876
|
-
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
877
|
-
if (!AudioContextCtor) {
|
|
878
|
-
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
879
|
-
}
|
|
880
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
881
|
-
audio: {
|
|
882
|
-
channelCount: options.channelCount ?? 1
|
|
883
|
-
}
|
|
884
|
-
});
|
|
885
|
-
audioContext = new AudioContextCtor;
|
|
886
|
-
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
887
|
-
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
888
|
-
processorNode.onaudioprocess = (event) => {
|
|
889
|
-
const channel = event.inputBuffer.getChannelData(0);
|
|
890
|
-
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
891
|
-
const pcm = floatTo16BitPCM(downsampled);
|
|
892
|
-
options.onLevel?.(getPcmLevel(pcm));
|
|
893
|
-
options.onAudio(pcm);
|
|
894
|
-
};
|
|
895
|
-
sourceNode.connect(processorNode);
|
|
896
|
-
processorNode.connect(audioContext.destination);
|
|
897
|
-
};
|
|
898
|
-
const stop = () => {
|
|
899
|
-
processorNode?.disconnect();
|
|
900
|
-
sourceNode?.disconnect();
|
|
901
|
-
mediaStream?.getTracks().forEach((track) => track.stop());
|
|
902
|
-
audioContext?.close();
|
|
903
|
-
options.onLevel?.(0);
|
|
904
|
-
audioContext = null;
|
|
905
|
-
mediaStream = null;
|
|
906
|
-
processorNode = null;
|
|
907
|
-
sourceNode = null;
|
|
908
|
-
};
|
|
909
|
-
return { start, stop };
|
|
910
|
-
};
|
|
911
|
-
|
|
912
|
-
// src/audioConditioning.ts
|
|
913
|
-
var DEFAULT_TARGET_LEVEL = 0.08;
|
|
914
|
-
var DEFAULT_MAX_GAIN = 3;
|
|
915
|
-
var DEFAULT_NOISE_GATE_THRESHOLD = 0.006;
|
|
916
|
-
var DEFAULT_NOISE_GATE_ATTENUATION = 0.15;
|
|
917
|
-
var toInt16Array = (audio) => {
|
|
918
|
-
if (audio instanceof ArrayBuffer) {
|
|
919
|
-
return new Int16Array(audio, 0, Math.floor(audio.byteLength / 2));
|
|
1085
|
+
// src/audioConditioning.ts
|
|
1086
|
+
var DEFAULT_TARGET_LEVEL = 0.08;
|
|
1087
|
+
var DEFAULT_MAX_GAIN = 3;
|
|
1088
|
+
var DEFAULT_NOISE_GATE_THRESHOLD = 0.006;
|
|
1089
|
+
var DEFAULT_NOISE_GATE_ATTENUATION = 0.15;
|
|
1090
|
+
var toInt16Array = (audio) => {
|
|
1091
|
+
if (audio instanceof ArrayBuffer) {
|
|
1092
|
+
return new Int16Array(audio, 0, Math.floor(audio.byteLength / 2));
|
|
920
1093
|
}
|
|
921
1094
|
return new Int16Array(audio.buffer, audio.byteOffset, Math.floor(audio.byteLength / 2));
|
|
922
1095
|
};
|
|
@@ -1234,8 +1407,10 @@ var createInitialState2 = (stream) => ({
|
|
|
1234
1407
|
isConnected: stream.isConnected,
|
|
1235
1408
|
isRecording: false,
|
|
1236
1409
|
partial: stream.partial,
|
|
1410
|
+
reconnect: stream.reconnect,
|
|
1237
1411
|
recordingError: null,
|
|
1238
1412
|
sessionId: stream.sessionId,
|
|
1413
|
+
sessionMetadata: stream.sessionMetadata,
|
|
1239
1414
|
scenarioId: stream.scenarioId,
|
|
1240
1415
|
status: stream.status,
|
|
1241
1416
|
turns: [...stream.turns]
|
|
@@ -1263,7 +1438,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1263
1438
|
error: stream.error,
|
|
1264
1439
|
isConnected: stream.isConnected,
|
|
1265
1440
|
partial: stream.partial,
|
|
1441
|
+
reconnect: stream.reconnect,
|
|
1266
1442
|
sessionId: stream.sessionId,
|
|
1443
|
+
sessionMetadata: stream.sessionMetadata,
|
|
1267
1444
|
scenarioId: stream.scenarioId,
|
|
1268
1445
|
status: stream.status,
|
|
1269
1446
|
turns: [...stream.turns]
|
|
@@ -1287,7 +1464,13 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1287
1464
|
capture = createMicrophoneCapture({
|
|
1288
1465
|
channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
|
|
1289
1466
|
onLevel: options.capture?.onLevel,
|
|
1290
|
-
onAudio: (audio) =>
|
|
1467
|
+
onAudio: (audio) => {
|
|
1468
|
+
if (options.capture?.onAudio) {
|
|
1469
|
+
options.capture.onAudio(audio, stream.sendAudio);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
stream.sendAudio(audio);
|
|
1473
|
+
},
|
|
1291
1474
|
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1292
1475
|
});
|
|
1293
1476
|
return capture;
|
|
@@ -1357,10 +1540,17 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1357
1540
|
get recordingError() {
|
|
1358
1541
|
return state.recordingError;
|
|
1359
1542
|
},
|
|
1543
|
+
get reconnect() {
|
|
1544
|
+
return state.reconnect;
|
|
1545
|
+
},
|
|
1360
1546
|
sendAudio: (audio) => stream.sendAudio(audio),
|
|
1547
|
+
simulateDisconnect: () => stream.simulateDisconnect(),
|
|
1361
1548
|
get sessionId() {
|
|
1362
1549
|
return state.sessionId;
|
|
1363
1550
|
},
|
|
1551
|
+
get sessionMetadata() {
|
|
1552
|
+
return state.sessionMetadata;
|
|
1553
|
+
},
|
|
1364
1554
|
get scenarioId() {
|
|
1365
1555
|
return state.scenarioId;
|
|
1366
1556
|
},
|
|
@@ -1397,114 +1587,3441 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1397
1587
|
};
|
|
1398
1588
|
};
|
|
1399
1589
|
|
|
1400
|
-
// src/
|
|
1590
|
+
// src/agentState.ts
|
|
1591
|
+
var deriveVoiceAgentUIState = (input) => {
|
|
1592
|
+
if (!input.isConnected) {
|
|
1593
|
+
return "idle";
|
|
1594
|
+
}
|
|
1595
|
+
if (input.isPlaying) {
|
|
1596
|
+
return "speaking";
|
|
1597
|
+
}
|
|
1598
|
+
if (input.isRecording && input.hasActivePartial) {
|
|
1599
|
+
return "listening";
|
|
1600
|
+
}
|
|
1601
|
+
if (input.isRecording) {
|
|
1602
|
+
return "listening";
|
|
1603
|
+
}
|
|
1604
|
+
if (input.lastTranscriptAt && !input.lastAssistantAt) {
|
|
1605
|
+
return "thinking";
|
|
1606
|
+
}
|
|
1607
|
+
if (input.lastTranscriptAt && input.lastAssistantAt && input.lastTranscriptAt > input.lastAssistantAt) {
|
|
1608
|
+
return "thinking";
|
|
1609
|
+
}
|
|
1610
|
+
return "idle";
|
|
1611
|
+
};
|
|
1612
|
+
var describeVoiceAgentUIState = (state) => {
|
|
1613
|
+
switch (state) {
|
|
1614
|
+
case "idle":
|
|
1615
|
+
return "Idle";
|
|
1616
|
+
case "listening":
|
|
1617
|
+
return "Listening";
|
|
1618
|
+
case "speaking":
|
|
1619
|
+
return "Speaking";
|
|
1620
|
+
case "thinking":
|
|
1621
|
+
return "Thinking";
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
var voiceAgentUIStateOrder = [
|
|
1625
|
+
"idle",
|
|
1626
|
+
"listening",
|
|
1627
|
+
"thinking",
|
|
1628
|
+
"speaking"
|
|
1629
|
+
];
|
|
1630
|
+
|
|
1631
|
+
// src/client/voiceWidgetView.ts
|
|
1632
|
+
var DEFAULT_VOICE_WIDGET_THEME = {
|
|
1633
|
+
accent: "#3b82f6",
|
|
1634
|
+
background: "#0f172a",
|
|
1635
|
+
errorAccent: "#ef4444",
|
|
1636
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
1637
|
+
foreground: "#f8fafc",
|
|
1638
|
+
radius: 16
|
|
1639
|
+
};
|
|
1640
|
+
var DEFAULT_VOICE_WIDGET_LABELS = {
|
|
1641
|
+
callEnded: "Call ended",
|
|
1642
|
+
connecting: "Connecting\u2026",
|
|
1643
|
+
endCall: "End call",
|
|
1644
|
+
idle: "Idle",
|
|
1645
|
+
listening: "Listening",
|
|
1646
|
+
mute: "Mute",
|
|
1647
|
+
speaking: "Speaking",
|
|
1648
|
+
startCall: "Start call",
|
|
1649
|
+
thinking: "Thinking",
|
|
1650
|
+
unmute: "Unmute"
|
|
1651
|
+
};
|
|
1652
|
+
var stateLabel = (state, labels) => {
|
|
1653
|
+
switch (state) {
|
|
1654
|
+
case "listening":
|
|
1655
|
+
return labels.listening;
|
|
1656
|
+
case "speaking":
|
|
1657
|
+
return labels.speaking;
|
|
1658
|
+
case "thinking":
|
|
1659
|
+
return labels.thinking;
|
|
1660
|
+
case "idle":
|
|
1661
|
+
return labels.idle;
|
|
1662
|
+
}
|
|
1663
|
+
};
|
|
1664
|
+
var createVoiceWidgetViewModel = (input) => {
|
|
1665
|
+
const theme = { ...DEFAULT_VOICE_WIDGET_THEME, ...input.theme };
|
|
1666
|
+
const labels = { ...DEFAULT_VOICE_WIDGET_LABELS, ...input.labels };
|
|
1667
|
+
const lastAssistantAt = input.state.assistantAudio.at(-1)?.receivedAt;
|
|
1668
|
+
const lastTranscriptAt = input.state.turns.at(-1)?.committedAt;
|
|
1669
|
+
const agentState = deriveVoiceAgentUIState({
|
|
1670
|
+
hasActivePartial: input.state.partial.length > 0,
|
|
1671
|
+
isConnected: input.state.isConnected,
|
|
1672
|
+
isPlaying: false,
|
|
1673
|
+
isRecording: input.state.isRecording,
|
|
1674
|
+
lastAssistantAt,
|
|
1675
|
+
lastTranscriptAt
|
|
1676
|
+
});
|
|
1677
|
+
const connecting = !input.state.isConnected && input.state.status !== "idle" && !input.state.error;
|
|
1678
|
+
const statusLabel = input.state.error ? "Error" : connecting ? labels.connecting : input.state.status === "completed" ? labels.callEnded : stateLabel(agentState, labels);
|
|
1679
|
+
return {
|
|
1680
|
+
agentState,
|
|
1681
|
+
classes: {
|
|
1682
|
+
container: `absolute-voice-widget absolute-voice-widget--${agentState}`,
|
|
1683
|
+
dot: `absolute-voice-widget__dot${input.state.error ? " absolute-voice-widget__dot--error" : ""}`
|
|
1684
|
+
},
|
|
1685
|
+
controls: {
|
|
1686
|
+
canEnd: input.state.isConnected,
|
|
1687
|
+
canMute: input.state.isRecording,
|
|
1688
|
+
canStart: !input.state.isRecording && input.state.status !== "completed"
|
|
1689
|
+
},
|
|
1690
|
+
errorMessage: input.state.error ?? undefined,
|
|
1691
|
+
labels,
|
|
1692
|
+
partial: input.state.partial || undefined,
|
|
1693
|
+
statusLabel,
|
|
1694
|
+
theme,
|
|
1695
|
+
title: input.title ?? "Voice"
|
|
1696
|
+
};
|
|
1697
|
+
};
|
|
1698
|
+
var escapeHtml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1699
|
+
var resolveRadius = (radius) => typeof radius === "number" ? `${radius}px` : radius;
|
|
1700
|
+
var renderVoiceWidgetHTML = (model) => {
|
|
1701
|
+
const t = model.theme;
|
|
1702
|
+
const containerStyle = `background:${t.background};border-radius:${resolveRadius(t.radius)};color:${t.foreground};font-family:${t.fontFamily};min-width:240px;padding:20px 22px;`;
|
|
1703
|
+
const dotStyle = `background:${model.errorMessage ? t.errorAccent : model.agentState === "idle" ? "rgba(148,163,184,0.6)" : t.accent};border-radius:50%;height:10px;width:10px;`;
|
|
1704
|
+
const buttons = [];
|
|
1705
|
+
if (model.controls.canStart) {
|
|
1706
|
+
buttons.push(`<button type="button" data-action="start" style="background:${t.accent};border:none;border-radius:12px;color:${t.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${escapeHtml(model.labels.startCall)}</button>`);
|
|
1707
|
+
}
|
|
1708
|
+
if (model.controls.canMute) {
|
|
1709
|
+
buttons.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${t.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${escapeHtml(model.labels.mute)}</button>`);
|
|
1710
|
+
}
|
|
1711
|
+
if (model.controls.canEnd) {
|
|
1712
|
+
buttons.push(`<button type="button" data-action="end" style="background:${t.errorAccent};border:none;border-radius:12px;color:${t.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${escapeHtml(model.labels.endCall)}</button>`);
|
|
1713
|
+
}
|
|
1714
|
+
return `<div role="region" aria-live="polite" data-agent-state="${model.agentState}" class="${escapeHtml(model.classes.container)}" style="${containerStyle}">
|
|
1715
|
+
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
1716
|
+
<span aria-hidden="true" class="${escapeHtml(model.classes.dot)}" style="${dotStyle}"></span>
|
|
1717
|
+
<strong style="font-size:15px;">${escapeHtml(model.title)}</strong>
|
|
1718
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${escapeHtml(model.statusLabel)}</span>
|
|
1719
|
+
</div>
|
|
1720
|
+
${model.partial ? `<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">\u201C${escapeHtml(model.partial)}\u201D</p>` : ""}
|
|
1721
|
+
<div style="display:flex;gap:10px;">${buttons.join("")}</div>
|
|
1722
|
+
${model.errorMessage ? `<p style="color:${t.errorAccent};font-size:12px;margin-top:12px;">${escapeHtml(model.errorMessage)}</p>` : ""}
|
|
1723
|
+
</div>`;
|
|
1724
|
+
};
|
|
1725
|
+
|
|
1726
|
+
// src/angular/voice-widget.service.ts
|
|
1401
1727
|
var _dec = [
|
|
1402
|
-
|
|
1728
|
+
Injectable2({ providedIn: "root" })
|
|
1403
1729
|
];
|
|
1404
1730
|
var _init = __decoratorStart(undefined);
|
|
1405
1731
|
|
|
1406
|
-
class
|
|
1732
|
+
class VoiceWidgetService {
|
|
1407
1733
|
connect(path, options = {}) {
|
|
1408
1734
|
const controller = createVoiceController(path, options);
|
|
1409
|
-
const
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
const recordingErrorSignal = signal3(null);
|
|
1416
|
-
const sessionIdSignal = signal3(controller.sessionId);
|
|
1417
|
-
const statusSignal = signal3(controller.status);
|
|
1418
|
-
const turnsSignal = signal3([]);
|
|
1735
|
+
const viewModelSignal = signal2(createVoiceWidgetViewModel({
|
|
1736
|
+
labels: options.labels,
|
|
1737
|
+
state: controller.getSnapshot(),
|
|
1738
|
+
theme: options.theme,
|
|
1739
|
+
title: options.title
|
|
1740
|
+
}));
|
|
1419
1741
|
const sync = () => {
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
recordingErrorSignal.set(controller.recordingError);
|
|
1427
|
-
sessionIdSignal.set(controller.sessionId);
|
|
1428
|
-
statusSignal.set(controller.status);
|
|
1429
|
-
turnsSignal.set([...controller.turns]);
|
|
1742
|
+
viewModelSignal.set(createVoiceWidgetViewModel({
|
|
1743
|
+
labels: options.labels,
|
|
1744
|
+
state: controller.getSnapshot(),
|
|
1745
|
+
theme: options.theme,
|
|
1746
|
+
title: options.title
|
|
1747
|
+
}));
|
|
1430
1748
|
};
|
|
1431
1749
|
const unsubscribe = controller.subscribe(sync);
|
|
1432
1750
|
sync();
|
|
1433
1751
|
return {
|
|
1434
|
-
assistantAudio: computed3(() => assistantAudioSignal()),
|
|
1435
|
-
assistantTexts: computed3(() => assistantTextsSignal()),
|
|
1436
|
-
bindHTMX: controller.bindHTMX,
|
|
1437
1752
|
close: () => {
|
|
1438
1753
|
unsubscribe();
|
|
1439
1754
|
controller.close();
|
|
1440
1755
|
},
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
sendAudio: (audio) => controller.sendAudio(audio),
|
|
1448
|
-
sessionId: computed3(() => sessionIdSignal()),
|
|
1449
|
-
startRecording: () => controller.startRecording(),
|
|
1450
|
-
status: computed3(() => statusSignal()),
|
|
1451
|
-
stopRecording: () => controller.stopRecording(),
|
|
1452
|
-
toggleRecording: () => controller.toggleRecording(),
|
|
1453
|
-
turns: computed3(() => turnsSignal())
|
|
1756
|
+
endCall: () => controller.close(),
|
|
1757
|
+
getHTML: () => renderVoiceWidgetHTML(viewModelSignal()),
|
|
1758
|
+
mute: () => controller.stopRecording(),
|
|
1759
|
+
startCall: () => controller.startRecording(),
|
|
1760
|
+
unmute: () => controller.startRecording(),
|
|
1761
|
+
viewModel: computed2(() => viewModelSignal())
|
|
1454
1762
|
};
|
|
1455
1763
|
}
|
|
1456
1764
|
}
|
|
1457
|
-
|
|
1458
|
-
__runInitializers(_init, 1,
|
|
1459
|
-
__decoratorMetadata(_init,
|
|
1460
|
-
let
|
|
1461
|
-
// src/angular/voice-
|
|
1462
|
-
import { computed as
|
|
1765
|
+
VoiceWidgetService = __decorateElement(_init, 0, "VoiceWidgetService", _dec, VoiceWidgetService);
|
|
1766
|
+
__runInitializers(_init, 1, VoiceWidgetService);
|
|
1767
|
+
__decoratorMetadata(_init, VoiceWidgetService);
|
|
1768
|
+
let _VoiceWidgetService = VoiceWidgetService;
|
|
1769
|
+
// src/angular/voice-call-player.service.ts
|
|
1770
|
+
import { computed as computed3, Injectable as Injectable3, signal as signal3 } from "@angular/core";
|
|
1463
1771
|
|
|
1464
|
-
// src/client/
|
|
1465
|
-
var
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1772
|
+
// src/client/callPlayer.ts
|
|
1773
|
+
var cloneState = (state) => ({
|
|
1774
|
+
...state
|
|
1775
|
+
});
|
|
1776
|
+
var normalizeTranscriptTimes = (transcripts, baseEpoch) => {
|
|
1777
|
+
if (typeof baseEpoch !== "number") {
|
|
1778
|
+
return transcripts;
|
|
1470
1779
|
}
|
|
1471
|
-
return
|
|
1780
|
+
return transcripts.map((transcript) => {
|
|
1781
|
+
const adjusted = { ...transcript };
|
|
1782
|
+
if (typeof adjusted.startedAtMs === "number" && adjusted.startedAtMs >= baseEpoch) {
|
|
1783
|
+
adjusted.startedAtMs = adjusted.startedAtMs - baseEpoch;
|
|
1784
|
+
}
|
|
1785
|
+
if (typeof adjusted.endedAtMs === "number" && adjusted.endedAtMs >= baseEpoch) {
|
|
1786
|
+
adjusted.endedAtMs = adjusted.endedAtMs - baseEpoch;
|
|
1787
|
+
}
|
|
1788
|
+
return adjusted;
|
|
1789
|
+
});
|
|
1472
1790
|
};
|
|
1473
|
-
var
|
|
1474
|
-
|
|
1475
|
-
let
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1791
|
+
var findActiveTranscript = (transcripts, positionMs) => {
|
|
1792
|
+
let candidate;
|
|
1793
|
+
for (let index = 0;index < transcripts.length; index += 1) {
|
|
1794
|
+
const transcript = transcripts[index];
|
|
1795
|
+
if (typeof transcript.startedAtMs !== "number")
|
|
1796
|
+
continue;
|
|
1797
|
+
if (transcript.startedAtMs > positionMs)
|
|
1798
|
+
break;
|
|
1799
|
+
if (typeof transcript.endedAtMs === "number" && transcript.endedAtMs < positionMs) {
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
candidate = { id: transcript.id, index };
|
|
1803
|
+
}
|
|
1804
|
+
return candidate ?? {};
|
|
1805
|
+
};
|
|
1806
|
+
var createVoiceCallPlayer = (options = {}) => {
|
|
1807
|
+
let transcripts = normalizeTranscriptTimes(options.transcripts ?? [], options.recordingStartedAtEpochMs);
|
|
1808
|
+
let state = {
|
|
1809
|
+
audioUrl: options.audioUrl,
|
|
1810
|
+
buffered: 0,
|
|
1811
|
+
currentTimeMs: 0,
|
|
1812
|
+
durationMs: 0,
|
|
1813
|
+
isPlaying: false,
|
|
1814
|
+
isReady: false,
|
|
1815
|
+
playbackRate: options.initialPlaybackRate ?? 1
|
|
1481
1816
|
};
|
|
1482
|
-
const
|
|
1483
|
-
|
|
1817
|
+
const listeners = new Set;
|
|
1818
|
+
const notify = () => {
|
|
1819
|
+
for (const listener of listeners)
|
|
1484
1820
|
listener();
|
|
1485
|
-
}
|
|
1486
1821
|
};
|
|
1487
|
-
const
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
const providers = await fetchVoiceProviderStatus(path, options);
|
|
1499
|
-
snapshot = {
|
|
1500
|
-
error: null,
|
|
1501
|
-
isLoading: false,
|
|
1502
|
-
providers,
|
|
1503
|
-
updatedAt: Date.now()
|
|
1822
|
+
const update = (next) => {
|
|
1823
|
+
state = { ...state, ...next };
|
|
1824
|
+
notify();
|
|
1825
|
+
};
|
|
1826
|
+
const refreshActive = () => {
|
|
1827
|
+
const { id, index } = findActiveTranscript(transcripts, state.currentTimeMs);
|
|
1828
|
+
if (id !== state.activeTranscriptId || index !== state.activeTranscriptIndex) {
|
|
1829
|
+
state = {
|
|
1830
|
+
...state,
|
|
1831
|
+
activeTranscriptId: id,
|
|
1832
|
+
activeTranscriptIndex: index
|
|
1504
1833
|
};
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1834
|
+
notify();
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
return {
|
|
1838
|
+
getState: () => cloneState(state),
|
|
1839
|
+
pause: () => {
|
|
1840
|
+
if (!state.isPlaying)
|
|
1841
|
+
return;
|
|
1842
|
+
update({ isPlaying: false });
|
|
1843
|
+
},
|
|
1844
|
+
play: async () => {
|
|
1845
|
+
update({ isPlaying: true });
|
|
1846
|
+
},
|
|
1847
|
+
reset: () => {
|
|
1848
|
+
state = {
|
|
1849
|
+
audioUrl: state.audioUrl,
|
|
1850
|
+
buffered: 0,
|
|
1851
|
+
currentTimeMs: 0,
|
|
1852
|
+
durationMs: 0,
|
|
1853
|
+
isPlaying: false,
|
|
1854
|
+
isReady: false,
|
|
1855
|
+
playbackRate: 1
|
|
1856
|
+
};
|
|
1857
|
+
notify();
|
|
1858
|
+
},
|
|
1859
|
+
seekMs: (positionMs) => {
|
|
1860
|
+
const clamped = Math.max(0, Math.min(state.durationMs || Number.POSITIVE_INFINITY, positionMs));
|
|
1861
|
+
update({ currentTimeMs: clamped });
|
|
1862
|
+
refreshActive();
|
|
1863
|
+
},
|
|
1864
|
+
seekToTranscript: (transcriptId) => {
|
|
1865
|
+
const found = transcripts.find((t) => t.id === transcriptId);
|
|
1866
|
+
if (!found || typeof found.startedAtMs !== "number") {
|
|
1867
|
+
return;
|
|
1868
|
+
}
|
|
1869
|
+
update({ currentTimeMs: Math.max(0, found.startedAtMs) });
|
|
1870
|
+
refreshActive();
|
|
1871
|
+
},
|
|
1872
|
+
setAudioUrl: (url) => {
|
|
1873
|
+
update({ audioUrl: url, isReady: false });
|
|
1874
|
+
},
|
|
1875
|
+
setBuffered: (seconds) => {
|
|
1876
|
+
update({ buffered: Math.max(0, seconds) });
|
|
1877
|
+
},
|
|
1878
|
+
setDuration: (durationMs) => {
|
|
1879
|
+
update({ durationMs: Math.max(0, durationMs) });
|
|
1880
|
+
},
|
|
1881
|
+
setError: (error) => {
|
|
1882
|
+
update({ error });
|
|
1883
|
+
},
|
|
1884
|
+
setPlaybackRate: (rate) => {
|
|
1885
|
+
update({ playbackRate: Math.max(0.25, Math.min(4, rate)) });
|
|
1886
|
+
},
|
|
1887
|
+
setPlaying: (playing) => {
|
|
1888
|
+
if (playing === state.isPlaying)
|
|
1889
|
+
return;
|
|
1890
|
+
update({ isPlaying: playing });
|
|
1891
|
+
},
|
|
1892
|
+
setReady: (ready) => {
|
|
1893
|
+
update({ isReady: ready });
|
|
1894
|
+
},
|
|
1895
|
+
setTime: (positionMs) => {
|
|
1896
|
+
const next = Math.max(0, positionMs);
|
|
1897
|
+
if (next === state.currentTimeMs)
|
|
1898
|
+
return;
|
|
1899
|
+
update({ currentTimeMs: next });
|
|
1900
|
+
refreshActive();
|
|
1901
|
+
},
|
|
1902
|
+
setTranscripts: (next) => {
|
|
1903
|
+
transcripts = normalizeTranscriptTimes(next, options.recordingStartedAtEpochMs);
|
|
1904
|
+
refreshActive();
|
|
1905
|
+
},
|
|
1906
|
+
subscribe: (listener) => {
|
|
1907
|
+
listeners.add(listener);
|
|
1908
|
+
return () => {
|
|
1909
|
+
listeners.delete(listener);
|
|
1910
|
+
};
|
|
1911
|
+
},
|
|
1912
|
+
transcripts: () => transcripts
|
|
1913
|
+
};
|
|
1914
|
+
};
|
|
1915
|
+
var formatVoiceCallPlayerTimestamp = (ms) => {
|
|
1916
|
+
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
1917
|
+
const minutes = Math.floor(seconds / 60);
|
|
1918
|
+
const remaining = seconds % 60;
|
|
1919
|
+
return `${String(minutes).padStart(2, "0")}:${String(remaining).padStart(2, "0")}`;
|
|
1920
|
+
};
|
|
1921
|
+
|
|
1922
|
+
// src/angular/voice-call-player.service.ts
|
|
1923
|
+
var _dec = [
|
|
1924
|
+
Injectable3({ providedIn: "root" })
|
|
1925
|
+
];
|
|
1926
|
+
var _init = __decoratorStart(undefined);
|
|
1927
|
+
|
|
1928
|
+
class VoiceCallPlayerService {
|
|
1929
|
+
build(options = {}) {
|
|
1930
|
+
const player = createVoiceCallPlayer(options);
|
|
1931
|
+
const stateSignal = signal3(player.getState());
|
|
1932
|
+
const unsubscribe = player.subscribe(() => {
|
|
1933
|
+
stateSignal.set(player.getState());
|
|
1934
|
+
});
|
|
1935
|
+
return {
|
|
1936
|
+
formatTimestamp: formatVoiceCallPlayerTimestamp,
|
|
1937
|
+
pause: () => player.pause(),
|
|
1938
|
+
play: () => player.play(),
|
|
1939
|
+
seekMs: (ms) => player.seekMs(ms),
|
|
1940
|
+
seekToTranscript: (id) => player.seekToTranscript(id),
|
|
1941
|
+
setPlaybackRate: (rate) => player.setPlaybackRate(rate),
|
|
1942
|
+
setTime: (ms) => player.setTime(ms),
|
|
1943
|
+
state: computed3(() => stateSignal()),
|
|
1944
|
+
stop: () => unsubscribe(),
|
|
1945
|
+
title: options.title ?? "Call replay",
|
|
1946
|
+
transcripts: () => player.transcripts()
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
VoiceCallPlayerService = __decorateElement(_init, 0, "VoiceCallPlayerService", _dec, VoiceCallPlayerService);
|
|
1951
|
+
__runInitializers(_init, 1, VoiceCallPlayerService);
|
|
1952
|
+
__decoratorMetadata(_init, VoiceCallPlayerService);
|
|
1953
|
+
let _VoiceCallPlayerService = VoiceCallPlayerService;
|
|
1954
|
+
// src/angular/voice-cost-dashboard.service.ts
|
|
1955
|
+
import { computed as computed4, Injectable as Injectable4, signal as signal4 } from "@angular/core";
|
|
1956
|
+
|
|
1957
|
+
// src/client/costDashboard.ts
|
|
1958
|
+
var padTwo = (value) => String(value).padStart(2, "0");
|
|
1959
|
+
var formatBucketKey = (epochMs, bucketBy) => {
|
|
1960
|
+
const date = new Date(epochMs);
|
|
1961
|
+
const y = date.getUTCFullYear();
|
|
1962
|
+
const m = padTwo(date.getUTCMonth() + 1);
|
|
1963
|
+
const d = padTwo(date.getUTCDate());
|
|
1964
|
+
const h = padTwo(date.getUTCHours());
|
|
1965
|
+
if (bucketBy === "month")
|
|
1966
|
+
return `${y}-${m}`;
|
|
1967
|
+
if (bucketBy === "day")
|
|
1968
|
+
return `${y}-${m}-${d}`;
|
|
1969
|
+
return `${y}-${m}-${d}T${h}`;
|
|
1970
|
+
};
|
|
1971
|
+
var isCostBreakdown = (value) => Boolean(value) && typeof value === "object" && typeof value.totalUsd === "number";
|
|
1972
|
+
var emptyBucket = (bucketKey) => ({
|
|
1973
|
+
bucketKey,
|
|
1974
|
+
callCount: 0,
|
|
1975
|
+
llmUsd: 0,
|
|
1976
|
+
sttUsd: 0,
|
|
1977
|
+
telephonyMinutes: 0,
|
|
1978
|
+
telephonyUsd: 0,
|
|
1979
|
+
totalUsd: 0,
|
|
1980
|
+
ttsUsd: 0
|
|
1981
|
+
});
|
|
1982
|
+
var accumulate = (bucket, payload) => {
|
|
1983
|
+
bucket.callCount += 1;
|
|
1984
|
+
bucket.llmUsd += payload.llm.usd;
|
|
1985
|
+
bucket.sttUsd += payload.stt.usd;
|
|
1986
|
+
bucket.ttsUsd += payload.tts.usd;
|
|
1987
|
+
bucket.telephonyUsd += payload.telephony.usd;
|
|
1988
|
+
bucket.telephonyMinutes += payload.telephony.minutes;
|
|
1989
|
+
bucket.totalUsd += payload.totalUsd;
|
|
1990
|
+
};
|
|
1991
|
+
var roundCurrency = (bucket) => {
|
|
1992
|
+
bucket.llmUsd = Math.round(bucket.llmUsd * 1e6) / 1e6;
|
|
1993
|
+
bucket.sttUsd = Math.round(bucket.sttUsd * 1e6) / 1e6;
|
|
1994
|
+
bucket.ttsUsd = Math.round(bucket.ttsUsd * 1e6) / 1e6;
|
|
1995
|
+
bucket.telephonyUsd = Math.round(bucket.telephonyUsd * 1e6) / 1e6;
|
|
1996
|
+
bucket.totalUsd = Math.round(bucket.totalUsd * 1e6) / 1e6;
|
|
1997
|
+
};
|
|
1998
|
+
var buildVoiceCostDashboardReport = (options) => {
|
|
1999
|
+
const bucketBy = options.bucketBy ?? "day";
|
|
2000
|
+
const fromMs = options.fromMs ?? Number.NEGATIVE_INFINITY;
|
|
2001
|
+
const toMs = options.toMs ?? Number.POSITIVE_INFINITY;
|
|
2002
|
+
const buckets = new Map;
|
|
2003
|
+
const grandTotal = emptyBucket("total");
|
|
2004
|
+
let minMs = Number.POSITIVE_INFINITY;
|
|
2005
|
+
let maxMs = Number.NEGATIVE_INFINITY;
|
|
2006
|
+
for (const event of options.events) {
|
|
2007
|
+
if (event.type !== "cost.ready")
|
|
2008
|
+
continue;
|
|
2009
|
+
if (event.at < fromMs || event.at > toMs)
|
|
2010
|
+
continue;
|
|
2011
|
+
if (!isCostBreakdown(event.payload))
|
|
2012
|
+
continue;
|
|
2013
|
+
minMs = Math.min(minMs, event.at);
|
|
2014
|
+
maxMs = Math.max(maxMs, event.at);
|
|
2015
|
+
const bucketKey = formatBucketKey(event.at, bucketBy);
|
|
2016
|
+
let bucket = buckets.get(bucketKey);
|
|
2017
|
+
if (!bucket) {
|
|
2018
|
+
bucket = emptyBucket(bucketKey);
|
|
2019
|
+
buckets.set(bucketKey, bucket);
|
|
2020
|
+
}
|
|
2021
|
+
accumulate(bucket, event.payload);
|
|
2022
|
+
accumulate(grandTotal, event.payload);
|
|
2023
|
+
}
|
|
2024
|
+
for (const bucket of buckets.values()) {
|
|
2025
|
+
roundCurrency(bucket);
|
|
2026
|
+
}
|
|
2027
|
+
roundCurrency(grandTotal);
|
|
2028
|
+
return {
|
|
2029
|
+
buckets: Array.from(buckets.values()).sort((a, b) => a.bucketKey.localeCompare(b.bucketKey)),
|
|
2030
|
+
generatedAt: Date.now(),
|
|
2031
|
+
grandTotal,
|
|
2032
|
+
windowEndMs: Number.isFinite(maxMs) ? maxMs : 0,
|
|
2033
|
+
windowStartMs: Number.isFinite(minMs) ? minMs : 0
|
|
2034
|
+
};
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
// src/angular/voice-cost-dashboard.service.ts
|
|
2038
|
+
var _dec = [
|
|
2039
|
+
Injectable4({ providedIn: "root" })
|
|
2040
|
+
];
|
|
2041
|
+
var _init = __decoratorStart(undefined);
|
|
2042
|
+
|
|
2043
|
+
class VoiceCostDashboardService {
|
|
2044
|
+
build(options) {
|
|
2045
|
+
const events = signal4(options.events);
|
|
2046
|
+
const filters = signal4({
|
|
2047
|
+
bucketBy: options.bucketBy,
|
|
2048
|
+
fromMs: options.fromMs,
|
|
2049
|
+
toMs: options.toMs
|
|
2050
|
+
});
|
|
2051
|
+
const report = computed4(() => {
|
|
2052
|
+
const f = filters();
|
|
2053
|
+
return buildVoiceCostDashboardReport({
|
|
2054
|
+
bucketBy: f.bucketBy,
|
|
2055
|
+
events: events(),
|
|
2056
|
+
fromMs: f.fromMs,
|
|
2057
|
+
toMs: f.toMs
|
|
2058
|
+
});
|
|
2059
|
+
});
|
|
2060
|
+
return {
|
|
2061
|
+
currency: options.currency ?? "USD",
|
|
2062
|
+
report,
|
|
2063
|
+
setEvents: (next) => events.set(next),
|
|
2064
|
+
setFilters: (next) => filters.update((current) => ({
|
|
2065
|
+
...current,
|
|
2066
|
+
bucketBy: next.bucketBy ?? current.bucketBy,
|
|
2067
|
+
fromMs: next.fromMs ?? current.fromMs,
|
|
2068
|
+
toMs: next.toMs ?? current.toMs
|
|
2069
|
+
})),
|
|
2070
|
+
title: options.title ?? "Voice cost dashboard"
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
VoiceCostDashboardService = __decorateElement(_init, 0, "VoiceCostDashboardService", _dec, VoiceCostDashboardService);
|
|
2075
|
+
__runInitializers(_init, 1, VoiceCostDashboardService);
|
|
2076
|
+
__decoratorMetadata(_init, VoiceCostDashboardService);
|
|
2077
|
+
let _VoiceCostDashboardService = VoiceCostDashboardService;
|
|
2078
|
+
// src/angular/voice-live-agent-console.service.ts
|
|
2079
|
+
import { computed as computed5, Injectable as Injectable5, signal as signal5 } from "@angular/core";
|
|
2080
|
+
|
|
2081
|
+
// src/client/liveCallViewer.ts
|
|
2082
|
+
var EVENT_BUFFER_LIMIT = 200;
|
|
2083
|
+
var createLiveCallViewer = (options) => {
|
|
2084
|
+
const bufferLimit = options.bufferLimit ?? EVENT_BUFFER_LIMIT;
|
|
2085
|
+
const subscribers = new Set;
|
|
2086
|
+
let state = {
|
|
2087
|
+
agentState: "idle",
|
|
2088
|
+
callDurationMs: 0,
|
|
2089
|
+
events: [],
|
|
2090
|
+
isConnected: true,
|
|
2091
|
+
isLiveListening: true,
|
|
2092
|
+
partialTranscript: "",
|
|
2093
|
+
sessionId: options.sessionId
|
|
2094
|
+
};
|
|
2095
|
+
const startedAt = options.startedAt ?? Date.now();
|
|
2096
|
+
const notify = () => {
|
|
2097
|
+
for (const subscriber of subscribers)
|
|
2098
|
+
subscriber();
|
|
2099
|
+
};
|
|
2100
|
+
const update = (next) => {
|
|
2101
|
+
state = { ...state, ...next };
|
|
2102
|
+
state.callDurationMs = Math.max(0, Date.now() - startedAt);
|
|
2103
|
+
state.agentState = deriveVoiceAgentUIState({
|
|
2104
|
+
hasActivePartial: state.partialTranscript.length > 0,
|
|
2105
|
+
isConnected: state.isConnected,
|
|
2106
|
+
isPlaying: false,
|
|
2107
|
+
isRecording: state.isLiveListening,
|
|
2108
|
+
lastAssistantAt: state.lastAssistantAt,
|
|
2109
|
+
lastTranscriptAt: state.lastTranscriptAt
|
|
2110
|
+
});
|
|
2111
|
+
notify();
|
|
2112
|
+
};
|
|
2113
|
+
const pushEvent = (event) => {
|
|
2114
|
+
const next = state.events.concat(event);
|
|
2115
|
+
if (next.length > bufferLimit) {
|
|
2116
|
+
next.splice(0, next.length - bufferLimit);
|
|
2117
|
+
}
|
|
2118
|
+
update({ events: next });
|
|
2119
|
+
};
|
|
2120
|
+
return {
|
|
2121
|
+
applyControl: (control) => {
|
|
2122
|
+
pushEvent({
|
|
2123
|
+
at: Date.now(),
|
|
2124
|
+
detail: control.reason,
|
|
2125
|
+
kind: "lifecycle",
|
|
2126
|
+
title: `control:${control.type}`
|
|
2127
|
+
});
|
|
2128
|
+
},
|
|
2129
|
+
applyEvent: pushEvent,
|
|
2130
|
+
applyMonitorEvent: ({ payload, type }) => {
|
|
2131
|
+
pushEvent({
|
|
2132
|
+
at: Date.now(),
|
|
2133
|
+
detail: JSON.stringify(payload).slice(0, 240),
|
|
2134
|
+
kind: type === "call.lifecycle" ? "lifecycle" : "lifecycle",
|
|
2135
|
+
title: type
|
|
2136
|
+
});
|
|
2137
|
+
},
|
|
2138
|
+
getState: () => state,
|
|
2139
|
+
noteAgentAudio: (at) => {
|
|
2140
|
+
const ts = at ?? Date.now();
|
|
2141
|
+
update({ lastAssistantAt: ts });
|
|
2142
|
+
pushEvent({
|
|
2143
|
+
at: ts,
|
|
2144
|
+
kind: "agent_audio",
|
|
2145
|
+
title: "Agent audio frame"
|
|
2146
|
+
});
|
|
2147
|
+
},
|
|
2148
|
+
notePartial: (text, at) => {
|
|
2149
|
+
update({ partialTranscript: text });
|
|
2150
|
+
if (text) {
|
|
2151
|
+
pushEvent({
|
|
2152
|
+
at: at ?? Date.now(),
|
|
2153
|
+
detail: text,
|
|
2154
|
+
kind: "transcript",
|
|
2155
|
+
title: "Partial"
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
},
|
|
2159
|
+
noteTranscript: (text, at) => {
|
|
2160
|
+
const ts = at ?? Date.now();
|
|
2161
|
+
update({ lastTranscriptAt: ts, partialTranscript: "" });
|
|
2162
|
+
pushEvent({
|
|
2163
|
+
at: ts,
|
|
2164
|
+
detail: text,
|
|
2165
|
+
kind: "transcript",
|
|
2166
|
+
title: "Final transcript"
|
|
2167
|
+
});
|
|
2168
|
+
},
|
|
2169
|
+
reset: (sessionId, startedAtOverride) => {
|
|
2170
|
+
state = {
|
|
2171
|
+
agentState: "idle",
|
|
2172
|
+
callDurationMs: 0,
|
|
2173
|
+
events: [],
|
|
2174
|
+
isConnected: true,
|
|
2175
|
+
isLiveListening: true,
|
|
2176
|
+
partialTranscript: "",
|
|
2177
|
+
sessionId
|
|
2178
|
+
};
|
|
2179
|
+
if (typeof startedAtOverride === "number") {}
|
|
2180
|
+
notify();
|
|
2181
|
+
},
|
|
2182
|
+
subscribe: (subscriber) => {
|
|
2183
|
+
subscribers.add(subscriber);
|
|
2184
|
+
return () => subscribers.delete(subscriber);
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
};
|
|
2188
|
+
|
|
2189
|
+
// src/client/liveAgentConsole.ts
|
|
2190
|
+
var createLiveAgentConsole = (options) => {
|
|
2191
|
+
const viewer = createLiveCallViewer(options);
|
|
2192
|
+
const recentLimit = Math.max(1, options.recentLimit ?? 12);
|
|
2193
|
+
let caller;
|
|
2194
|
+
let hasTakeover = false;
|
|
2195
|
+
let takeoverAt;
|
|
2196
|
+
let takeoverReason;
|
|
2197
|
+
const subscribers = new Set;
|
|
2198
|
+
const buildState = () => {
|
|
2199
|
+
const view = viewer.getState();
|
|
2200
|
+
return {
|
|
2201
|
+
caller,
|
|
2202
|
+
hasTakeover,
|
|
2203
|
+
recentTimeline: view.events.slice(-recentLimit),
|
|
2204
|
+
takeoverAt,
|
|
2205
|
+
takeoverReason,
|
|
2206
|
+
view
|
|
2207
|
+
};
|
|
2208
|
+
};
|
|
2209
|
+
const notify = () => {
|
|
2210
|
+
for (const subscriber of subscribers)
|
|
2211
|
+
subscriber();
|
|
2212
|
+
};
|
|
2213
|
+
const unsubscribeViewer = viewer.subscribe(() => {
|
|
2214
|
+
notify();
|
|
2215
|
+
});
|
|
2216
|
+
if (options.resolveCaller) {
|
|
2217
|
+
Promise.resolve(options.resolveCaller()).then((snapshot) => {
|
|
2218
|
+
caller = snapshot;
|
|
2219
|
+
notify();
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
return {
|
|
2223
|
+
getState: buildState,
|
|
2224
|
+
noteAgentAudio: (at) => viewer.noteAgentAudio(at),
|
|
2225
|
+
notePartial: (text, at) => viewer.notePartial(text, at),
|
|
2226
|
+
noteTranscript: (text, at) => viewer.noteTranscript(text, at),
|
|
2227
|
+
releaseTakeover: () => {
|
|
2228
|
+
if (!hasTakeover)
|
|
2229
|
+
return;
|
|
2230
|
+
hasTakeover = false;
|
|
2231
|
+
takeoverAt = undefined;
|
|
2232
|
+
takeoverReason = undefined;
|
|
2233
|
+
viewer.applyControl({ reason: "released", type: "takeover.release" });
|
|
2234
|
+
notify();
|
|
2235
|
+
},
|
|
2236
|
+
setCaller: (snapshot) => {
|
|
2237
|
+
caller = snapshot;
|
|
2238
|
+
notify();
|
|
2239
|
+
},
|
|
2240
|
+
subscribe: (listener) => {
|
|
2241
|
+
subscribers.add(listener);
|
|
2242
|
+
return () => {
|
|
2243
|
+
subscribers.delete(listener);
|
|
2244
|
+
if (subscribers.size === 0)
|
|
2245
|
+
unsubscribeViewer();
|
|
2246
|
+
};
|
|
2247
|
+
},
|
|
2248
|
+
takeover: (reason) => {
|
|
2249
|
+
if (hasTakeover)
|
|
2250
|
+
return;
|
|
2251
|
+
hasTakeover = true;
|
|
2252
|
+
takeoverAt = Date.now();
|
|
2253
|
+
takeoverReason = reason;
|
|
2254
|
+
viewer.applyControl({ reason, type: "takeover.engaged" });
|
|
2255
|
+
notify();
|
|
2256
|
+
},
|
|
2257
|
+
viewer
|
|
2258
|
+
};
|
|
2259
|
+
};
|
|
2260
|
+
|
|
2261
|
+
// src/angular/voice-live-agent-console.service.ts
|
|
2262
|
+
var _dec = [
|
|
2263
|
+
Injectable5({ providedIn: "root" })
|
|
2264
|
+
];
|
|
2265
|
+
var _init = __decoratorStart(undefined);
|
|
2266
|
+
|
|
2267
|
+
class VoiceLiveAgentConsoleService {
|
|
2268
|
+
build(options) {
|
|
2269
|
+
const console = createLiveAgentConsole(options);
|
|
2270
|
+
const stateSignal = signal5(console.getState());
|
|
2271
|
+
const unsubscribe = console.subscribe(() => {
|
|
2272
|
+
stateSignal.set(console.getState());
|
|
2273
|
+
});
|
|
2274
|
+
return {
|
|
2275
|
+
releaseTakeover: () => console.releaseTakeover(),
|
|
2276
|
+
setCaller: (caller) => console.setCaller(caller),
|
|
2277
|
+
state: computed5(() => stateSignal()),
|
|
2278
|
+
stop: () => unsubscribe(),
|
|
2279
|
+
takeover: (reason) => console.takeover(reason),
|
|
2280
|
+
takeoverButtonLabel: options.takeoverButtonLabel ?? "Take over",
|
|
2281
|
+
title: options.title ?? "Live agent console"
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
VoiceLiveAgentConsoleService = __decorateElement(_init, 0, "VoiceLiveAgentConsoleService", _dec, VoiceLiveAgentConsoleService);
|
|
2286
|
+
__runInitializers(_init, 1, VoiceLiveAgentConsoleService);
|
|
2287
|
+
__decoratorMetadata(_init, VoiceLiveAgentConsoleService);
|
|
2288
|
+
let _VoiceLiveAgentConsoleService = VoiceLiveAgentConsoleService;
|
|
2289
|
+
// src/angular/voice-live-call-viewer.service.ts
|
|
2290
|
+
import { computed as computed6, Injectable as Injectable6, signal as signal6 } from "@angular/core";
|
|
2291
|
+
var _dec = [
|
|
2292
|
+
Injectable6({ providedIn: "root" })
|
|
2293
|
+
];
|
|
2294
|
+
var _init = __decoratorStart(undefined);
|
|
2295
|
+
|
|
2296
|
+
class VoiceLiveCallViewerService {
|
|
2297
|
+
build(options) {
|
|
2298
|
+
const viewer = options.viewer ?? createLiveCallViewer(options);
|
|
2299
|
+
const stateSignal = signal6(viewer.getState());
|
|
2300
|
+
const unsubscribe = viewer.subscribe(() => {
|
|
2301
|
+
stateSignal.set(viewer.getState());
|
|
2302
|
+
});
|
|
2303
|
+
return {
|
|
2304
|
+
noteAgentAudio: (at) => viewer.noteAgentAudio(at),
|
|
2305
|
+
notePartial: (text, at) => viewer.notePartial(text, at),
|
|
2306
|
+
noteTranscript: (text, at) => viewer.noteTranscript(text, at),
|
|
2307
|
+
reset: (sessionId, startedAt) => viewer.reset(sessionId, startedAt),
|
|
2308
|
+
state: computed6(() => stateSignal()),
|
|
2309
|
+
stop: () => unsubscribe(),
|
|
2310
|
+
title: options.title ?? "Live call"
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
VoiceLiveCallViewerService = __decorateElement(_init, 0, "VoiceLiveCallViewerService", _dec, VoiceLiveCallViewerService);
|
|
2315
|
+
__runInitializers(_init, 1, VoiceLiveCallViewerService);
|
|
2316
|
+
__decoratorMetadata(_init, VoiceLiveCallViewerService);
|
|
2317
|
+
let _VoiceLiveCallViewerService = VoiceLiveCallViewerService;
|
|
2318
|
+
// src/angular/voice-replay-timeline.service.ts
|
|
2319
|
+
import { computed as computed7, Injectable as Injectable7, signal as signal7 } from "@angular/core";
|
|
2320
|
+
|
|
2321
|
+
// src/client/replayTimeline.ts
|
|
2322
|
+
var categorize = (entry) => {
|
|
2323
|
+
const event = entry.event.toLowerCase();
|
|
2324
|
+
if (event.startsWith("stt.") || event.includes("user"))
|
|
2325
|
+
return "user";
|
|
2326
|
+
if (event.startsWith("tts.") || event.includes("assistant") || event.includes("agent"))
|
|
2327
|
+
return "agent";
|
|
2328
|
+
if (event.startsWith("tool.") || event.includes("tool"))
|
|
2329
|
+
return "tool";
|
|
2330
|
+
return "lifecycle";
|
|
2331
|
+
};
|
|
2332
|
+
var buildReplayTimelineReport = (input) => {
|
|
2333
|
+
const events = [];
|
|
2334
|
+
let summaryAgentTurns = 0;
|
|
2335
|
+
let summaryUserTurns = 0;
|
|
2336
|
+
let summaryToolCalls = 0;
|
|
2337
|
+
for (const entry of input.artifact.timeline ?? []) {
|
|
2338
|
+
const category = categorize(entry);
|
|
2339
|
+
if (category === "user")
|
|
2340
|
+
summaryUserTurns += 1;
|
|
2341
|
+
if (category === "agent")
|
|
2342
|
+
summaryAgentTurns += 1;
|
|
2343
|
+
if (category === "tool")
|
|
2344
|
+
summaryToolCalls += 1;
|
|
2345
|
+
events.push({
|
|
2346
|
+
at: entry.atMs,
|
|
2347
|
+
category,
|
|
2348
|
+
detail: entry.text ?? entry.reason,
|
|
2349
|
+
durationMs: entry.chunkDurationMs,
|
|
2350
|
+
label: entry.event
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
events.sort((a, b) => a.at - b.at);
|
|
2354
|
+
const first = events[0]?.at ?? 0;
|
|
2355
|
+
const last = events.at(-1)?.at ?? first;
|
|
2356
|
+
return {
|
|
2357
|
+
duration: last - first,
|
|
2358
|
+
events,
|
|
2359
|
+
metadata: {
|
|
2360
|
+
artifactId: input.artifact.id ?? "",
|
|
2361
|
+
title: input.artifact.title
|
|
2362
|
+
},
|
|
2363
|
+
startedAt: first,
|
|
2364
|
+
summary: {
|
|
2365
|
+
agentTurns: summaryAgentTurns,
|
|
2366
|
+
toolCalls: summaryToolCalls,
|
|
2367
|
+
userTurns: summaryUserTurns
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
};
|
|
2371
|
+
|
|
2372
|
+
// src/angular/voice-replay-timeline.service.ts
|
|
2373
|
+
var _dec = [
|
|
2374
|
+
Injectable7({ providedIn: "root" })
|
|
2375
|
+
];
|
|
2376
|
+
var _init = __decoratorStart(undefined);
|
|
2377
|
+
|
|
2378
|
+
class VoiceReplayTimelineService {
|
|
2379
|
+
build(options) {
|
|
2380
|
+
const artifact = signal7(options.artifact);
|
|
2381
|
+
const report = computed7(() => buildReplayTimelineReport({ artifact: artifact() }));
|
|
2382
|
+
return {
|
|
2383
|
+
report,
|
|
2384
|
+
setArtifact: (next) => artifact.set(next),
|
|
2385
|
+
title: options.title
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
VoiceReplayTimelineService = __decorateElement(_init, 0, "VoiceReplayTimelineService", _dec, VoiceReplayTimelineService);
|
|
2390
|
+
__runInitializers(_init, 1, VoiceReplayTimelineService);
|
|
2391
|
+
__decoratorMetadata(_init, VoiceReplayTimelineService);
|
|
2392
|
+
let _VoiceReplayTimelineService = VoiceReplayTimelineService;
|
|
2393
|
+
// src/angular/voice-platform-coverage.service.ts
|
|
2394
|
+
import { computed as computed8, Injectable as Injectable8, signal as signal8 } from "@angular/core";
|
|
2395
|
+
|
|
2396
|
+
// src/client/platformCoverage.ts
|
|
2397
|
+
var fetchVoicePlatformCoverage = async (path = "/api/voice/platform-coverage", options = {}) => {
|
|
2398
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2399
|
+
const response = await fetchImpl(path);
|
|
2400
|
+
if (!response.ok) {
|
|
2401
|
+
throw new Error(`Voice platform coverage failed: HTTP ${response.status}`);
|
|
2402
|
+
}
|
|
2403
|
+
return await response.json();
|
|
2404
|
+
};
|
|
2405
|
+
var createVoicePlatformCoverageStore = (path = "/api/voice/platform-coverage", options = {}) => {
|
|
2406
|
+
const listeners = new Set;
|
|
2407
|
+
let closed = false;
|
|
2408
|
+
let timer;
|
|
2409
|
+
let snapshot = {
|
|
2410
|
+
error: null,
|
|
2411
|
+
isLoading: false
|
|
2412
|
+
};
|
|
2413
|
+
const emit = () => {
|
|
2414
|
+
for (const listener of listeners) {
|
|
2415
|
+
listener();
|
|
2416
|
+
}
|
|
2417
|
+
};
|
|
2418
|
+
const refresh = async () => {
|
|
2419
|
+
if (closed) {
|
|
2420
|
+
return snapshot.report;
|
|
2421
|
+
}
|
|
2422
|
+
snapshot = {
|
|
2423
|
+
...snapshot,
|
|
2424
|
+
error: null,
|
|
2425
|
+
isLoading: true
|
|
2426
|
+
};
|
|
2427
|
+
emit();
|
|
2428
|
+
try {
|
|
2429
|
+
const report = await fetchVoicePlatformCoverage(path, options);
|
|
2430
|
+
snapshot = {
|
|
2431
|
+
error: null,
|
|
2432
|
+
isLoading: false,
|
|
2433
|
+
report,
|
|
2434
|
+
updatedAt: Date.now()
|
|
2435
|
+
};
|
|
2436
|
+
emit();
|
|
2437
|
+
return report;
|
|
2438
|
+
} catch (error) {
|
|
2439
|
+
snapshot = {
|
|
2440
|
+
...snapshot,
|
|
2441
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2442
|
+
isLoading: false
|
|
2443
|
+
};
|
|
2444
|
+
emit();
|
|
2445
|
+
throw error;
|
|
2446
|
+
}
|
|
2447
|
+
};
|
|
2448
|
+
const close = () => {
|
|
2449
|
+
closed = true;
|
|
2450
|
+
if (timer) {
|
|
2451
|
+
clearInterval(timer);
|
|
2452
|
+
timer = undefined;
|
|
2453
|
+
}
|
|
2454
|
+
listeners.clear();
|
|
2455
|
+
};
|
|
2456
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
2457
|
+
timer = setInterval(() => {
|
|
2458
|
+
refresh().catch(() => {});
|
|
2459
|
+
}, options.intervalMs);
|
|
2460
|
+
}
|
|
2461
|
+
return {
|
|
2462
|
+
close,
|
|
2463
|
+
getServerSnapshot: () => snapshot,
|
|
2464
|
+
getSnapshot: () => snapshot,
|
|
2465
|
+
refresh,
|
|
2466
|
+
subscribe: (listener) => {
|
|
2467
|
+
listeners.add(listener);
|
|
2468
|
+
return () => {
|
|
2469
|
+
listeners.delete(listener);
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
};
|
|
2473
|
+
};
|
|
2474
|
+
|
|
2475
|
+
// src/angular/voice-platform-coverage.service.ts
|
|
2476
|
+
var _dec = [
|
|
2477
|
+
Injectable8({ providedIn: "root" })
|
|
2478
|
+
];
|
|
2479
|
+
var _init = __decoratorStart(undefined);
|
|
2480
|
+
|
|
2481
|
+
class VoicePlatformCoverageService {
|
|
2482
|
+
connect(path = "/api/voice/platform-coverage", options = {}) {
|
|
2483
|
+
const store = createVoicePlatformCoverageStore(path, options);
|
|
2484
|
+
const errorSignal = signal8(null);
|
|
2485
|
+
const isLoadingSignal = signal8(false);
|
|
2486
|
+
const reportSignal = signal8(undefined);
|
|
2487
|
+
const updatedAtSignal = signal8(undefined);
|
|
2488
|
+
const sync = () => {
|
|
2489
|
+
const snapshot = store.getSnapshot();
|
|
2490
|
+
errorSignal.set(snapshot.error);
|
|
2491
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
2492
|
+
reportSignal.set(snapshot.report);
|
|
2493
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
2494
|
+
};
|
|
2495
|
+
const unsubscribe = store.subscribe(sync);
|
|
2496
|
+
sync();
|
|
2497
|
+
if (typeof window !== "undefined") {
|
|
2498
|
+
store.refresh().catch(() => {});
|
|
2499
|
+
}
|
|
2500
|
+
return {
|
|
2501
|
+
close: () => {
|
|
2502
|
+
unsubscribe();
|
|
2503
|
+
store.close();
|
|
2504
|
+
},
|
|
2505
|
+
error: computed8(() => errorSignal()),
|
|
2506
|
+
isLoading: computed8(() => isLoadingSignal()),
|
|
2507
|
+
refresh: store.refresh,
|
|
2508
|
+
report: computed8(() => reportSignal()),
|
|
2509
|
+
updatedAt: computed8(() => updatedAtSignal())
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
VoicePlatformCoverageService = __decorateElement(_init, 0, "VoicePlatformCoverageService", _dec, VoicePlatformCoverageService);
|
|
2514
|
+
__runInitializers(_init, 1, VoicePlatformCoverageService);
|
|
2515
|
+
__decoratorMetadata(_init, VoicePlatformCoverageService);
|
|
2516
|
+
let _VoicePlatformCoverageService = VoicePlatformCoverageService;
|
|
2517
|
+
// src/angular/voice-proof-trends.service.ts
|
|
2518
|
+
import { computed as computed9, Injectable as Injectable9, signal as signal9 } from "@angular/core";
|
|
2519
|
+
|
|
2520
|
+
// src/client/proofTrends.ts
|
|
2521
|
+
var fetchVoiceProofTrends = async (path = "/api/voice/proof-trends", options = {}) => {
|
|
2522
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2523
|
+
const response = await fetchImpl(path);
|
|
2524
|
+
if (!response.ok) {
|
|
2525
|
+
throw new Error(`Voice proof trends failed: HTTP ${response.status}`);
|
|
2526
|
+
}
|
|
2527
|
+
return await response.json();
|
|
2528
|
+
};
|
|
2529
|
+
var createVoiceProofTrendsStore = (path = "/api/voice/proof-trends", options = {}) => {
|
|
2530
|
+
const listeners = new Set;
|
|
2531
|
+
let closed = false;
|
|
2532
|
+
let timer;
|
|
2533
|
+
let snapshot = {
|
|
2534
|
+
error: null,
|
|
2535
|
+
isLoading: false
|
|
2536
|
+
};
|
|
2537
|
+
const emit = () => {
|
|
2538
|
+
for (const listener of listeners) {
|
|
2539
|
+
listener();
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
const refresh = async () => {
|
|
2543
|
+
if (closed) {
|
|
2544
|
+
return snapshot.report;
|
|
2545
|
+
}
|
|
2546
|
+
snapshot = {
|
|
2547
|
+
...snapshot,
|
|
2548
|
+
error: null,
|
|
2549
|
+
isLoading: true
|
|
2550
|
+
};
|
|
2551
|
+
emit();
|
|
2552
|
+
try {
|
|
2553
|
+
const report = await fetchVoiceProofTrends(path, options);
|
|
2554
|
+
snapshot = {
|
|
2555
|
+
error: null,
|
|
2556
|
+
isLoading: false,
|
|
2557
|
+
report,
|
|
2558
|
+
updatedAt: Date.now()
|
|
2559
|
+
};
|
|
2560
|
+
emit();
|
|
2561
|
+
return report;
|
|
2562
|
+
} catch (error) {
|
|
2563
|
+
snapshot = {
|
|
2564
|
+
...snapshot,
|
|
2565
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2566
|
+
isLoading: false
|
|
2567
|
+
};
|
|
2568
|
+
emit();
|
|
2569
|
+
throw error;
|
|
2570
|
+
}
|
|
2571
|
+
};
|
|
2572
|
+
const close = () => {
|
|
2573
|
+
closed = true;
|
|
2574
|
+
if (timer) {
|
|
2575
|
+
clearInterval(timer);
|
|
2576
|
+
timer = undefined;
|
|
2577
|
+
}
|
|
2578
|
+
listeners.clear();
|
|
2579
|
+
};
|
|
2580
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
2581
|
+
timer = setInterval(() => {
|
|
2582
|
+
refresh().catch(() => {});
|
|
2583
|
+
}, options.intervalMs);
|
|
2584
|
+
}
|
|
2585
|
+
return {
|
|
2586
|
+
close,
|
|
2587
|
+
getServerSnapshot: () => snapshot,
|
|
2588
|
+
getSnapshot: () => snapshot,
|
|
2589
|
+
refresh,
|
|
2590
|
+
subscribe: (listener) => {
|
|
2591
|
+
listeners.add(listener);
|
|
2592
|
+
return () => {
|
|
2593
|
+
listeners.delete(listener);
|
|
2594
|
+
};
|
|
2595
|
+
}
|
|
2596
|
+
};
|
|
2597
|
+
};
|
|
2598
|
+
|
|
2599
|
+
// src/angular/voice-proof-trends.service.ts
|
|
2600
|
+
var _dec = [
|
|
2601
|
+
Injectable9({ providedIn: "root" })
|
|
2602
|
+
];
|
|
2603
|
+
var _init = __decoratorStart(undefined);
|
|
2604
|
+
|
|
2605
|
+
class VoiceProofTrendsService {
|
|
2606
|
+
connect(path = "/api/voice/proof-trends", options = {}) {
|
|
2607
|
+
const store = createVoiceProofTrendsStore(path, options);
|
|
2608
|
+
const errorSignal = signal9(null);
|
|
2609
|
+
const isLoadingSignal = signal9(false);
|
|
2610
|
+
const reportSignal = signal9(undefined);
|
|
2611
|
+
const updatedAtSignal = signal9(undefined);
|
|
2612
|
+
const sync = () => {
|
|
2613
|
+
const snapshot = store.getSnapshot();
|
|
2614
|
+
errorSignal.set(snapshot.error);
|
|
2615
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
2616
|
+
reportSignal.set(snapshot.report);
|
|
2617
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
2618
|
+
};
|
|
2619
|
+
const unsubscribe = store.subscribe(sync);
|
|
2620
|
+
sync();
|
|
2621
|
+
if (typeof window !== "undefined") {
|
|
2622
|
+
store.refresh().catch(() => {});
|
|
2623
|
+
}
|
|
2624
|
+
return {
|
|
2625
|
+
close: () => {
|
|
2626
|
+
unsubscribe();
|
|
2627
|
+
store.close();
|
|
2628
|
+
},
|
|
2629
|
+
error: computed9(() => errorSignal()),
|
|
2630
|
+
isLoading: computed9(() => isLoadingSignal()),
|
|
2631
|
+
refresh: store.refresh,
|
|
2632
|
+
report: computed9(() => reportSignal()),
|
|
2633
|
+
updatedAt: computed9(() => updatedAtSignal())
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
VoiceProofTrendsService = __decorateElement(_init, 0, "VoiceProofTrendsService", _dec, VoiceProofTrendsService);
|
|
2638
|
+
__runInitializers(_init, 1, VoiceProofTrendsService);
|
|
2639
|
+
__decoratorMetadata(_init, VoiceProofTrendsService);
|
|
2640
|
+
let _VoiceProofTrendsService = VoiceProofTrendsService;
|
|
2641
|
+
// src/angular/voice-reconnect-profile-evidence.service.ts
|
|
2642
|
+
import { computed as computed10, Injectable as Injectable10, signal as signal10 } from "@angular/core";
|
|
2643
|
+
|
|
2644
|
+
// src/client/reconnectProfileEvidence.ts
|
|
2645
|
+
var fetchVoiceReconnectProfileEvidence = async (path = "/api/voice/reconnect-profile-evidence", options = {}) => {
|
|
2646
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2647
|
+
const response = await fetchImpl(path);
|
|
2648
|
+
if (!response.ok) {
|
|
2649
|
+
throw new Error(`Voice reconnect profile evidence failed: HTTP ${response.status}`);
|
|
2650
|
+
}
|
|
2651
|
+
return await response.json();
|
|
2652
|
+
};
|
|
2653
|
+
var createVoiceReconnectProfileEvidenceStore = (path = "/api/voice/reconnect-profile-evidence", options = {}) => {
|
|
2654
|
+
const listeners = new Set;
|
|
2655
|
+
let closed = false;
|
|
2656
|
+
let timer;
|
|
2657
|
+
let snapshot = {
|
|
2658
|
+
error: null,
|
|
2659
|
+
isLoading: false
|
|
2660
|
+
};
|
|
2661
|
+
const emit = () => {
|
|
2662
|
+
for (const listener of listeners) {
|
|
2663
|
+
listener();
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
const refresh = async () => {
|
|
2667
|
+
if (closed) {
|
|
2668
|
+
return snapshot.report;
|
|
2669
|
+
}
|
|
2670
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
2671
|
+
emit();
|
|
2672
|
+
try {
|
|
2673
|
+
const report = await fetchVoiceReconnectProfileEvidence(path, options);
|
|
2674
|
+
snapshot = {
|
|
2675
|
+
error: null,
|
|
2676
|
+
isLoading: false,
|
|
2677
|
+
report,
|
|
2678
|
+
updatedAt: Date.now()
|
|
2679
|
+
};
|
|
2680
|
+
emit();
|
|
2681
|
+
return report;
|
|
2682
|
+
} catch (error) {
|
|
2683
|
+
snapshot = {
|
|
2684
|
+
...snapshot,
|
|
2685
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2686
|
+
isLoading: false
|
|
2687
|
+
};
|
|
2688
|
+
emit();
|
|
2689
|
+
throw error;
|
|
2690
|
+
}
|
|
2691
|
+
};
|
|
2692
|
+
const close = () => {
|
|
2693
|
+
closed = true;
|
|
2694
|
+
if (timer) {
|
|
2695
|
+
clearInterval(timer);
|
|
2696
|
+
timer = undefined;
|
|
2697
|
+
}
|
|
2698
|
+
listeners.clear();
|
|
2699
|
+
};
|
|
2700
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
2701
|
+
timer = setInterval(() => {
|
|
2702
|
+
refresh().catch(() => {});
|
|
2703
|
+
}, options.intervalMs);
|
|
2704
|
+
}
|
|
2705
|
+
return {
|
|
2706
|
+
close,
|
|
2707
|
+
getServerSnapshot: () => snapshot,
|
|
2708
|
+
getSnapshot: () => snapshot,
|
|
2709
|
+
refresh,
|
|
2710
|
+
subscribe: (listener) => {
|
|
2711
|
+
listeners.add(listener);
|
|
2712
|
+
return () => {
|
|
2713
|
+
listeners.delete(listener);
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
};
|
|
2717
|
+
};
|
|
2718
|
+
|
|
2719
|
+
// src/angular/voice-reconnect-profile-evidence.service.ts
|
|
2720
|
+
var _dec = [
|
|
2721
|
+
Injectable10({ providedIn: "root" })
|
|
2722
|
+
];
|
|
2723
|
+
var _init = __decoratorStart(undefined);
|
|
2724
|
+
|
|
2725
|
+
class VoiceReconnectProfileEvidenceService {
|
|
2726
|
+
connect(path = "/api/voice/reconnect-profile-evidence", options = {}) {
|
|
2727
|
+
const store = createVoiceReconnectProfileEvidenceStore(path, options);
|
|
2728
|
+
const errorSignal = signal10(null);
|
|
2729
|
+
const isLoadingSignal = signal10(false);
|
|
2730
|
+
const reportSignal = signal10(undefined);
|
|
2731
|
+
const updatedAtSignal = signal10(undefined);
|
|
2732
|
+
const sync = () => {
|
|
2733
|
+
const snapshot = store.getSnapshot();
|
|
2734
|
+
errorSignal.set(snapshot.error);
|
|
2735
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
2736
|
+
reportSignal.set(snapshot.report);
|
|
2737
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
2738
|
+
};
|
|
2739
|
+
const unsubscribe = store.subscribe(sync);
|
|
2740
|
+
sync();
|
|
2741
|
+
if (typeof window !== "undefined") {
|
|
2742
|
+
store.refresh().catch(() => {});
|
|
2743
|
+
}
|
|
2744
|
+
return {
|
|
2745
|
+
close: () => {
|
|
2746
|
+
unsubscribe();
|
|
2747
|
+
store.close();
|
|
2748
|
+
},
|
|
2749
|
+
error: computed10(() => errorSignal()),
|
|
2750
|
+
isLoading: computed10(() => isLoadingSignal()),
|
|
2751
|
+
refresh: store.refresh,
|
|
2752
|
+
report: computed10(() => reportSignal()),
|
|
2753
|
+
updatedAt: computed10(() => updatedAtSignal())
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
VoiceReconnectProfileEvidenceService = __decorateElement(_init, 0, "VoiceReconnectProfileEvidenceService", _dec, VoiceReconnectProfileEvidenceService);
|
|
2758
|
+
__runInitializers(_init, 1, VoiceReconnectProfileEvidenceService);
|
|
2759
|
+
__decoratorMetadata(_init, VoiceReconnectProfileEvidenceService);
|
|
2760
|
+
let _VoiceReconnectProfileEvidenceService = VoiceReconnectProfileEvidenceService;
|
|
2761
|
+
// src/angular/voice-call-debugger.service.ts
|
|
2762
|
+
import { computed as computed11, Injectable as Injectable11, signal as signal11 } from "@angular/core";
|
|
2763
|
+
|
|
2764
|
+
// src/client/callDebugger.ts
|
|
2765
|
+
var fetchVoiceCallDebugger = async (path, options = {}) => {
|
|
2766
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2767
|
+
const response = await fetchImpl(path);
|
|
2768
|
+
if (!response.ok) {
|
|
2769
|
+
throw new Error(`Voice call debugger failed: HTTP ${response.status}`);
|
|
2770
|
+
}
|
|
2771
|
+
return await response.json();
|
|
2772
|
+
};
|
|
2773
|
+
var createVoiceCallDebuggerStore = (path, options = {}) => {
|
|
2774
|
+
const listeners = new Set;
|
|
2775
|
+
let closed = false;
|
|
2776
|
+
let timer;
|
|
2777
|
+
let snapshot = {
|
|
2778
|
+
error: null,
|
|
2779
|
+
isLoading: false
|
|
2780
|
+
};
|
|
2781
|
+
const emit = () => {
|
|
2782
|
+
for (const listener of listeners) {
|
|
2783
|
+
listener();
|
|
2784
|
+
}
|
|
2785
|
+
};
|
|
2786
|
+
const refresh = async () => {
|
|
2787
|
+
if (closed) {
|
|
2788
|
+
return snapshot.report;
|
|
2789
|
+
}
|
|
2790
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
2791
|
+
emit();
|
|
2792
|
+
try {
|
|
2793
|
+
const report = await fetchVoiceCallDebugger(path, options);
|
|
2794
|
+
snapshot = {
|
|
2795
|
+
error: null,
|
|
2796
|
+
isLoading: false,
|
|
2797
|
+
report,
|
|
2798
|
+
updatedAt: Date.now()
|
|
2799
|
+
};
|
|
2800
|
+
emit();
|
|
2801
|
+
return report;
|
|
2802
|
+
} catch (error) {
|
|
2803
|
+
snapshot = {
|
|
2804
|
+
...snapshot,
|
|
2805
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2806
|
+
isLoading: false
|
|
2807
|
+
};
|
|
2808
|
+
emit();
|
|
2809
|
+
throw error;
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
const close = () => {
|
|
2813
|
+
closed = true;
|
|
2814
|
+
if (timer) {
|
|
2815
|
+
clearInterval(timer);
|
|
2816
|
+
timer = undefined;
|
|
2817
|
+
}
|
|
2818
|
+
listeners.clear();
|
|
2819
|
+
};
|
|
2820
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
2821
|
+
timer = setInterval(() => {
|
|
2822
|
+
refresh().catch(() => {});
|
|
2823
|
+
}, options.intervalMs);
|
|
2824
|
+
}
|
|
2825
|
+
return {
|
|
2826
|
+
close,
|
|
2827
|
+
getServerSnapshot: () => snapshot,
|
|
2828
|
+
getSnapshot: () => snapshot,
|
|
2829
|
+
refresh,
|
|
2830
|
+
subscribe: (listener) => {
|
|
2831
|
+
listeners.add(listener);
|
|
2832
|
+
return () => {
|
|
2833
|
+
listeners.delete(listener);
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2837
|
+
};
|
|
2838
|
+
|
|
2839
|
+
// src/angular/voice-call-debugger.service.ts
|
|
2840
|
+
var _dec = [
|
|
2841
|
+
Injectable11({ providedIn: "root" })
|
|
2842
|
+
];
|
|
2843
|
+
var _init = __decoratorStart(undefined);
|
|
2844
|
+
|
|
2845
|
+
class VoiceCallDebuggerService {
|
|
2846
|
+
connect(path, options = {}) {
|
|
2847
|
+
const store = createVoiceCallDebuggerStore(path, options);
|
|
2848
|
+
const errorSignal = signal11(null);
|
|
2849
|
+
const isLoadingSignal = signal11(false);
|
|
2850
|
+
const reportSignal = signal11(undefined);
|
|
2851
|
+
const updatedAtSignal = signal11(undefined);
|
|
2852
|
+
const sync = () => {
|
|
2853
|
+
const state = store.getSnapshot();
|
|
2854
|
+
errorSignal.set(state.error);
|
|
2855
|
+
isLoadingSignal.set(state.isLoading);
|
|
2856
|
+
reportSignal.set(state.report);
|
|
2857
|
+
updatedAtSignal.set(state.updatedAt);
|
|
2858
|
+
};
|
|
2859
|
+
const unsubscribe = store.subscribe(sync);
|
|
2860
|
+
sync();
|
|
2861
|
+
store.refresh().catch(() => {});
|
|
2862
|
+
return {
|
|
2863
|
+
close: () => {
|
|
2864
|
+
unsubscribe();
|
|
2865
|
+
store.close();
|
|
2866
|
+
},
|
|
2867
|
+
error: computed11(() => errorSignal()),
|
|
2868
|
+
isLoading: computed11(() => isLoadingSignal()),
|
|
2869
|
+
refresh: store.refresh,
|
|
2870
|
+
report: computed11(() => reportSignal()),
|
|
2871
|
+
updatedAt: computed11(() => updatedAtSignal())
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
VoiceCallDebuggerService = __decorateElement(_init, 0, "VoiceCallDebuggerService", _dec, VoiceCallDebuggerService);
|
|
2876
|
+
__runInitializers(_init, 1, VoiceCallDebuggerService);
|
|
2877
|
+
__decoratorMetadata(_init, VoiceCallDebuggerService);
|
|
2878
|
+
let _VoiceCallDebuggerService = VoiceCallDebuggerService;
|
|
2879
|
+
// src/angular/voice-session-snapshot.service.ts
|
|
2880
|
+
import { computed as computed12, Injectable as Injectable12, signal as signal12 } from "@angular/core";
|
|
2881
|
+
|
|
2882
|
+
// src/client/sessionSnapshot.ts
|
|
2883
|
+
var withTurnId = (path, turnId) => {
|
|
2884
|
+
if (!turnId) {
|
|
2885
|
+
return path;
|
|
2886
|
+
}
|
|
2887
|
+
const url = new URL(path, "http://absolutejs.local");
|
|
2888
|
+
url.searchParams.set("turnId", turnId);
|
|
2889
|
+
return `${url.pathname}${url.search}`;
|
|
2890
|
+
};
|
|
2891
|
+
var fetchVoiceSessionSnapshot = async (path, options = {}) => {
|
|
2892
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2893
|
+
const response = await fetchImpl(withTurnId(path, options.turnId));
|
|
2894
|
+
if (!response.ok) {
|
|
2895
|
+
throw new Error(`Voice session snapshot failed: HTTP ${response.status}`);
|
|
2896
|
+
}
|
|
2897
|
+
return await response.json();
|
|
2898
|
+
};
|
|
2899
|
+
var createVoiceSessionSnapshotStore = (path, options = {}) => {
|
|
2900
|
+
const listeners = new Set;
|
|
2901
|
+
let closed = false;
|
|
2902
|
+
let timer;
|
|
2903
|
+
let snapshot = {
|
|
2904
|
+
error: null,
|
|
2905
|
+
isLoading: false
|
|
2906
|
+
};
|
|
2907
|
+
const emit = () => {
|
|
2908
|
+
for (const listener of listeners) {
|
|
2909
|
+
listener();
|
|
2910
|
+
}
|
|
2911
|
+
};
|
|
2912
|
+
const refresh = async () => {
|
|
2913
|
+
if (closed) {
|
|
2914
|
+
return snapshot.snapshot;
|
|
2915
|
+
}
|
|
2916
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
2917
|
+
emit();
|
|
2918
|
+
try {
|
|
2919
|
+
const next = await fetchVoiceSessionSnapshot(path, options);
|
|
2920
|
+
snapshot = {
|
|
2921
|
+
error: null,
|
|
2922
|
+
isLoading: false,
|
|
2923
|
+
snapshot: next,
|
|
2924
|
+
updatedAt: Date.now()
|
|
2925
|
+
};
|
|
2926
|
+
emit();
|
|
2927
|
+
return next;
|
|
2928
|
+
} catch (error) {
|
|
2929
|
+
snapshot = {
|
|
2930
|
+
...snapshot,
|
|
2931
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2932
|
+
isLoading: false
|
|
2933
|
+
};
|
|
2934
|
+
emit();
|
|
2935
|
+
throw error;
|
|
2936
|
+
}
|
|
2937
|
+
};
|
|
2938
|
+
const download = () => {
|
|
2939
|
+
const current = snapshot.snapshot;
|
|
2940
|
+
if (current === undefined) {
|
|
2941
|
+
throw new Error("Voice session snapshot has not been loaded.");
|
|
2942
|
+
}
|
|
2943
|
+
return new Blob([JSON.stringify(current, null, 2)], {
|
|
2944
|
+
type: "application/json"
|
|
2945
|
+
});
|
|
2946
|
+
};
|
|
2947
|
+
const close = () => {
|
|
2948
|
+
closed = true;
|
|
2949
|
+
if (timer) {
|
|
2950
|
+
clearInterval(timer);
|
|
2951
|
+
timer = undefined;
|
|
2952
|
+
}
|
|
2953
|
+
listeners.clear();
|
|
2954
|
+
};
|
|
2955
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
2956
|
+
timer = setInterval(() => {
|
|
2957
|
+
refresh().catch(() => {});
|
|
2958
|
+
}, options.intervalMs);
|
|
2959
|
+
}
|
|
2960
|
+
return {
|
|
2961
|
+
close,
|
|
2962
|
+
download,
|
|
2963
|
+
getServerSnapshot: () => snapshot,
|
|
2964
|
+
getSnapshot: () => snapshot,
|
|
2965
|
+
refresh,
|
|
2966
|
+
subscribe: (listener) => {
|
|
2967
|
+
listeners.add(listener);
|
|
2968
|
+
return () => {
|
|
2969
|
+
listeners.delete(listener);
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
};
|
|
2973
|
+
};
|
|
2974
|
+
|
|
2975
|
+
// src/angular/voice-session-snapshot.service.ts
|
|
2976
|
+
var _dec = [
|
|
2977
|
+
Injectable12({ providedIn: "root" })
|
|
2978
|
+
];
|
|
2979
|
+
var _init = __decoratorStart(undefined);
|
|
2980
|
+
|
|
2981
|
+
class VoiceSessionSnapshotService {
|
|
2982
|
+
connect(path, options = {}) {
|
|
2983
|
+
const store = createVoiceSessionSnapshotStore(path, options);
|
|
2984
|
+
const errorSignal = signal12(null);
|
|
2985
|
+
const isLoadingSignal = signal12(false);
|
|
2986
|
+
const snapshotSignal = signal12(undefined);
|
|
2987
|
+
const updatedAtSignal = signal12(undefined);
|
|
2988
|
+
const sync = () => {
|
|
2989
|
+
const state = store.getSnapshot();
|
|
2990
|
+
errorSignal.set(state.error);
|
|
2991
|
+
isLoadingSignal.set(state.isLoading);
|
|
2992
|
+
snapshotSignal.set(state.snapshot);
|
|
2993
|
+
updatedAtSignal.set(state.updatedAt);
|
|
2994
|
+
};
|
|
2995
|
+
const unsubscribe = store.subscribe(sync);
|
|
2996
|
+
sync();
|
|
2997
|
+
store.refresh().catch(() => {});
|
|
2998
|
+
return {
|
|
2999
|
+
close: () => {
|
|
3000
|
+
unsubscribe();
|
|
3001
|
+
store.close();
|
|
3002
|
+
},
|
|
3003
|
+
download: store.download,
|
|
3004
|
+
error: computed12(() => errorSignal()),
|
|
3005
|
+
isLoading: computed12(() => isLoadingSignal()),
|
|
3006
|
+
refresh: store.refresh,
|
|
3007
|
+
snapshot: computed12(() => snapshotSignal()),
|
|
3008
|
+
updatedAt: computed12(() => updatedAtSignal())
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
VoiceSessionSnapshotService = __decorateElement(_init, 0, "VoiceSessionSnapshotService", _dec, VoiceSessionSnapshotService);
|
|
3013
|
+
__runInitializers(_init, 1, VoiceSessionSnapshotService);
|
|
3014
|
+
__decoratorMetadata(_init, VoiceSessionSnapshotService);
|
|
3015
|
+
let _VoiceSessionSnapshotService = VoiceSessionSnapshotService;
|
|
3016
|
+
// src/angular/voice-session-observability.service.ts
|
|
3017
|
+
import { computed as computed13, Injectable as Injectable13, signal as signal13 } from "@angular/core";
|
|
3018
|
+
|
|
3019
|
+
// src/client/sessionObservability.ts
|
|
3020
|
+
var fetchVoiceSessionObservability = async (path, options = {}) => {
|
|
3021
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3022
|
+
const response = await fetchImpl(path);
|
|
3023
|
+
if (!response.ok) {
|
|
3024
|
+
throw new Error(`Voice session observability failed: HTTP ${response.status}`);
|
|
3025
|
+
}
|
|
3026
|
+
return await response.json();
|
|
3027
|
+
};
|
|
3028
|
+
var createVoiceSessionObservabilityStore = (path, options = {}) => {
|
|
3029
|
+
const listeners = new Set;
|
|
3030
|
+
let closed = false;
|
|
3031
|
+
let timer;
|
|
3032
|
+
let snapshot = {
|
|
3033
|
+
error: null,
|
|
3034
|
+
isLoading: false,
|
|
3035
|
+
report: null
|
|
3036
|
+
};
|
|
3037
|
+
const emit = () => {
|
|
3038
|
+
for (const listener of listeners) {
|
|
3039
|
+
listener();
|
|
3040
|
+
}
|
|
3041
|
+
};
|
|
3042
|
+
const refresh = async () => {
|
|
3043
|
+
if (closed) {
|
|
3044
|
+
return snapshot.report;
|
|
3045
|
+
}
|
|
3046
|
+
snapshot = {
|
|
3047
|
+
...snapshot,
|
|
3048
|
+
error: null,
|
|
3049
|
+
isLoading: true
|
|
3050
|
+
};
|
|
3051
|
+
emit();
|
|
3052
|
+
try {
|
|
3053
|
+
const report = await fetchVoiceSessionObservability(path, options);
|
|
3054
|
+
snapshot = {
|
|
3055
|
+
error: null,
|
|
3056
|
+
isLoading: false,
|
|
3057
|
+
report,
|
|
3058
|
+
updatedAt: Date.now()
|
|
3059
|
+
};
|
|
3060
|
+
emit();
|
|
3061
|
+
return report;
|
|
3062
|
+
} catch (error) {
|
|
3063
|
+
snapshot = {
|
|
3064
|
+
...snapshot,
|
|
3065
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3066
|
+
isLoading: false
|
|
3067
|
+
};
|
|
3068
|
+
emit();
|
|
3069
|
+
throw error;
|
|
3070
|
+
}
|
|
3071
|
+
};
|
|
3072
|
+
const close = () => {
|
|
3073
|
+
closed = true;
|
|
3074
|
+
if (timer) {
|
|
3075
|
+
clearInterval(timer);
|
|
3076
|
+
timer = undefined;
|
|
3077
|
+
}
|
|
3078
|
+
listeners.clear();
|
|
3079
|
+
};
|
|
3080
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3081
|
+
timer = setInterval(() => {
|
|
3082
|
+
refresh().catch(() => {});
|
|
3083
|
+
}, options.intervalMs);
|
|
3084
|
+
}
|
|
3085
|
+
return {
|
|
3086
|
+
close,
|
|
3087
|
+
getServerSnapshot: () => snapshot,
|
|
3088
|
+
getSnapshot: () => snapshot,
|
|
3089
|
+
refresh,
|
|
3090
|
+
subscribe: (listener) => {
|
|
3091
|
+
listeners.add(listener);
|
|
3092
|
+
return () => {
|
|
3093
|
+
listeners.delete(listener);
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
3096
|
+
};
|
|
3097
|
+
};
|
|
3098
|
+
|
|
3099
|
+
// src/angular/voice-session-observability.service.ts
|
|
3100
|
+
var _dec = [
|
|
3101
|
+
Injectable13({ providedIn: "root" })
|
|
3102
|
+
];
|
|
3103
|
+
var _init = __decoratorStart(undefined);
|
|
3104
|
+
|
|
3105
|
+
class VoiceSessionObservabilityService {
|
|
3106
|
+
connect(path = "/api/voice/session-observability/latest", options = {}) {
|
|
3107
|
+
const store = createVoiceSessionObservabilityStore(path, options);
|
|
3108
|
+
const errorSignal = signal13(null);
|
|
3109
|
+
const isLoadingSignal = signal13(false);
|
|
3110
|
+
const reportSignal = signal13(null);
|
|
3111
|
+
const updatedAtSignal = signal13(undefined);
|
|
3112
|
+
const sync = () => {
|
|
3113
|
+
const snapshot = store.getSnapshot();
|
|
3114
|
+
errorSignal.set(snapshot.error);
|
|
3115
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3116
|
+
reportSignal.set(snapshot.report);
|
|
3117
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3118
|
+
};
|
|
3119
|
+
const unsubscribe = store.subscribe(sync);
|
|
3120
|
+
sync();
|
|
3121
|
+
store.refresh().catch(() => {});
|
|
3122
|
+
return {
|
|
3123
|
+
close: () => {
|
|
3124
|
+
unsubscribe();
|
|
3125
|
+
store.close();
|
|
3126
|
+
},
|
|
3127
|
+
error: computed13(() => errorSignal()),
|
|
3128
|
+
isLoading: computed13(() => isLoadingSignal()),
|
|
3129
|
+
refresh: store.refresh,
|
|
3130
|
+
report: computed13(() => reportSignal()),
|
|
3131
|
+
updatedAt: computed13(() => updatedAtSignal())
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
VoiceSessionObservabilityService = __decorateElement(_init, 0, "VoiceSessionObservabilityService", _dec, VoiceSessionObservabilityService);
|
|
3136
|
+
__runInitializers(_init, 1, VoiceSessionObservabilityService);
|
|
3137
|
+
__decoratorMetadata(_init, VoiceSessionObservabilityService);
|
|
3138
|
+
let _VoiceSessionObservabilityService = VoiceSessionObservabilityService;
|
|
3139
|
+
// src/angular/voice-profile-comparison.service.ts
|
|
3140
|
+
import { computed as computed14, Injectable as Injectable14, signal as signal14 } from "@angular/core";
|
|
3141
|
+
|
|
3142
|
+
// src/client/profileComparison.ts
|
|
3143
|
+
var fetchVoiceProfileComparison = async (path = "/api/voice/real-call-profile-history", options = {}) => {
|
|
3144
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3145
|
+
const response = await fetchImpl(path);
|
|
3146
|
+
if (!response.ok) {
|
|
3147
|
+
throw new Error(`Voice profile comparison failed: HTTP ${response.status}`);
|
|
3148
|
+
}
|
|
3149
|
+
return await response.json();
|
|
3150
|
+
};
|
|
3151
|
+
var createVoiceProfileComparisonStore = (path = "/api/voice/real-call-profile-history", options = {}) => {
|
|
3152
|
+
const listeners = new Set;
|
|
3153
|
+
let closed = false;
|
|
3154
|
+
let timer;
|
|
3155
|
+
let snapshot = {
|
|
3156
|
+
error: null,
|
|
3157
|
+
isLoading: false
|
|
3158
|
+
};
|
|
3159
|
+
const emit = () => {
|
|
3160
|
+
for (const listener of listeners) {
|
|
3161
|
+
listener();
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
3164
|
+
const refresh = async () => {
|
|
3165
|
+
if (closed) {
|
|
3166
|
+
return snapshot.report;
|
|
3167
|
+
}
|
|
3168
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
3169
|
+
emit();
|
|
3170
|
+
try {
|
|
3171
|
+
const report = await fetchVoiceProfileComparison(path, options);
|
|
3172
|
+
snapshot = {
|
|
3173
|
+
error: null,
|
|
3174
|
+
isLoading: false,
|
|
3175
|
+
report,
|
|
3176
|
+
updatedAt: Date.now()
|
|
3177
|
+
};
|
|
3178
|
+
emit();
|
|
3179
|
+
return report;
|
|
3180
|
+
} catch (error) {
|
|
3181
|
+
snapshot = {
|
|
3182
|
+
...snapshot,
|
|
3183
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3184
|
+
isLoading: false
|
|
3185
|
+
};
|
|
3186
|
+
emit();
|
|
3187
|
+
throw error;
|
|
3188
|
+
}
|
|
3189
|
+
};
|
|
3190
|
+
const close = () => {
|
|
3191
|
+
closed = true;
|
|
3192
|
+
if (timer) {
|
|
3193
|
+
clearInterval(timer);
|
|
3194
|
+
timer = undefined;
|
|
3195
|
+
}
|
|
3196
|
+
listeners.clear();
|
|
3197
|
+
};
|
|
3198
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
3199
|
+
timer = setInterval(() => {
|
|
3200
|
+
refresh().catch(() => {});
|
|
3201
|
+
}, options.intervalMs);
|
|
3202
|
+
}
|
|
3203
|
+
return {
|
|
3204
|
+
close,
|
|
3205
|
+
getServerSnapshot: () => snapshot,
|
|
3206
|
+
getSnapshot: () => snapshot,
|
|
3207
|
+
refresh,
|
|
3208
|
+
subscribe: (listener) => {
|
|
3209
|
+
listeners.add(listener);
|
|
3210
|
+
return () => {
|
|
3211
|
+
listeners.delete(listener);
|
|
3212
|
+
};
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
};
|
|
3216
|
+
|
|
3217
|
+
// src/angular/voice-profile-comparison.service.ts
|
|
3218
|
+
var _dec = [
|
|
3219
|
+
Injectable14({ providedIn: "root" })
|
|
3220
|
+
];
|
|
3221
|
+
var _init = __decoratorStart(undefined);
|
|
3222
|
+
|
|
3223
|
+
class VoiceProfileComparisonService {
|
|
3224
|
+
connect(path = "/api/voice/real-call-profile-history", options = {}) {
|
|
3225
|
+
const store = createVoiceProfileComparisonStore(path, options);
|
|
3226
|
+
const errorSignal = signal14(null);
|
|
3227
|
+
const isLoadingSignal = signal14(false);
|
|
3228
|
+
const reportSignal = signal14(undefined);
|
|
3229
|
+
const updatedAtSignal = signal14(undefined);
|
|
3230
|
+
const sync = () => {
|
|
3231
|
+
const snapshot = store.getSnapshot();
|
|
3232
|
+
errorSignal.set(snapshot.error);
|
|
3233
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3234
|
+
reportSignal.set(snapshot.report);
|
|
3235
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3236
|
+
};
|
|
3237
|
+
const unsubscribe = store.subscribe(sync);
|
|
3238
|
+
sync();
|
|
3239
|
+
if (typeof window !== "undefined") {
|
|
3240
|
+
store.refresh().catch(() => {});
|
|
3241
|
+
}
|
|
3242
|
+
return {
|
|
3243
|
+
close: () => {
|
|
3244
|
+
unsubscribe();
|
|
3245
|
+
store.close();
|
|
3246
|
+
},
|
|
3247
|
+
error: computed14(() => errorSignal()),
|
|
3248
|
+
isLoading: computed14(() => isLoadingSignal()),
|
|
3249
|
+
refresh: store.refresh,
|
|
3250
|
+
report: computed14(() => reportSignal()),
|
|
3251
|
+
updatedAt: computed14(() => updatedAtSignal())
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
VoiceProfileComparisonService = __decorateElement(_init, 0, "VoiceProfileComparisonService", _dec, VoiceProfileComparisonService);
|
|
3256
|
+
__runInitializers(_init, 1, VoiceProfileComparisonService);
|
|
3257
|
+
__decoratorMetadata(_init, VoiceProfileComparisonService);
|
|
3258
|
+
let _VoiceProfileComparisonService = VoiceProfileComparisonService;
|
|
3259
|
+
// src/angular/voice-readiness-failures.service.ts
|
|
3260
|
+
import { computed as computed15, Injectable as Injectable15, signal as signal15 } from "@angular/core";
|
|
3261
|
+
|
|
3262
|
+
// src/client/readinessFailures.ts
|
|
3263
|
+
var fetchVoiceReadinessFailures = async (path = "/api/production-readiness", options = {}) => {
|
|
3264
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3265
|
+
const response = await fetchImpl(path);
|
|
3266
|
+
if (!response.ok) {
|
|
3267
|
+
throw new Error(`Voice readiness failed: HTTP ${response.status}`);
|
|
3268
|
+
}
|
|
3269
|
+
return await response.json();
|
|
3270
|
+
};
|
|
3271
|
+
var createVoiceReadinessFailuresStore = (path = "/api/production-readiness", options = {}) => {
|
|
3272
|
+
const listeners = new Set;
|
|
3273
|
+
let closed = false;
|
|
3274
|
+
let timer;
|
|
3275
|
+
let snapshot = {
|
|
3276
|
+
error: null,
|
|
3277
|
+
isLoading: false
|
|
3278
|
+
};
|
|
3279
|
+
const emit = () => {
|
|
3280
|
+
for (const listener of listeners) {
|
|
3281
|
+
listener();
|
|
3282
|
+
}
|
|
3283
|
+
};
|
|
3284
|
+
const refresh = async () => {
|
|
3285
|
+
if (closed) {
|
|
3286
|
+
return snapshot.report;
|
|
3287
|
+
}
|
|
3288
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
3289
|
+
emit();
|
|
3290
|
+
try {
|
|
3291
|
+
const report = await fetchVoiceReadinessFailures(path, options);
|
|
3292
|
+
snapshot = {
|
|
3293
|
+
error: null,
|
|
3294
|
+
isLoading: false,
|
|
3295
|
+
report,
|
|
3296
|
+
updatedAt: Date.now()
|
|
3297
|
+
};
|
|
3298
|
+
emit();
|
|
3299
|
+
return report;
|
|
3300
|
+
} catch (error) {
|
|
3301
|
+
snapshot = {
|
|
3302
|
+
...snapshot,
|
|
3303
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3304
|
+
isLoading: false
|
|
3305
|
+
};
|
|
3306
|
+
emit();
|
|
3307
|
+
throw error;
|
|
3308
|
+
}
|
|
3309
|
+
};
|
|
3310
|
+
const close = () => {
|
|
3311
|
+
closed = true;
|
|
3312
|
+
if (timer) {
|
|
3313
|
+
clearInterval(timer);
|
|
3314
|
+
timer = undefined;
|
|
3315
|
+
}
|
|
3316
|
+
listeners.clear();
|
|
3317
|
+
};
|
|
3318
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
3319
|
+
timer = setInterval(() => {
|
|
3320
|
+
refresh().catch(() => {});
|
|
3321
|
+
}, options.intervalMs);
|
|
3322
|
+
}
|
|
3323
|
+
return {
|
|
3324
|
+
close,
|
|
3325
|
+
getServerSnapshot: () => snapshot,
|
|
3326
|
+
getSnapshot: () => snapshot,
|
|
3327
|
+
refresh,
|
|
3328
|
+
subscribe: (listener) => {
|
|
3329
|
+
listeners.add(listener);
|
|
3330
|
+
return () => {
|
|
3331
|
+
listeners.delete(listener);
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
};
|
|
3335
|
+
};
|
|
3336
|
+
|
|
3337
|
+
// src/angular/voice-readiness-failures.service.ts
|
|
3338
|
+
var _dec = [
|
|
3339
|
+
Injectable15({ providedIn: "root" })
|
|
3340
|
+
];
|
|
3341
|
+
var _init = __decoratorStart(undefined);
|
|
3342
|
+
|
|
3343
|
+
class VoiceReadinessFailuresService {
|
|
3344
|
+
connect(path = "/api/production-readiness", options = {}) {
|
|
3345
|
+
const store = createVoiceReadinessFailuresStore(path, options);
|
|
3346
|
+
const errorSignal = signal15(null);
|
|
3347
|
+
const isLoadingSignal = signal15(false);
|
|
3348
|
+
const reportSignal = signal15(undefined);
|
|
3349
|
+
const updatedAtSignal = signal15(undefined);
|
|
3350
|
+
const sync = () => {
|
|
3351
|
+
const snapshot = store.getSnapshot();
|
|
3352
|
+
errorSignal.set(snapshot.error);
|
|
3353
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3354
|
+
reportSignal.set(snapshot.report);
|
|
3355
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3356
|
+
};
|
|
3357
|
+
const unsubscribe = store.subscribe(sync);
|
|
3358
|
+
sync();
|
|
3359
|
+
if (typeof window !== "undefined") {
|
|
3360
|
+
store.refresh().catch(() => {});
|
|
3361
|
+
}
|
|
3362
|
+
return {
|
|
3363
|
+
close: () => {
|
|
3364
|
+
unsubscribe();
|
|
3365
|
+
store.close();
|
|
3366
|
+
},
|
|
3367
|
+
error: computed15(() => errorSignal()),
|
|
3368
|
+
explanations: computed15(() => reportSignal()?.checks.filter((check) => check.status !== "pass" && !!check.gateExplanation) ?? []),
|
|
3369
|
+
isLoading: computed15(() => isLoadingSignal()),
|
|
3370
|
+
refresh: store.refresh,
|
|
3371
|
+
report: computed15(() => reportSignal()),
|
|
3372
|
+
updatedAt: computed15(() => updatedAtSignal())
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
VoiceReadinessFailuresService = __decorateElement(_init, 0, "VoiceReadinessFailuresService", _dec, VoiceReadinessFailuresService);
|
|
3377
|
+
__runInitializers(_init, 1, VoiceReadinessFailuresService);
|
|
3378
|
+
__decoratorMetadata(_init, VoiceReadinessFailuresService);
|
|
3379
|
+
let _VoiceReadinessFailuresService = VoiceReadinessFailuresService;
|
|
3380
|
+
// src/angular/voice-ops-action-center.service.ts
|
|
3381
|
+
import { computed as computed16, Injectable as Injectable16, signal as signal16 } from "@angular/core";
|
|
3382
|
+
|
|
3383
|
+
// src/client/opsActionCenter.ts
|
|
3384
|
+
var recordVoiceOpsActionResult = async (result, options = {}) => {
|
|
3385
|
+
if (options.auditPath === false) {
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
const path = options.auditPath ?? "/api/voice/ops-actions/audit";
|
|
3389
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3390
|
+
const response = await fetchImpl(path, {
|
|
3391
|
+
body: JSON.stringify(result),
|
|
3392
|
+
headers: {
|
|
3393
|
+
"Content-Type": "application/json"
|
|
3394
|
+
},
|
|
3395
|
+
method: "POST"
|
|
3396
|
+
});
|
|
3397
|
+
if (!response.ok) {
|
|
3398
|
+
throw new Error(`Voice ops action audit failed: HTTP ${response.status}`);
|
|
3399
|
+
}
|
|
3400
|
+
};
|
|
3401
|
+
var createVoiceOpsActionCenterActions = (options = {}) => {
|
|
3402
|
+
const deliveryRuntimePath = options.deliveryRuntimePath ?? "/api/voice-delivery-runtime";
|
|
3403
|
+
const actions = [];
|
|
3404
|
+
if (options.includeProductionReadiness !== false) {
|
|
3405
|
+
actions.push({
|
|
3406
|
+
description: "Refresh the production readiness report.",
|
|
3407
|
+
id: "production-readiness",
|
|
3408
|
+
label: "Refresh readiness",
|
|
3409
|
+
method: "GET",
|
|
3410
|
+
path: options.productionReadinessPath ?? "/api/production-readiness"
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3413
|
+
if (options.includeDeliveryRuntime !== false) {
|
|
3414
|
+
actions.push({
|
|
3415
|
+
description: "Drain pending and failed audit/trace deliveries.",
|
|
3416
|
+
id: "delivery-runtime.tick",
|
|
3417
|
+
label: "Tick delivery workers",
|
|
3418
|
+
method: "POST",
|
|
3419
|
+
path: `${deliveryRuntimePath.replace(/\/$/, "")}/tick`
|
|
3420
|
+
}, {
|
|
3421
|
+
description: "Move reviewed dead letters back to live delivery queues.",
|
|
3422
|
+
id: "delivery-runtime.requeue-dead-letters",
|
|
3423
|
+
label: "Requeue dead letters",
|
|
3424
|
+
method: "POST",
|
|
3425
|
+
path: `${deliveryRuntimePath.replace(/\/$/, "")}/requeue-dead-letters`
|
|
3426
|
+
});
|
|
3427
|
+
}
|
|
3428
|
+
if (options.includeTurnLatencyProof !== false) {
|
|
3429
|
+
actions.push({
|
|
3430
|
+
description: "Run the synthetic turn latency proof.",
|
|
3431
|
+
id: "turn-latency.proof",
|
|
3432
|
+
label: "Run latency proof",
|
|
3433
|
+
method: "POST",
|
|
3434
|
+
path: options.turnLatencyProofPath ?? "/api/turn-latency/proof"
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
if (options.includeProviderSimulation !== false) {
|
|
3438
|
+
const pathPrefix = options.providerSimulationPathPrefix ?? "/api/stt-simulate";
|
|
3439
|
+
for (const provider of options.providers ?? []) {
|
|
3440
|
+
actions.push({
|
|
3441
|
+
description: `Simulate ${provider} provider failure.`,
|
|
3442
|
+
id: `provider.${provider}.failure`,
|
|
3443
|
+
label: `Simulate ${provider} failure`,
|
|
3444
|
+
method: "POST",
|
|
3445
|
+
path: `${pathPrefix}/failure?provider=${encodeURIComponent(provider)}`
|
|
3446
|
+
}, {
|
|
3447
|
+
description: `Mark ${provider} provider recovered.`,
|
|
3448
|
+
id: `provider.${provider}.recovery`,
|
|
3449
|
+
label: `Recover ${provider}`,
|
|
3450
|
+
method: "POST",
|
|
3451
|
+
path: `${pathPrefix}/recovery?provider=${encodeURIComponent(provider)}`
|
|
3452
|
+
});
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
return actions;
|
|
3456
|
+
};
|
|
3457
|
+
var runVoiceOpsAction = async (action, options = {}) => {
|
|
3458
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3459
|
+
const response = await fetchImpl(action.path, {
|
|
3460
|
+
method: action.method ?? "POST"
|
|
3461
|
+
});
|
|
3462
|
+
const body = await response.json().catch(() => null);
|
|
3463
|
+
if (!response.ok) {
|
|
3464
|
+
const message = body && typeof body === "object" && "error" in body ? String(body.error) : `Voice ops action "${action.id}" failed: HTTP ${response.status}`;
|
|
3465
|
+
throw new Error(message);
|
|
3466
|
+
}
|
|
3467
|
+
return {
|
|
3468
|
+
actionId: action.id,
|
|
3469
|
+
body,
|
|
3470
|
+
ok: response.ok,
|
|
3471
|
+
ranAt: Date.now(),
|
|
3472
|
+
status: response.status
|
|
3473
|
+
};
|
|
3474
|
+
};
|
|
3475
|
+
var createVoiceOpsActionCenterStore = (options = {}) => {
|
|
3476
|
+
const listeners = new Set;
|
|
3477
|
+
let closed = false;
|
|
3478
|
+
let timer;
|
|
3479
|
+
let snapshot = {
|
|
3480
|
+
actions: options.actions ?? createVoiceOpsActionCenterActions(),
|
|
3481
|
+
error: null,
|
|
3482
|
+
isRunning: false
|
|
3483
|
+
};
|
|
3484
|
+
const emit = () => {
|
|
3485
|
+
for (const listener of listeners) {
|
|
3486
|
+
listener();
|
|
3487
|
+
}
|
|
3488
|
+
};
|
|
3489
|
+
const setActions = (actions) => {
|
|
3490
|
+
snapshot = { ...snapshot, actions, updatedAt: Date.now() };
|
|
3491
|
+
emit();
|
|
3492
|
+
};
|
|
3493
|
+
const run = async (actionId) => {
|
|
3494
|
+
if (closed) {
|
|
3495
|
+
return snapshot.lastResult;
|
|
3496
|
+
}
|
|
3497
|
+
const action = snapshot.actions.find((item) => item.id === actionId);
|
|
3498
|
+
if (!action) {
|
|
3499
|
+
throw new Error(`Voice ops action "${actionId}" is not configured.`);
|
|
3500
|
+
}
|
|
3501
|
+
if (action.disabled) {
|
|
3502
|
+
throw new Error(`Voice ops action "${actionId}" is disabled.`);
|
|
3503
|
+
}
|
|
3504
|
+
snapshot = {
|
|
3505
|
+
...snapshot,
|
|
3506
|
+
error: null,
|
|
3507
|
+
isRunning: true,
|
|
3508
|
+
runningActionId: action.id
|
|
3509
|
+
};
|
|
3510
|
+
emit();
|
|
3511
|
+
try {
|
|
3512
|
+
const result = await runVoiceOpsAction(action, options);
|
|
3513
|
+
await options.onActionResult?.(result);
|
|
3514
|
+
await recordVoiceOpsActionResult(result, options);
|
|
3515
|
+
snapshot = {
|
|
3516
|
+
...snapshot,
|
|
3517
|
+
error: null,
|
|
3518
|
+
isRunning: false,
|
|
3519
|
+
lastResult: result,
|
|
3520
|
+
runningActionId: undefined,
|
|
3521
|
+
updatedAt: Date.now()
|
|
3522
|
+
};
|
|
3523
|
+
emit();
|
|
3524
|
+
return result;
|
|
3525
|
+
} catch (error) {
|
|
3526
|
+
const result = {
|
|
3527
|
+
actionId: action.id,
|
|
3528
|
+
body: null,
|
|
3529
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3530
|
+
ok: false,
|
|
3531
|
+
ranAt: Date.now(),
|
|
3532
|
+
status: 0
|
|
3533
|
+
};
|
|
3534
|
+
await options.onActionResult?.(result);
|
|
3535
|
+
await recordVoiceOpsActionResult(result, options).catch(() => {});
|
|
3536
|
+
snapshot = {
|
|
3537
|
+
...snapshot,
|
|
3538
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3539
|
+
isRunning: false,
|
|
3540
|
+
runningActionId: undefined
|
|
3541
|
+
};
|
|
3542
|
+
emit();
|
|
3543
|
+
throw error;
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
const close = () => {
|
|
3547
|
+
closed = true;
|
|
3548
|
+
if (timer) {
|
|
3549
|
+
clearInterval(timer);
|
|
3550
|
+
timer = undefined;
|
|
3551
|
+
}
|
|
3552
|
+
listeners.clear();
|
|
3553
|
+
};
|
|
3554
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
3555
|
+
timer = setInterval(() => {
|
|
3556
|
+
emit();
|
|
3557
|
+
}, options.intervalMs);
|
|
3558
|
+
}
|
|
3559
|
+
return {
|
|
3560
|
+
close,
|
|
3561
|
+
getServerSnapshot: () => snapshot,
|
|
3562
|
+
getSnapshot: () => snapshot,
|
|
3563
|
+
run,
|
|
3564
|
+
setActions,
|
|
3565
|
+
subscribe: (listener) => {
|
|
3566
|
+
listeners.add(listener);
|
|
3567
|
+
return () => {
|
|
3568
|
+
listeners.delete(listener);
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3571
|
+
};
|
|
3572
|
+
};
|
|
3573
|
+
|
|
3574
|
+
// src/angular/voice-ops-action-center.service.ts
|
|
3575
|
+
var _dec = [
|
|
3576
|
+
Injectable16({ providedIn: "root" })
|
|
3577
|
+
];
|
|
3578
|
+
var _init = __decoratorStart(undefined);
|
|
3579
|
+
|
|
3580
|
+
class VoiceOpsActionCenterService {
|
|
3581
|
+
connect(options = {}) {
|
|
3582
|
+
const store = createVoiceOpsActionCenterStore(options);
|
|
3583
|
+
const actionsSignal = signal16([]);
|
|
3584
|
+
const errorSignal = signal16(null);
|
|
3585
|
+
const isRunningSignal = signal16(false);
|
|
3586
|
+
const lastResultSignal = signal16(undefined);
|
|
3587
|
+
const runningActionIdSignal = signal16(undefined);
|
|
3588
|
+
const sync = () => {
|
|
3589
|
+
const snapshot = store.getSnapshot();
|
|
3590
|
+
actionsSignal.set(snapshot.actions);
|
|
3591
|
+
errorSignal.set(snapshot.error);
|
|
3592
|
+
isRunningSignal.set(snapshot.isRunning);
|
|
3593
|
+
lastResultSignal.set(snapshot.lastResult);
|
|
3594
|
+
runningActionIdSignal.set(snapshot.runningActionId);
|
|
3595
|
+
};
|
|
3596
|
+
const unsubscribe = store.subscribe(sync);
|
|
3597
|
+
sync();
|
|
3598
|
+
return {
|
|
3599
|
+
actions: computed16(() => actionsSignal()),
|
|
3600
|
+
close: () => {
|
|
3601
|
+
unsubscribe();
|
|
3602
|
+
store.close();
|
|
3603
|
+
},
|
|
3604
|
+
error: computed16(() => errorSignal()),
|
|
3605
|
+
isRunning: computed16(() => isRunningSignal()),
|
|
3606
|
+
lastResult: computed16(() => lastResultSignal()),
|
|
3607
|
+
run: store.run,
|
|
3608
|
+
runningActionId: computed16(() => runningActionIdSignal()),
|
|
3609
|
+
setActions: store.setActions
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
VoiceOpsActionCenterService = __decorateElement(_init, 0, "VoiceOpsActionCenterService", _dec, VoiceOpsActionCenterService);
|
|
3614
|
+
__runInitializers(_init, 1, VoiceOpsActionCenterService);
|
|
3615
|
+
__decoratorMetadata(_init, VoiceOpsActionCenterService);
|
|
3616
|
+
let _VoiceOpsActionCenterService = VoiceOpsActionCenterService;
|
|
3617
|
+
// src/angular/voice-live-ops.service.ts
|
|
3618
|
+
import { computed as computed17, Injectable as Injectable17, signal as signal17 } from "@angular/core";
|
|
3619
|
+
|
|
3620
|
+
// src/client/liveOps.ts
|
|
3621
|
+
var postVoiceLiveOpsAction = async (input, options = {}) => {
|
|
3622
|
+
if (!input.sessionId) {
|
|
3623
|
+
throw new Error("Start a voice session before running live ops actions.");
|
|
3624
|
+
}
|
|
3625
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3626
|
+
const response = await fetchImpl(options.actionPath ?? "/api/voice/live-ops/action", {
|
|
3627
|
+
body: JSON.stringify(input),
|
|
3628
|
+
headers: {
|
|
3629
|
+
"Content-Type": "application/json"
|
|
3630
|
+
},
|
|
3631
|
+
method: "POST"
|
|
3632
|
+
});
|
|
3633
|
+
const payload = await response.json().catch(() => null);
|
|
3634
|
+
if (!response.ok || !payload?.ok) {
|
|
3635
|
+
const message = payload && typeof payload === "object" && "error" in payload ? String(payload.error) : `Voice live ops action failed: HTTP ${response.status}`;
|
|
3636
|
+
throw new Error(message);
|
|
3637
|
+
}
|
|
3638
|
+
return payload;
|
|
3639
|
+
};
|
|
3640
|
+
var createVoiceLiveOpsStore = (options = {}) => {
|
|
3641
|
+
const listeners = new Set;
|
|
3642
|
+
let closed = false;
|
|
3643
|
+
let snapshot = {
|
|
3644
|
+
error: null,
|
|
3645
|
+
isRunning: false
|
|
3646
|
+
};
|
|
3647
|
+
const emit = () => {
|
|
3648
|
+
for (const listener of listeners) {
|
|
3649
|
+
listener();
|
|
3650
|
+
}
|
|
3651
|
+
};
|
|
3652
|
+
const run = async (input) => {
|
|
3653
|
+
if (closed) {
|
|
3654
|
+
return snapshot.lastResult;
|
|
3655
|
+
}
|
|
3656
|
+
snapshot = {
|
|
3657
|
+
...snapshot,
|
|
3658
|
+
error: null,
|
|
3659
|
+
isRunning: true,
|
|
3660
|
+
runningAction: input.action
|
|
3661
|
+
};
|
|
3662
|
+
emit();
|
|
3663
|
+
try {
|
|
3664
|
+
const result = await postVoiceLiveOpsAction(input, options);
|
|
3665
|
+
await options.onControl?.(result);
|
|
3666
|
+
snapshot = {
|
|
3667
|
+
...snapshot,
|
|
3668
|
+
error: null,
|
|
3669
|
+
isRunning: false,
|
|
3670
|
+
lastResult: result,
|
|
3671
|
+
runningAction: undefined,
|
|
3672
|
+
updatedAt: Date.now()
|
|
3673
|
+
};
|
|
3674
|
+
emit();
|
|
3675
|
+
return result;
|
|
3676
|
+
} catch (error) {
|
|
3677
|
+
snapshot = {
|
|
3678
|
+
...snapshot,
|
|
3679
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3680
|
+
isRunning: false,
|
|
3681
|
+
runningAction: undefined,
|
|
3682
|
+
updatedAt: Date.now()
|
|
3683
|
+
};
|
|
3684
|
+
emit();
|
|
3685
|
+
throw error;
|
|
3686
|
+
}
|
|
3687
|
+
};
|
|
3688
|
+
const close = () => {
|
|
3689
|
+
closed = true;
|
|
3690
|
+
listeners.clear();
|
|
3691
|
+
};
|
|
3692
|
+
return {
|
|
3693
|
+
close,
|
|
3694
|
+
getServerSnapshot: () => snapshot,
|
|
3695
|
+
getSnapshot: () => snapshot,
|
|
3696
|
+
run,
|
|
3697
|
+
subscribe: (listener) => {
|
|
3698
|
+
listeners.add(listener);
|
|
3699
|
+
return () => {
|
|
3700
|
+
listeners.delete(listener);
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3703
|
+
};
|
|
3704
|
+
};
|
|
3705
|
+
|
|
3706
|
+
// src/angular/voice-live-ops.service.ts
|
|
3707
|
+
var _dec = [
|
|
3708
|
+
Injectable17({ providedIn: "root" })
|
|
3709
|
+
];
|
|
3710
|
+
var _init = __decoratorStart(undefined);
|
|
3711
|
+
|
|
3712
|
+
class VoiceLiveOpsService {
|
|
3713
|
+
connect(options = {}) {
|
|
3714
|
+
const store = createVoiceLiveOpsStore(options);
|
|
3715
|
+
const errorSignal = signal17(null);
|
|
3716
|
+
const isRunningSignal = signal17(false);
|
|
3717
|
+
const lastResultSignal = signal17(undefined);
|
|
3718
|
+
const runningActionSignal = signal17(undefined);
|
|
3719
|
+
const sync = () => {
|
|
3720
|
+
const snapshot = store.getSnapshot();
|
|
3721
|
+
errorSignal.set(snapshot.error);
|
|
3722
|
+
isRunningSignal.set(snapshot.isRunning);
|
|
3723
|
+
lastResultSignal.set(snapshot.lastResult);
|
|
3724
|
+
runningActionSignal.set(snapshot.runningAction);
|
|
3725
|
+
};
|
|
3726
|
+
const unsubscribe = store.subscribe(sync);
|
|
3727
|
+
sync();
|
|
3728
|
+
return {
|
|
3729
|
+
close: () => {
|
|
3730
|
+
unsubscribe();
|
|
3731
|
+
store.close();
|
|
3732
|
+
},
|
|
3733
|
+
error: computed17(() => errorSignal()),
|
|
3734
|
+
isRunning: computed17(() => isRunningSignal()),
|
|
3735
|
+
lastResult: computed17(() => lastResultSignal()),
|
|
3736
|
+
run: store.run,
|
|
3737
|
+
runningAction: computed17(() => runningActionSignal())
|
|
3738
|
+
};
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
VoiceLiveOpsService = __decorateElement(_init, 0, "VoiceLiveOpsService", _dec, VoiceLiveOpsService);
|
|
3742
|
+
__runInitializers(_init, 1, VoiceLiveOpsService);
|
|
3743
|
+
__decoratorMetadata(_init, VoiceLiveOpsService);
|
|
3744
|
+
let _VoiceLiveOpsService = VoiceLiveOpsService;
|
|
3745
|
+
// src/angular/voice-delivery-runtime.service.ts
|
|
3746
|
+
import { computed as computed18, Injectable as Injectable18, signal as signal18 } from "@angular/core";
|
|
3747
|
+
|
|
3748
|
+
// src/client/deliveryRuntime.ts
|
|
3749
|
+
var getDefaultActionPath = (path, action, options) => {
|
|
3750
|
+
if (action === "tick") {
|
|
3751
|
+
return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
|
|
3752
|
+
}
|
|
3753
|
+
return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
|
|
3754
|
+
};
|
|
3755
|
+
var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
3756
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3757
|
+
const response = await fetchImpl(path);
|
|
3758
|
+
if (!response.ok) {
|
|
3759
|
+
throw new Error(`Voice delivery runtime failed: HTTP ${response.status}`);
|
|
3760
|
+
}
|
|
3761
|
+
return await response.json();
|
|
3762
|
+
};
|
|
3763
|
+
var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
3764
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3765
|
+
const response = await fetchImpl(getDefaultActionPath(path, action, options), {
|
|
3766
|
+
method: "POST"
|
|
3767
|
+
});
|
|
3768
|
+
if (!response.ok) {
|
|
3769
|
+
throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
|
|
3770
|
+
}
|
|
3771
|
+
const body = await response.json();
|
|
3772
|
+
return {
|
|
3773
|
+
action,
|
|
3774
|
+
result: body.result,
|
|
3775
|
+
summary: body.summary,
|
|
3776
|
+
updatedAt: Date.now()
|
|
3777
|
+
};
|
|
3778
|
+
};
|
|
3779
|
+
var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
3780
|
+
const listeners = new Set;
|
|
3781
|
+
let closed = false;
|
|
3782
|
+
let timer;
|
|
3783
|
+
let snapshot = {
|
|
3784
|
+
actionError: null,
|
|
3785
|
+
actionStatus: "idle",
|
|
3786
|
+
error: null,
|
|
3787
|
+
isLoading: false
|
|
3788
|
+
};
|
|
3789
|
+
const emit = () => {
|
|
3790
|
+
for (const listener of listeners) {
|
|
3791
|
+
listener();
|
|
3792
|
+
}
|
|
3793
|
+
};
|
|
3794
|
+
const refresh = async () => {
|
|
3795
|
+
if (closed) {
|
|
3796
|
+
return snapshot.report;
|
|
3797
|
+
}
|
|
3798
|
+
snapshot = {
|
|
3799
|
+
...snapshot,
|
|
3800
|
+
error: null,
|
|
3801
|
+
isLoading: true
|
|
3802
|
+
};
|
|
3803
|
+
emit();
|
|
3804
|
+
try {
|
|
3805
|
+
const report = await fetchVoiceDeliveryRuntime(path, options);
|
|
3806
|
+
snapshot = {
|
|
3807
|
+
...snapshot,
|
|
3808
|
+
error: null,
|
|
3809
|
+
isLoading: false,
|
|
3810
|
+
report,
|
|
3811
|
+
updatedAt: Date.now()
|
|
3812
|
+
};
|
|
3813
|
+
emit();
|
|
3814
|
+
return report;
|
|
3815
|
+
} catch (error) {
|
|
3816
|
+
snapshot = {
|
|
3817
|
+
...snapshot,
|
|
3818
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3819
|
+
isLoading: false
|
|
3820
|
+
};
|
|
3821
|
+
emit();
|
|
3822
|
+
throw error;
|
|
3823
|
+
}
|
|
3824
|
+
};
|
|
3825
|
+
const runAction = async (action) => {
|
|
3826
|
+
if (closed) {
|
|
3827
|
+
return snapshot.lastAction;
|
|
3828
|
+
}
|
|
3829
|
+
snapshot = {
|
|
3830
|
+
...snapshot,
|
|
3831
|
+
actionError: null,
|
|
3832
|
+
actionStatus: "running"
|
|
3833
|
+
};
|
|
3834
|
+
emit();
|
|
3835
|
+
try {
|
|
3836
|
+
const result = await runVoiceDeliveryRuntimeAction(action, path, options);
|
|
3837
|
+
snapshot = {
|
|
3838
|
+
...snapshot,
|
|
3839
|
+
actionError: null,
|
|
3840
|
+
actionStatus: "completed",
|
|
3841
|
+
lastAction: result
|
|
3842
|
+
};
|
|
3843
|
+
emit();
|
|
3844
|
+
await refresh();
|
|
3845
|
+
return result;
|
|
3846
|
+
} catch (error) {
|
|
3847
|
+
snapshot = {
|
|
3848
|
+
...snapshot,
|
|
3849
|
+
actionError: error instanceof Error ? error.message : String(error),
|
|
3850
|
+
actionStatus: "failed"
|
|
3851
|
+
};
|
|
3852
|
+
emit();
|
|
3853
|
+
throw error;
|
|
3854
|
+
}
|
|
3855
|
+
};
|
|
3856
|
+
const close = () => {
|
|
3857
|
+
closed = true;
|
|
3858
|
+
if (timer) {
|
|
3859
|
+
clearInterval(timer);
|
|
3860
|
+
timer = undefined;
|
|
3861
|
+
}
|
|
3862
|
+
listeners.clear();
|
|
3863
|
+
};
|
|
3864
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
3865
|
+
timer = setInterval(() => {
|
|
3866
|
+
refresh().catch(() => {});
|
|
3867
|
+
}, options.intervalMs);
|
|
3868
|
+
}
|
|
3869
|
+
return {
|
|
3870
|
+
close,
|
|
3871
|
+
getServerSnapshot: () => snapshot,
|
|
3872
|
+
getSnapshot: () => snapshot,
|
|
3873
|
+
requeueDeadLetters: () => runAction("requeue-dead-letters"),
|
|
3874
|
+
refresh,
|
|
3875
|
+
tick: () => runAction("tick"),
|
|
3876
|
+
subscribe: (listener) => {
|
|
3877
|
+
listeners.add(listener);
|
|
3878
|
+
return () => {
|
|
3879
|
+
listeners.delete(listener);
|
|
3880
|
+
};
|
|
3881
|
+
}
|
|
3882
|
+
};
|
|
3883
|
+
};
|
|
3884
|
+
|
|
3885
|
+
// src/angular/voice-delivery-runtime.service.ts
|
|
3886
|
+
var _dec = [
|
|
3887
|
+
Injectable18({ providedIn: "root" })
|
|
3888
|
+
];
|
|
3889
|
+
var _init = __decoratorStart(undefined);
|
|
3890
|
+
|
|
3891
|
+
class VoiceDeliveryRuntimeService {
|
|
3892
|
+
connect(path = "/api/voice-delivery-runtime", options = {}) {
|
|
3893
|
+
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
3894
|
+
const actionErrorSignal = signal18(null);
|
|
3895
|
+
const actionStatusSignal = signal18("idle");
|
|
3896
|
+
const errorSignal = signal18(null);
|
|
3897
|
+
const isLoadingSignal = signal18(false);
|
|
3898
|
+
const reportSignal = signal18(undefined);
|
|
3899
|
+
const updatedAtSignal = signal18(undefined);
|
|
3900
|
+
const sync = () => {
|
|
3901
|
+
const snapshot = store.getSnapshot();
|
|
3902
|
+
actionErrorSignal.set(snapshot.actionError);
|
|
3903
|
+
actionStatusSignal.set(snapshot.actionStatus);
|
|
3904
|
+
errorSignal.set(snapshot.error);
|
|
3905
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
3906
|
+
reportSignal.set(snapshot.report);
|
|
3907
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
3908
|
+
};
|
|
3909
|
+
const unsubscribe = store.subscribe(sync);
|
|
3910
|
+
sync();
|
|
3911
|
+
if (typeof window !== "undefined") {
|
|
3912
|
+
store.refresh().catch(() => {});
|
|
3913
|
+
}
|
|
3914
|
+
return {
|
|
3915
|
+
close: () => {
|
|
3916
|
+
unsubscribe();
|
|
3917
|
+
store.close();
|
|
3918
|
+
},
|
|
3919
|
+
error: computed18(() => errorSignal()),
|
|
3920
|
+
actionError: computed18(() => actionErrorSignal()),
|
|
3921
|
+
actionStatus: computed18(() => actionStatusSignal()),
|
|
3922
|
+
isLoading: computed18(() => isLoadingSignal()),
|
|
3923
|
+
requeueDeadLetters: store.requeueDeadLetters,
|
|
3924
|
+
refresh: store.refresh,
|
|
3925
|
+
report: computed18(() => reportSignal()),
|
|
3926
|
+
tick: store.tick,
|
|
3927
|
+
updatedAt: computed18(() => updatedAtSignal())
|
|
3928
|
+
};
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
VoiceDeliveryRuntimeService = __decorateElement(_init, 0, "VoiceDeliveryRuntimeService", _dec, VoiceDeliveryRuntimeService);
|
|
3932
|
+
__runInitializers(_init, 1, VoiceDeliveryRuntimeService);
|
|
3933
|
+
__decoratorMetadata(_init, VoiceDeliveryRuntimeService);
|
|
3934
|
+
let _VoiceDeliveryRuntimeService = VoiceDeliveryRuntimeService;
|
|
3935
|
+
// src/angular/voice-campaign-dialer-proof.service.ts
|
|
3936
|
+
import { computed as computed19, Injectable as Injectable19, signal as signal19 } from "@angular/core";
|
|
3937
|
+
|
|
3938
|
+
// src/client/campaignDialerProof.ts
|
|
3939
|
+
var fetchVoiceCampaignDialerProofStatus = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
3940
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3941
|
+
const response = await fetchImpl(path);
|
|
3942
|
+
if (!response.ok) {
|
|
3943
|
+
throw new Error(`Voice campaign dialer proof status failed: HTTP ${response.status}`);
|
|
3944
|
+
}
|
|
3945
|
+
return await response.json();
|
|
3946
|
+
};
|
|
3947
|
+
var runVoiceCampaignDialerProofAction = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
3948
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
3949
|
+
const response = await fetchImpl(path, { method: "POST" });
|
|
3950
|
+
if (!response.ok) {
|
|
3951
|
+
throw new Error(`Voice campaign dialer proof failed: HTTP ${response.status}`);
|
|
3952
|
+
}
|
|
3953
|
+
return await response.json();
|
|
3954
|
+
};
|
|
3955
|
+
var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
3956
|
+
const listeners = new Set;
|
|
3957
|
+
let closed = false;
|
|
3958
|
+
let timer;
|
|
3959
|
+
let snapshot = {
|
|
3960
|
+
error: null,
|
|
3961
|
+
isLoading: false
|
|
3962
|
+
};
|
|
3963
|
+
const emit = () => {
|
|
3964
|
+
for (const listener of listeners) {
|
|
3965
|
+
listener();
|
|
3966
|
+
}
|
|
3967
|
+
};
|
|
3968
|
+
const refresh = async () => {
|
|
3969
|
+
if (closed) {
|
|
3970
|
+
return snapshot.status;
|
|
3971
|
+
}
|
|
3972
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
3973
|
+
emit();
|
|
3974
|
+
try {
|
|
3975
|
+
const status = await fetchVoiceCampaignDialerProofStatus(path, options);
|
|
3976
|
+
snapshot = {
|
|
3977
|
+
...snapshot,
|
|
3978
|
+
error: null,
|
|
3979
|
+
isLoading: false,
|
|
3980
|
+
status,
|
|
3981
|
+
updatedAt: Date.now()
|
|
3982
|
+
};
|
|
3983
|
+
emit();
|
|
3984
|
+
return status;
|
|
3985
|
+
} catch (error) {
|
|
3986
|
+
snapshot = {
|
|
3987
|
+
...snapshot,
|
|
3988
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3989
|
+
isLoading: false
|
|
3990
|
+
};
|
|
3991
|
+
emit();
|
|
3992
|
+
throw error;
|
|
3993
|
+
}
|
|
3994
|
+
};
|
|
3995
|
+
const runProof = async () => {
|
|
3996
|
+
const runPath = options.runPath ?? snapshot.status?.runPath ?? path;
|
|
3997
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
3998
|
+
emit();
|
|
3999
|
+
try {
|
|
4000
|
+
const report = await runVoiceCampaignDialerProofAction(runPath, options);
|
|
4001
|
+
snapshot = {
|
|
4002
|
+
...snapshot,
|
|
4003
|
+
error: null,
|
|
4004
|
+
isLoading: false,
|
|
4005
|
+
report,
|
|
4006
|
+
status: {
|
|
4007
|
+
generatedAt: Date.now(),
|
|
4008
|
+
mode: report.mode,
|
|
4009
|
+
ok: report.ok,
|
|
4010
|
+
providers: report.providers.map((provider) => provider.provider),
|
|
4011
|
+
runPath,
|
|
4012
|
+
safe: true
|
|
4013
|
+
},
|
|
4014
|
+
updatedAt: Date.now()
|
|
4015
|
+
};
|
|
4016
|
+
emit();
|
|
4017
|
+
return report;
|
|
4018
|
+
} catch (error) {
|
|
4019
|
+
snapshot = {
|
|
4020
|
+
...snapshot,
|
|
4021
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4022
|
+
isLoading: false
|
|
4023
|
+
};
|
|
4024
|
+
emit();
|
|
4025
|
+
throw error;
|
|
4026
|
+
}
|
|
4027
|
+
};
|
|
4028
|
+
const close = () => {
|
|
4029
|
+
closed = true;
|
|
4030
|
+
if (timer) {
|
|
4031
|
+
clearInterval(timer);
|
|
4032
|
+
timer = undefined;
|
|
4033
|
+
}
|
|
4034
|
+
listeners.clear();
|
|
4035
|
+
};
|
|
4036
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
4037
|
+
timer = setInterval(() => {
|
|
4038
|
+
refresh().catch(() => {});
|
|
4039
|
+
}, options.intervalMs);
|
|
4040
|
+
}
|
|
4041
|
+
return {
|
|
4042
|
+
close,
|
|
4043
|
+
getServerSnapshot: () => snapshot,
|
|
4044
|
+
getSnapshot: () => snapshot,
|
|
4045
|
+
refresh,
|
|
4046
|
+
runProof,
|
|
4047
|
+
subscribe: (listener) => {
|
|
4048
|
+
listeners.add(listener);
|
|
4049
|
+
return () => {
|
|
4050
|
+
listeners.delete(listener);
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
};
|
|
4054
|
+
};
|
|
4055
|
+
|
|
4056
|
+
// src/angular/voice-campaign-dialer-proof.service.ts
|
|
4057
|
+
var _dec = [
|
|
4058
|
+
Injectable19({ providedIn: "root" })
|
|
4059
|
+
];
|
|
4060
|
+
var _init = __decoratorStart(undefined);
|
|
4061
|
+
|
|
4062
|
+
class VoiceCampaignDialerProofService {
|
|
4063
|
+
connect(path = "/api/voice/campaigns/dialer-proof", options = {}) {
|
|
4064
|
+
const store = createVoiceCampaignDialerProofStore(path, options);
|
|
4065
|
+
const errorSignal = signal19(null);
|
|
4066
|
+
const isLoadingSignal = signal19(false);
|
|
4067
|
+
const reportSignal = signal19(undefined);
|
|
4068
|
+
const statusSignal = signal19(undefined);
|
|
4069
|
+
const updatedAtSignal = signal19(undefined);
|
|
4070
|
+
const sync = () => {
|
|
4071
|
+
const snapshot = store.getSnapshot();
|
|
4072
|
+
errorSignal.set(snapshot.error);
|
|
4073
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4074
|
+
reportSignal.set(snapshot.report);
|
|
4075
|
+
statusSignal.set(snapshot.status);
|
|
4076
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4077
|
+
};
|
|
4078
|
+
const unsubscribe = store.subscribe(sync);
|
|
4079
|
+
sync();
|
|
4080
|
+
store.refresh().catch(() => {});
|
|
4081
|
+
return {
|
|
4082
|
+
close: () => {
|
|
4083
|
+
unsubscribe();
|
|
4084
|
+
store.close();
|
|
4085
|
+
},
|
|
4086
|
+
error: computed19(() => errorSignal()),
|
|
4087
|
+
isLoading: computed19(() => isLoadingSignal()),
|
|
4088
|
+
refresh: store.refresh,
|
|
4089
|
+
report: computed19(() => reportSignal()),
|
|
4090
|
+
runProof: store.runProof,
|
|
4091
|
+
status: computed19(() => statusSignal()),
|
|
4092
|
+
updatedAt: computed19(() => updatedAtSignal())
|
|
4093
|
+
};
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
VoiceCampaignDialerProofService = __decorateElement(_init, 0, "VoiceCampaignDialerProofService", _dec, VoiceCampaignDialerProofService);
|
|
4097
|
+
__runInitializers(_init, 1, VoiceCampaignDialerProofService);
|
|
4098
|
+
__decoratorMetadata(_init, VoiceCampaignDialerProofService);
|
|
4099
|
+
let _VoiceCampaignDialerProofService = VoiceCampaignDialerProofService;
|
|
4100
|
+
// src/angular/voice-stream.service.ts
|
|
4101
|
+
import { computed as computed20, Injectable as Injectable20, signal as signal20 } from "@angular/core";
|
|
4102
|
+
var _dec = [
|
|
4103
|
+
Injectable20({ providedIn: "root" })
|
|
4104
|
+
];
|
|
4105
|
+
var _init = __decoratorStart(undefined);
|
|
4106
|
+
|
|
4107
|
+
class VoiceStreamService {
|
|
4108
|
+
connect(path, options = {}) {
|
|
4109
|
+
const stream = createVoiceStream(path, options);
|
|
4110
|
+
const assistantAudioSignal = signal20([]);
|
|
4111
|
+
const assistantTextsSignal = signal20([]);
|
|
4112
|
+
const callSignal = signal20(null);
|
|
4113
|
+
const errorSignal = signal20(null);
|
|
4114
|
+
const isConnectedSignal = signal20(false);
|
|
4115
|
+
const partialSignal = signal20("");
|
|
4116
|
+
const reconnectSignal = signal20(stream.reconnect);
|
|
4117
|
+
const sessionIdSignal = signal20(stream.sessionId);
|
|
4118
|
+
const sessionMetadataSignal = signal20(stream.sessionMetadata);
|
|
4119
|
+
const statusSignal = signal20(stream.status);
|
|
4120
|
+
const turnsSignal = signal20([]);
|
|
4121
|
+
const sync = () => {
|
|
4122
|
+
assistantAudioSignal.set([...stream.assistantAudio]);
|
|
4123
|
+
assistantTextsSignal.set([...stream.assistantTexts]);
|
|
4124
|
+
callSignal.set(stream.call);
|
|
4125
|
+
errorSignal.set(stream.error);
|
|
4126
|
+
isConnectedSignal.set(stream.isConnected);
|
|
4127
|
+
partialSignal.set(stream.partial);
|
|
4128
|
+
reconnectSignal.set(stream.reconnect);
|
|
4129
|
+
sessionIdSignal.set(stream.sessionId);
|
|
4130
|
+
sessionMetadataSignal.set(stream.sessionMetadata);
|
|
4131
|
+
statusSignal.set(stream.status);
|
|
4132
|
+
turnsSignal.set([...stream.turns]);
|
|
4133
|
+
};
|
|
4134
|
+
const unsubscribe = stream.subscribe(sync);
|
|
4135
|
+
sync();
|
|
4136
|
+
return {
|
|
4137
|
+
assistantAudio: computed20(() => assistantAudioSignal()),
|
|
4138
|
+
assistantTexts: computed20(() => assistantTextsSignal()),
|
|
4139
|
+
call: computed20(() => callSignal()),
|
|
4140
|
+
callControl: (message) => stream.callControl(message),
|
|
4141
|
+
close: () => {
|
|
4142
|
+
unsubscribe();
|
|
4143
|
+
stream.close();
|
|
4144
|
+
},
|
|
4145
|
+
endTurn: () => stream.endTurn(),
|
|
4146
|
+
error: computed20(() => errorSignal()),
|
|
4147
|
+
isConnected: computed20(() => isConnectedSignal()),
|
|
4148
|
+
partial: computed20(() => partialSignal()),
|
|
4149
|
+
reconnect: computed20(() => reconnectSignal()),
|
|
4150
|
+
sendAudio: (audio) => stream.sendAudio(audio),
|
|
4151
|
+
simulateDisconnect: () => stream.simulateDisconnect(),
|
|
4152
|
+
sessionId: computed20(() => sessionIdSignal()),
|
|
4153
|
+
sessionMetadata: computed20(() => sessionMetadataSignal()),
|
|
4154
|
+
status: computed20(() => statusSignal()),
|
|
4155
|
+
turns: computed20(() => turnsSignal())
|
|
4156
|
+
};
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
VoiceStreamService = __decorateElement(_init, 0, "VoiceStreamService", _dec, VoiceStreamService);
|
|
4160
|
+
__runInitializers(_init, 1, VoiceStreamService);
|
|
4161
|
+
__decoratorMetadata(_init, VoiceStreamService);
|
|
4162
|
+
let _VoiceStreamService = VoiceStreamService;
|
|
4163
|
+
// src/angular/voice-controller.service.ts
|
|
4164
|
+
import { computed as computed21, Injectable as Injectable21, signal as signal21 } from "@angular/core";
|
|
4165
|
+
var _dec = [
|
|
4166
|
+
Injectable21({ providedIn: "root" })
|
|
4167
|
+
];
|
|
4168
|
+
var _init = __decoratorStart(undefined);
|
|
4169
|
+
|
|
4170
|
+
class VoiceControllerService {
|
|
4171
|
+
connect(path, options = {}) {
|
|
4172
|
+
const controller = createVoiceController(path, options);
|
|
4173
|
+
const assistantAudioSignal = signal21([]);
|
|
4174
|
+
const assistantTextsSignal = signal21([]);
|
|
4175
|
+
const errorSignal = signal21(null);
|
|
4176
|
+
const isConnectedSignal = signal21(false);
|
|
4177
|
+
const isRecordingSignal = signal21(false);
|
|
4178
|
+
const partialSignal = signal21("");
|
|
4179
|
+
const reconnectSignal = signal21(controller.reconnect);
|
|
4180
|
+
const recordingErrorSignal = signal21(null);
|
|
4181
|
+
const sessionIdSignal = signal21(controller.sessionId);
|
|
4182
|
+
const statusSignal = signal21(controller.status);
|
|
4183
|
+
const turnsSignal = signal21([]);
|
|
4184
|
+
const sync = () => {
|
|
4185
|
+
assistantAudioSignal.set([...controller.assistantAudio]);
|
|
4186
|
+
assistantTextsSignal.set([...controller.assistantTexts]);
|
|
4187
|
+
errorSignal.set(controller.error);
|
|
4188
|
+
isConnectedSignal.set(controller.isConnected);
|
|
4189
|
+
isRecordingSignal.set(controller.isRecording);
|
|
4190
|
+
partialSignal.set(controller.partial);
|
|
4191
|
+
reconnectSignal.set(controller.reconnect);
|
|
4192
|
+
recordingErrorSignal.set(controller.recordingError);
|
|
4193
|
+
sessionIdSignal.set(controller.sessionId);
|
|
4194
|
+
statusSignal.set(controller.status);
|
|
4195
|
+
turnsSignal.set([...controller.turns]);
|
|
4196
|
+
};
|
|
4197
|
+
const unsubscribe = controller.subscribe(sync);
|
|
4198
|
+
sync();
|
|
4199
|
+
return {
|
|
4200
|
+
assistantAudio: computed21(() => assistantAudioSignal()),
|
|
4201
|
+
assistantTexts: computed21(() => assistantTextsSignal()),
|
|
4202
|
+
bindHTMX: controller.bindHTMX,
|
|
4203
|
+
close: () => {
|
|
4204
|
+
unsubscribe();
|
|
4205
|
+
controller.close();
|
|
4206
|
+
},
|
|
4207
|
+
endTurn: () => controller.endTurn(),
|
|
4208
|
+
error: computed21(() => errorSignal()),
|
|
4209
|
+
isConnected: computed21(() => isConnectedSignal()),
|
|
4210
|
+
isRecording: computed21(() => isRecordingSignal()),
|
|
4211
|
+
partial: computed21(() => partialSignal()),
|
|
4212
|
+
reconnect: computed21(() => reconnectSignal()),
|
|
4213
|
+
recordingError: computed21(() => recordingErrorSignal()),
|
|
4214
|
+
sendAudio: (audio) => controller.sendAudio(audio),
|
|
4215
|
+
simulateDisconnect: () => controller.simulateDisconnect(),
|
|
4216
|
+
sessionId: computed21(() => sessionIdSignal()),
|
|
4217
|
+
startRecording: () => controller.startRecording(),
|
|
4218
|
+
status: computed21(() => statusSignal()),
|
|
4219
|
+
stopRecording: () => controller.stopRecording(),
|
|
4220
|
+
toggleRecording: () => controller.toggleRecording(),
|
|
4221
|
+
turns: computed21(() => turnsSignal())
|
|
4222
|
+
};
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
VoiceControllerService = __decorateElement(_init, 0, "VoiceControllerService", _dec, VoiceControllerService);
|
|
4226
|
+
__runInitializers(_init, 1, VoiceControllerService);
|
|
4227
|
+
__decoratorMetadata(_init, VoiceControllerService);
|
|
4228
|
+
let _VoiceControllerService = VoiceControllerService;
|
|
4229
|
+
// src/angular/voice-provider-capabilities.service.ts
|
|
4230
|
+
import { computed as computed22, Injectable as Injectable22, signal as signal22 } from "@angular/core";
|
|
4231
|
+
|
|
4232
|
+
// src/client/providerCapabilities.ts
|
|
4233
|
+
var fetchVoiceProviderCapabilities = async (path = "/api/provider-capabilities", options = {}) => {
|
|
4234
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4235
|
+
const response = await fetchImpl(path);
|
|
4236
|
+
if (!response.ok) {
|
|
4237
|
+
throw new Error(`Voice provider capabilities failed: HTTP ${response.status}`);
|
|
4238
|
+
}
|
|
4239
|
+
return await response.json();
|
|
4240
|
+
};
|
|
4241
|
+
var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities", options = {}) => {
|
|
4242
|
+
const listeners = new Set;
|
|
4243
|
+
let closed = false;
|
|
4244
|
+
let timer;
|
|
4245
|
+
let snapshot = {
|
|
4246
|
+
error: null,
|
|
4247
|
+
isLoading: false
|
|
4248
|
+
};
|
|
4249
|
+
const emit = () => {
|
|
4250
|
+
for (const listener of listeners) {
|
|
4251
|
+
listener();
|
|
4252
|
+
}
|
|
4253
|
+
};
|
|
4254
|
+
const refresh = async () => {
|
|
4255
|
+
if (closed) {
|
|
4256
|
+
return snapshot.report;
|
|
4257
|
+
}
|
|
4258
|
+
snapshot = {
|
|
4259
|
+
...snapshot,
|
|
4260
|
+
error: null,
|
|
4261
|
+
isLoading: true
|
|
4262
|
+
};
|
|
4263
|
+
emit();
|
|
4264
|
+
try {
|
|
4265
|
+
const report = await fetchVoiceProviderCapabilities(path, options);
|
|
4266
|
+
snapshot = {
|
|
4267
|
+
error: null,
|
|
4268
|
+
isLoading: false,
|
|
4269
|
+
report,
|
|
4270
|
+
updatedAt: Date.now()
|
|
4271
|
+
};
|
|
4272
|
+
emit();
|
|
4273
|
+
return report;
|
|
4274
|
+
} catch (error) {
|
|
4275
|
+
snapshot = {
|
|
4276
|
+
...snapshot,
|
|
4277
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4278
|
+
isLoading: false
|
|
4279
|
+
};
|
|
4280
|
+
emit();
|
|
4281
|
+
throw error;
|
|
4282
|
+
}
|
|
4283
|
+
};
|
|
4284
|
+
const close = () => {
|
|
4285
|
+
closed = true;
|
|
4286
|
+
if (timer) {
|
|
4287
|
+
clearInterval(timer);
|
|
4288
|
+
timer = undefined;
|
|
4289
|
+
}
|
|
4290
|
+
listeners.clear();
|
|
4291
|
+
};
|
|
4292
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
4293
|
+
timer = setInterval(() => {
|
|
4294
|
+
refresh().catch(() => {});
|
|
4295
|
+
}, options.intervalMs);
|
|
4296
|
+
}
|
|
4297
|
+
return {
|
|
4298
|
+
close,
|
|
4299
|
+
getServerSnapshot: () => snapshot,
|
|
4300
|
+
getSnapshot: () => snapshot,
|
|
4301
|
+
refresh,
|
|
4302
|
+
subscribe: (listener) => {
|
|
4303
|
+
listeners.add(listener);
|
|
4304
|
+
return () => {
|
|
4305
|
+
listeners.delete(listener);
|
|
4306
|
+
};
|
|
4307
|
+
}
|
|
4308
|
+
};
|
|
4309
|
+
};
|
|
4310
|
+
|
|
4311
|
+
// src/angular/voice-provider-capabilities.service.ts
|
|
4312
|
+
var _dec = [
|
|
4313
|
+
Injectable22({ providedIn: "root" })
|
|
4314
|
+
];
|
|
4315
|
+
var _init = __decoratorStart(undefined);
|
|
4316
|
+
|
|
4317
|
+
class VoiceProviderCapabilitiesService {
|
|
4318
|
+
connect(path = "/api/provider-capabilities", options = {}) {
|
|
4319
|
+
const store = createVoiceProviderCapabilitiesStore(path, options);
|
|
4320
|
+
const errorSignal = signal22(null);
|
|
4321
|
+
const isLoadingSignal = signal22(false);
|
|
4322
|
+
const reportSignal = signal22(undefined);
|
|
4323
|
+
const updatedAtSignal = signal22(undefined);
|
|
4324
|
+
const sync = () => {
|
|
4325
|
+
const snapshot = store.getSnapshot();
|
|
4326
|
+
errorSignal.set(snapshot.error);
|
|
4327
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4328
|
+
reportSignal.set(snapshot.report);
|
|
4329
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4330
|
+
};
|
|
4331
|
+
const unsubscribe = store.subscribe(sync);
|
|
4332
|
+
sync();
|
|
4333
|
+
store.refresh().catch(() => {});
|
|
4334
|
+
return {
|
|
4335
|
+
close: () => {
|
|
4336
|
+
unsubscribe();
|
|
4337
|
+
store.close();
|
|
4338
|
+
},
|
|
4339
|
+
error: computed22(() => errorSignal()),
|
|
4340
|
+
isLoading: computed22(() => isLoadingSignal()),
|
|
4341
|
+
refresh: store.refresh,
|
|
4342
|
+
report: computed22(() => reportSignal()),
|
|
4343
|
+
updatedAt: computed22(() => updatedAtSignal())
|
|
4344
|
+
};
|
|
4345
|
+
}
|
|
4346
|
+
}
|
|
4347
|
+
VoiceProviderCapabilitiesService = __decorateElement(_init, 0, "VoiceProviderCapabilitiesService", _dec, VoiceProviderCapabilitiesService);
|
|
4348
|
+
__runInitializers(_init, 1, VoiceProviderCapabilitiesService);
|
|
4349
|
+
__decoratorMetadata(_init, VoiceProviderCapabilitiesService);
|
|
4350
|
+
let _VoiceProviderCapabilitiesService = VoiceProviderCapabilitiesService;
|
|
4351
|
+
// src/angular/voice-provider-contracts.service.ts
|
|
4352
|
+
import { computed as computed23, Injectable as Injectable23, signal as signal23 } from "@angular/core";
|
|
4353
|
+
|
|
4354
|
+
// src/client/providerContracts.ts
|
|
4355
|
+
var fetchVoiceProviderContracts = async (path = "/api/provider-contracts", options = {}) => {
|
|
4356
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4357
|
+
const response = await fetchImpl(path);
|
|
4358
|
+
if (!response.ok) {
|
|
4359
|
+
throw new Error(`Voice provider contracts failed: HTTP ${response.status}`);
|
|
4360
|
+
}
|
|
4361
|
+
return await response.json();
|
|
4362
|
+
};
|
|
4363
|
+
var createVoiceProviderContractsStore = (path = "/api/provider-contracts", options = {}) => {
|
|
4364
|
+
const listeners = new Set;
|
|
4365
|
+
let closed = false;
|
|
4366
|
+
let timer;
|
|
4367
|
+
let snapshot = {
|
|
4368
|
+
error: null,
|
|
4369
|
+
isLoading: false
|
|
4370
|
+
};
|
|
4371
|
+
const emit = () => {
|
|
4372
|
+
for (const listener of listeners) {
|
|
4373
|
+
listener();
|
|
4374
|
+
}
|
|
4375
|
+
};
|
|
4376
|
+
const refresh = async () => {
|
|
4377
|
+
if (closed) {
|
|
4378
|
+
return snapshot.report;
|
|
4379
|
+
}
|
|
4380
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
4381
|
+
emit();
|
|
4382
|
+
try {
|
|
4383
|
+
const report = await fetchVoiceProviderContracts(path, options);
|
|
4384
|
+
snapshot = {
|
|
4385
|
+
error: null,
|
|
4386
|
+
isLoading: false,
|
|
4387
|
+
report,
|
|
4388
|
+
updatedAt: Date.now()
|
|
4389
|
+
};
|
|
4390
|
+
emit();
|
|
4391
|
+
return report;
|
|
4392
|
+
} catch (error) {
|
|
4393
|
+
snapshot = {
|
|
4394
|
+
...snapshot,
|
|
4395
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4396
|
+
isLoading: false
|
|
4397
|
+
};
|
|
4398
|
+
emit();
|
|
4399
|
+
throw error;
|
|
4400
|
+
}
|
|
4401
|
+
};
|
|
4402
|
+
const close = () => {
|
|
4403
|
+
closed = true;
|
|
4404
|
+
if (timer) {
|
|
4405
|
+
clearInterval(timer);
|
|
4406
|
+
timer = undefined;
|
|
4407
|
+
}
|
|
4408
|
+
listeners.clear();
|
|
4409
|
+
};
|
|
4410
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
4411
|
+
timer = setInterval(() => {
|
|
4412
|
+
refresh().catch(() => {});
|
|
4413
|
+
}, options.intervalMs);
|
|
4414
|
+
}
|
|
4415
|
+
return {
|
|
4416
|
+
close,
|
|
4417
|
+
getServerSnapshot: () => snapshot,
|
|
4418
|
+
getSnapshot: () => snapshot,
|
|
4419
|
+
refresh,
|
|
4420
|
+
subscribe: (listener) => {
|
|
4421
|
+
listeners.add(listener);
|
|
4422
|
+
return () => {
|
|
4423
|
+
listeners.delete(listener);
|
|
4424
|
+
};
|
|
4425
|
+
}
|
|
4426
|
+
};
|
|
4427
|
+
};
|
|
4428
|
+
|
|
4429
|
+
// src/angular/voice-provider-contracts.service.ts
|
|
4430
|
+
var _dec = [
|
|
4431
|
+
Injectable23({ providedIn: "root" })
|
|
4432
|
+
];
|
|
4433
|
+
var _init = __decoratorStart(undefined);
|
|
4434
|
+
|
|
4435
|
+
class VoiceProviderContractsService {
|
|
4436
|
+
connect(path = "/api/provider-contracts", options = {}) {
|
|
4437
|
+
const store = createVoiceProviderContractsStore(path, options);
|
|
4438
|
+
const errorSignal = signal23(null);
|
|
4439
|
+
const isLoadingSignal = signal23(false);
|
|
4440
|
+
const reportSignal = signal23(undefined);
|
|
4441
|
+
const updatedAtSignal = signal23(undefined);
|
|
4442
|
+
const sync = () => {
|
|
4443
|
+
const snapshot = store.getSnapshot();
|
|
4444
|
+
errorSignal.set(snapshot.error);
|
|
4445
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4446
|
+
reportSignal.set(snapshot.report);
|
|
4447
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4448
|
+
};
|
|
4449
|
+
const unsubscribe = store.subscribe(sync);
|
|
4450
|
+
sync();
|
|
4451
|
+
store.refresh().catch(() => {});
|
|
4452
|
+
return {
|
|
4453
|
+
close: () => {
|
|
4454
|
+
unsubscribe();
|
|
4455
|
+
store.close();
|
|
4456
|
+
},
|
|
4457
|
+
error: computed23(() => errorSignal()),
|
|
4458
|
+
isLoading: computed23(() => isLoadingSignal()),
|
|
4459
|
+
refresh: store.refresh,
|
|
4460
|
+
report: computed23(() => reportSignal()),
|
|
4461
|
+
updatedAt: computed23(() => updatedAtSignal())
|
|
4462
|
+
};
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
VoiceProviderContractsService = __decorateElement(_init, 0, "VoiceProviderContractsService", _dec, VoiceProviderContractsService);
|
|
4466
|
+
__runInitializers(_init, 1, VoiceProviderContractsService);
|
|
4467
|
+
__decoratorMetadata(_init, VoiceProviderContractsService);
|
|
4468
|
+
let _VoiceProviderContractsService = VoiceProviderContractsService;
|
|
4469
|
+
// src/angular/voice-provider-status.service.ts
|
|
4470
|
+
import { computed as computed24, Injectable as Injectable24, signal as signal24 } from "@angular/core";
|
|
4471
|
+
|
|
4472
|
+
// src/client/providerStatus.ts
|
|
4473
|
+
var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
|
|
4474
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4475
|
+
const response = await fetchImpl(path);
|
|
4476
|
+
if (!response.ok) {
|
|
4477
|
+
throw new Error(`Voice provider status failed: HTTP ${response.status}`);
|
|
4478
|
+
}
|
|
4479
|
+
return await response.json();
|
|
4480
|
+
};
|
|
4481
|
+
var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {}) => {
|
|
4482
|
+
const listeners = new Set;
|
|
4483
|
+
let closed = false;
|
|
4484
|
+
let timer;
|
|
4485
|
+
let snapshot = {
|
|
4486
|
+
error: null,
|
|
4487
|
+
isLoading: false,
|
|
4488
|
+
providers: []
|
|
4489
|
+
};
|
|
4490
|
+
const emit = () => {
|
|
4491
|
+
for (const listener of listeners) {
|
|
4492
|
+
listener();
|
|
4493
|
+
}
|
|
4494
|
+
};
|
|
4495
|
+
const refresh = async () => {
|
|
4496
|
+
if (closed) {
|
|
4497
|
+
return snapshot.providers;
|
|
4498
|
+
}
|
|
4499
|
+
snapshot = {
|
|
4500
|
+
...snapshot,
|
|
4501
|
+
error: null,
|
|
4502
|
+
isLoading: true
|
|
4503
|
+
};
|
|
4504
|
+
emit();
|
|
4505
|
+
try {
|
|
4506
|
+
const providers = await fetchVoiceProviderStatus(path, options);
|
|
4507
|
+
snapshot = {
|
|
4508
|
+
error: null,
|
|
4509
|
+
isLoading: false,
|
|
4510
|
+
providers,
|
|
4511
|
+
updatedAt: Date.now()
|
|
4512
|
+
};
|
|
4513
|
+
emit();
|
|
4514
|
+
return providers;
|
|
4515
|
+
} catch (error) {
|
|
4516
|
+
snapshot = {
|
|
4517
|
+
...snapshot,
|
|
4518
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4519
|
+
isLoading: false
|
|
4520
|
+
};
|
|
4521
|
+
emit();
|
|
4522
|
+
throw error;
|
|
4523
|
+
}
|
|
4524
|
+
};
|
|
4525
|
+
const close = () => {
|
|
4526
|
+
closed = true;
|
|
4527
|
+
if (timer) {
|
|
4528
|
+
clearInterval(timer);
|
|
4529
|
+
timer = undefined;
|
|
4530
|
+
}
|
|
4531
|
+
listeners.clear();
|
|
4532
|
+
};
|
|
4533
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
4534
|
+
timer = setInterval(() => {
|
|
4535
|
+
refresh().catch(() => {});
|
|
4536
|
+
}, options.intervalMs);
|
|
4537
|
+
}
|
|
4538
|
+
return {
|
|
4539
|
+
close,
|
|
4540
|
+
getServerSnapshot: () => snapshot,
|
|
4541
|
+
getSnapshot: () => snapshot,
|
|
4542
|
+
refresh,
|
|
4543
|
+
subscribe: (listener) => {
|
|
4544
|
+
listeners.add(listener);
|
|
4545
|
+
return () => {
|
|
4546
|
+
listeners.delete(listener);
|
|
4547
|
+
};
|
|
4548
|
+
}
|
|
4549
|
+
};
|
|
4550
|
+
};
|
|
4551
|
+
|
|
4552
|
+
// src/angular/voice-provider-status.service.ts
|
|
4553
|
+
var _dec = [
|
|
4554
|
+
Injectable24({ providedIn: "root" })
|
|
4555
|
+
];
|
|
4556
|
+
var _init = __decoratorStart(undefined);
|
|
4557
|
+
|
|
4558
|
+
class VoiceProviderStatusService {
|
|
4559
|
+
connect(path = "/api/provider-status", options = {}) {
|
|
4560
|
+
const store = createVoiceProviderStatusStore(path, options);
|
|
4561
|
+
const errorSignal = signal24(null);
|
|
4562
|
+
const isLoadingSignal = signal24(false);
|
|
4563
|
+
const providersSignal = signal24([]);
|
|
4564
|
+
const updatedAtSignal = signal24(undefined);
|
|
4565
|
+
const sync = () => {
|
|
4566
|
+
const snapshot = store.getSnapshot();
|
|
4567
|
+
errorSignal.set(snapshot.error);
|
|
4568
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4569
|
+
providersSignal.set([...snapshot.providers]);
|
|
4570
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4571
|
+
};
|
|
4572
|
+
const unsubscribe = store.subscribe(sync);
|
|
4573
|
+
sync();
|
|
4574
|
+
store.refresh().catch(() => {});
|
|
4575
|
+
return {
|
|
4576
|
+
close: () => {
|
|
4577
|
+
unsubscribe();
|
|
4578
|
+
store.close();
|
|
4579
|
+
},
|
|
4580
|
+
error: computed24(() => errorSignal()),
|
|
4581
|
+
isLoading: computed24(() => isLoadingSignal()),
|
|
4582
|
+
providers: computed24(() => providersSignal()),
|
|
4583
|
+
refresh: store.refresh,
|
|
4584
|
+
updatedAt: computed24(() => updatedAtSignal())
|
|
4585
|
+
};
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
VoiceProviderStatusService = __decorateElement(_init, 0, "VoiceProviderStatusService", _dec, VoiceProviderStatusService);
|
|
4589
|
+
__runInitializers(_init, 1, VoiceProviderStatusService);
|
|
4590
|
+
__decoratorMetadata(_init, VoiceProviderStatusService);
|
|
4591
|
+
let _VoiceProviderStatusService = VoiceProviderStatusService;
|
|
4592
|
+
// src/angular/voice-routing-status.service.ts
|
|
4593
|
+
import { Injectable as Injectable25, signal as signal25 } from "@angular/core";
|
|
4594
|
+
|
|
4595
|
+
// src/client/routingStatus.ts
|
|
4596
|
+
var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
|
|
4597
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4598
|
+
const response = await fetchImpl(path);
|
|
4599
|
+
if (!response.ok) {
|
|
4600
|
+
throw new Error(`Voice routing status failed: HTTP ${response.status}`);
|
|
4601
|
+
}
|
|
4602
|
+
return await response.json();
|
|
4603
|
+
};
|
|
4604
|
+
var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {}) => {
|
|
4605
|
+
const listeners = new Set;
|
|
4606
|
+
let closed = false;
|
|
4607
|
+
let timer;
|
|
4608
|
+
let snapshot = {
|
|
4609
|
+
decision: null,
|
|
4610
|
+
error: null,
|
|
4611
|
+
isLoading: false
|
|
4612
|
+
};
|
|
4613
|
+
const emit = () => {
|
|
4614
|
+
for (const listener of listeners) {
|
|
4615
|
+
listener();
|
|
4616
|
+
}
|
|
4617
|
+
};
|
|
4618
|
+
const refresh = async () => {
|
|
4619
|
+
if (closed) {
|
|
4620
|
+
return snapshot.decision;
|
|
4621
|
+
}
|
|
4622
|
+
snapshot = {
|
|
4623
|
+
...snapshot,
|
|
4624
|
+
error: null,
|
|
4625
|
+
isLoading: true
|
|
4626
|
+
};
|
|
4627
|
+
emit();
|
|
4628
|
+
try {
|
|
4629
|
+
const decision = await fetchVoiceRoutingStatus(path, options);
|
|
4630
|
+
snapshot = {
|
|
4631
|
+
decision,
|
|
4632
|
+
error: null,
|
|
4633
|
+
isLoading: false,
|
|
4634
|
+
updatedAt: Date.now()
|
|
4635
|
+
};
|
|
4636
|
+
emit();
|
|
4637
|
+
return decision;
|
|
4638
|
+
} catch (error) {
|
|
4639
|
+
snapshot = {
|
|
4640
|
+
...snapshot,
|
|
4641
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4642
|
+
isLoading: false
|
|
4643
|
+
};
|
|
4644
|
+
emit();
|
|
4645
|
+
throw error;
|
|
4646
|
+
}
|
|
4647
|
+
};
|
|
4648
|
+
const close = () => {
|
|
4649
|
+
closed = true;
|
|
4650
|
+
if (timer) {
|
|
4651
|
+
clearInterval(timer);
|
|
4652
|
+
timer = undefined;
|
|
4653
|
+
}
|
|
4654
|
+
listeners.clear();
|
|
4655
|
+
};
|
|
4656
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
4657
|
+
timer = setInterval(() => {
|
|
4658
|
+
refresh().catch(() => {});
|
|
4659
|
+
}, options.intervalMs);
|
|
4660
|
+
}
|
|
4661
|
+
return {
|
|
4662
|
+
close,
|
|
4663
|
+
getServerSnapshot: () => snapshot,
|
|
4664
|
+
getSnapshot: () => snapshot,
|
|
4665
|
+
refresh,
|
|
4666
|
+
subscribe: (listener) => {
|
|
4667
|
+
listeners.add(listener);
|
|
4668
|
+
return () => {
|
|
4669
|
+
listeners.delete(listener);
|
|
4670
|
+
};
|
|
4671
|
+
}
|
|
4672
|
+
};
|
|
4673
|
+
};
|
|
4674
|
+
|
|
4675
|
+
// src/angular/voice-routing-status.service.ts
|
|
4676
|
+
var _dec = [
|
|
4677
|
+
Injectable25({ providedIn: "root" })
|
|
4678
|
+
];
|
|
4679
|
+
var _init = __decoratorStart(undefined);
|
|
4680
|
+
|
|
4681
|
+
class VoiceRoutingStatusService {
|
|
4682
|
+
connect(path = "/api/routing/latest", options = {}) {
|
|
4683
|
+
const store = createVoiceRoutingStatusStore(path, options);
|
|
4684
|
+
const decisionSignal = signal25(null);
|
|
4685
|
+
const errorSignal = signal25(null);
|
|
4686
|
+
const isLoadingSignal = signal25(false);
|
|
4687
|
+
const updatedAtSignal = signal25(undefined);
|
|
4688
|
+
const sync = () => {
|
|
4689
|
+
const snapshot = store.getSnapshot();
|
|
4690
|
+
decisionSignal.set(snapshot.decision);
|
|
4691
|
+
errorSignal.set(snapshot.error);
|
|
4692
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4693
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4694
|
+
};
|
|
4695
|
+
const unsubscribe = store.subscribe(sync);
|
|
4696
|
+
sync();
|
|
4697
|
+
store.refresh().catch(() => {});
|
|
4698
|
+
return {
|
|
4699
|
+
close: () => {
|
|
4700
|
+
unsubscribe();
|
|
4701
|
+
store.close();
|
|
4702
|
+
},
|
|
4703
|
+
decision: decisionSignal.asReadonly(),
|
|
4704
|
+
error: errorSignal.asReadonly(),
|
|
4705
|
+
isLoading: isLoadingSignal.asReadonly(),
|
|
4706
|
+
refresh: store.refresh,
|
|
4707
|
+
updatedAt: updatedAtSignal.asReadonly()
|
|
4708
|
+
};
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
VoiceRoutingStatusService = __decorateElement(_init, 0, "VoiceRoutingStatusService", _dec, VoiceRoutingStatusService);
|
|
4712
|
+
__runInitializers(_init, 1, VoiceRoutingStatusService);
|
|
4713
|
+
__decoratorMetadata(_init, VoiceRoutingStatusService);
|
|
4714
|
+
let _VoiceRoutingStatusService = VoiceRoutingStatusService;
|
|
4715
|
+
// src/angular/voice-trace-timeline.service.ts
|
|
4716
|
+
import { computed as computed25, Injectable as Injectable26, signal as signal26 } from "@angular/core";
|
|
4717
|
+
|
|
4718
|
+
// src/client/traceTimeline.ts
|
|
4719
|
+
var fetchVoiceTraceTimeline = async (path = "/api/voice-traces", options = {}) => {
|
|
4720
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4721
|
+
const response = await fetchImpl(path);
|
|
4722
|
+
if (!response.ok) {
|
|
4723
|
+
throw new Error(`Voice trace timeline failed: HTTP ${response.status}`);
|
|
4724
|
+
}
|
|
4725
|
+
return await response.json();
|
|
4726
|
+
};
|
|
4727
|
+
var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) => {
|
|
4728
|
+
const listeners = new Set;
|
|
4729
|
+
let closed = false;
|
|
4730
|
+
let timer;
|
|
4731
|
+
let snapshot = {
|
|
4732
|
+
error: null,
|
|
4733
|
+
isLoading: false,
|
|
4734
|
+
report: null
|
|
4735
|
+
};
|
|
4736
|
+
const emit = () => {
|
|
4737
|
+
for (const listener of listeners) {
|
|
4738
|
+
listener();
|
|
4739
|
+
}
|
|
4740
|
+
};
|
|
4741
|
+
const refresh = async () => {
|
|
4742
|
+
if (closed) {
|
|
4743
|
+
return snapshot.report;
|
|
4744
|
+
}
|
|
4745
|
+
snapshot = {
|
|
4746
|
+
...snapshot,
|
|
4747
|
+
error: null,
|
|
4748
|
+
isLoading: true
|
|
4749
|
+
};
|
|
4750
|
+
emit();
|
|
4751
|
+
try {
|
|
4752
|
+
const report = await fetchVoiceTraceTimeline(path, options);
|
|
4753
|
+
snapshot = {
|
|
4754
|
+
error: null,
|
|
4755
|
+
isLoading: false,
|
|
4756
|
+
report,
|
|
4757
|
+
updatedAt: Date.now()
|
|
4758
|
+
};
|
|
4759
|
+
emit();
|
|
4760
|
+
return report;
|
|
4761
|
+
} catch (error) {
|
|
4762
|
+
snapshot = {
|
|
4763
|
+
...snapshot,
|
|
4764
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4765
|
+
isLoading: false
|
|
4766
|
+
};
|
|
4767
|
+
emit();
|
|
4768
|
+
throw error;
|
|
4769
|
+
}
|
|
4770
|
+
};
|
|
4771
|
+
const close = () => {
|
|
4772
|
+
closed = true;
|
|
4773
|
+
if (timer) {
|
|
4774
|
+
clearInterval(timer);
|
|
4775
|
+
timer = undefined;
|
|
4776
|
+
}
|
|
4777
|
+
listeners.clear();
|
|
4778
|
+
};
|
|
4779
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
4780
|
+
timer = setInterval(() => {
|
|
4781
|
+
refresh().catch(() => {});
|
|
4782
|
+
}, options.intervalMs);
|
|
4783
|
+
}
|
|
4784
|
+
return {
|
|
4785
|
+
close,
|
|
4786
|
+
getServerSnapshot: () => snapshot,
|
|
4787
|
+
getSnapshot: () => snapshot,
|
|
4788
|
+
refresh,
|
|
4789
|
+
subscribe: (listener) => {
|
|
4790
|
+
listeners.add(listener);
|
|
4791
|
+
return () => {
|
|
4792
|
+
listeners.delete(listener);
|
|
4793
|
+
};
|
|
4794
|
+
}
|
|
4795
|
+
};
|
|
4796
|
+
};
|
|
4797
|
+
|
|
4798
|
+
// src/angular/voice-trace-timeline.service.ts
|
|
4799
|
+
var _dec = [
|
|
4800
|
+
Injectable26({ providedIn: "root" })
|
|
4801
|
+
];
|
|
4802
|
+
var _init = __decoratorStart(undefined);
|
|
4803
|
+
|
|
4804
|
+
class VoiceTraceTimelineService {
|
|
4805
|
+
connect(path = "/api/voice-traces", options = {}) {
|
|
4806
|
+
const store = createVoiceTraceTimelineStore(path, options);
|
|
4807
|
+
const errorSignal = signal26(null);
|
|
4808
|
+
const isLoadingSignal = signal26(false);
|
|
4809
|
+
const reportSignal = signal26(null);
|
|
4810
|
+
const updatedAtSignal = signal26(undefined);
|
|
4811
|
+
const sync = () => {
|
|
4812
|
+
const snapshot = store.getSnapshot();
|
|
4813
|
+
errorSignal.set(snapshot.error);
|
|
4814
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4815
|
+
reportSignal.set(snapshot.report);
|
|
4816
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4817
|
+
};
|
|
4818
|
+
const unsubscribe = store.subscribe(sync);
|
|
4819
|
+
sync();
|
|
4820
|
+
store.refresh().catch(() => {});
|
|
4821
|
+
return {
|
|
4822
|
+
close: () => {
|
|
4823
|
+
unsubscribe();
|
|
4824
|
+
store.close();
|
|
4825
|
+
},
|
|
4826
|
+
error: computed25(() => errorSignal()),
|
|
4827
|
+
isLoading: computed25(() => isLoadingSignal()),
|
|
4828
|
+
refresh: store.refresh,
|
|
4829
|
+
report: computed25(() => reportSignal()),
|
|
4830
|
+
updatedAt: computed25(() => updatedAtSignal())
|
|
4831
|
+
};
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
VoiceTraceTimelineService = __decorateElement(_init, 0, "VoiceTraceTimelineService", _dec, VoiceTraceTimelineService);
|
|
4835
|
+
__runInitializers(_init, 1, VoiceTraceTimelineService);
|
|
4836
|
+
__decoratorMetadata(_init, VoiceTraceTimelineService);
|
|
4837
|
+
let _VoiceTraceTimelineService = VoiceTraceTimelineService;
|
|
4838
|
+
// src/angular/voice-agent-squad-status.service.ts
|
|
4839
|
+
import { computed as computed26, Injectable as Injectable27, signal as signal27 } from "@angular/core";
|
|
4840
|
+
|
|
4841
|
+
// src/client/agentSquadStatus.ts
|
|
4842
|
+
var getString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
4843
|
+
var getPayloadString = (event, key) => getString(event.payload?.[key]);
|
|
4844
|
+
var eventStatus = (event) => {
|
|
4845
|
+
const status = getPayloadString(event, "status");
|
|
4846
|
+
if (status === "blocked")
|
|
4847
|
+
return "blocked";
|
|
4848
|
+
if (status === "unknown-target")
|
|
4849
|
+
return "unknown-target";
|
|
4850
|
+
if (status === "allowed")
|
|
4851
|
+
return "handoff";
|
|
4852
|
+
return event.type === "agent.result" ? "active" : "handoff";
|
|
4853
|
+
};
|
|
4854
|
+
var deriveSessionSpecialist = (session) => {
|
|
4855
|
+
const events = [...session.events].sort((left, right) => left.at - right.at);
|
|
4856
|
+
const agentEvents = events.filter((event) => event.type === "agent.handoff" || event.type === "agent.context" || event.type === "agent.result" || event.type === "agent.model");
|
|
4857
|
+
const latest = agentEvents.at(-1);
|
|
4858
|
+
if (!latest) {
|
|
4859
|
+
return {
|
|
4860
|
+
lastEventAt: session.lastEventAt,
|
|
4861
|
+
sessionId: session.sessionId,
|
|
4862
|
+
status: "idle"
|
|
4863
|
+
};
|
|
4864
|
+
}
|
|
4865
|
+
const handoffEvents = events.filter((event) => event.type === "agent.handoff");
|
|
4866
|
+
const lastHandoff = handoffEvents.at(-1);
|
|
4867
|
+
const latestAgentId = getPayloadString(latest, "agentId");
|
|
4868
|
+
const handoffStatus = lastHandoff ? eventStatus(lastHandoff) : undefined;
|
|
4869
|
+
const currentTarget = handoffStatus === "blocked" || handoffStatus === "unknown-target" ? getPayloadString(lastHandoff, "fromAgentId") ?? latestAgentId : getPayloadString(lastHandoff ?? latest, "targetAgentId") ?? latestAgentId;
|
|
4870
|
+
return {
|
|
4871
|
+
fromAgentId: getPayloadString(lastHandoff ?? latest, "fromAgentId"),
|
|
4872
|
+
lastEventAt: latest.at,
|
|
4873
|
+
reason: getPayloadString(lastHandoff ?? latest, "reason") ?? getPayloadString(latest, "handoffTarget"),
|
|
4874
|
+
sessionId: session.sessionId,
|
|
4875
|
+
status: lastHandoff ? eventStatus(lastHandoff) : "active",
|
|
4876
|
+
summary: getPayloadString(lastHandoff ?? latest, "summary"),
|
|
4877
|
+
targetAgentId: currentTarget,
|
|
4878
|
+
turnId: latest.turnId
|
|
4879
|
+
};
|
|
4880
|
+
};
|
|
4881
|
+
var buildVoiceAgentSquadStatusReport = (timeline, options = {}) => {
|
|
4882
|
+
const sessions = (timeline?.sessions ?? []).filter((session) => !options.sessionId || session.sessionId === options.sessionId).map(deriveSessionSpecialist).sort((left, right) => (right.lastEventAt ?? 0) - (left.lastEventAt ?? 0));
|
|
4883
|
+
const active = sessions.filter((session) => session.status !== "idle");
|
|
4884
|
+
return {
|
|
4885
|
+
active,
|
|
4886
|
+
checkedAt: timeline?.checkedAt,
|
|
4887
|
+
current: active[0] ?? sessions[0],
|
|
4888
|
+
sessionCount: sessions.length,
|
|
4889
|
+
sessions
|
|
4890
|
+
};
|
|
4891
|
+
};
|
|
4892
|
+
var createVoiceAgentSquadStatusStore = (path = "/api/voice-traces", options = {}) => {
|
|
4893
|
+
const timelineStore = createVoiceTraceTimelineStore(path, options);
|
|
4894
|
+
const getReport = () => buildVoiceAgentSquadStatusReport(timelineStore.getSnapshot().report, {
|
|
4895
|
+
sessionId: options.sessionId
|
|
4896
|
+
});
|
|
4897
|
+
const getSnapshot = () => {
|
|
4898
|
+
const snapshot = timelineStore.getSnapshot();
|
|
4899
|
+
return {
|
|
4900
|
+
error: snapshot.error,
|
|
4901
|
+
isLoading: snapshot.isLoading,
|
|
4902
|
+
report: getReport(),
|
|
4903
|
+
updatedAt: snapshot.updatedAt
|
|
4904
|
+
};
|
|
4905
|
+
};
|
|
4906
|
+
return {
|
|
4907
|
+
close: timelineStore.close,
|
|
4908
|
+
getServerSnapshot: getSnapshot,
|
|
4909
|
+
getSnapshot,
|
|
4910
|
+
refresh: timelineStore.refresh,
|
|
4911
|
+
subscribe: timelineStore.subscribe
|
|
4912
|
+
};
|
|
4913
|
+
};
|
|
4914
|
+
|
|
4915
|
+
// src/angular/voice-agent-squad-status.service.ts
|
|
4916
|
+
var _dec = [
|
|
4917
|
+
Injectable27({ providedIn: "root" })
|
|
4918
|
+
];
|
|
4919
|
+
var _init = __decoratorStart(undefined);
|
|
4920
|
+
|
|
4921
|
+
class VoiceAgentSquadStatusService {
|
|
4922
|
+
connect(path = "/api/voice-traces", options = {}) {
|
|
4923
|
+
const store = createVoiceAgentSquadStatusStore(path, options);
|
|
4924
|
+
const errorSignal = signal27(null);
|
|
4925
|
+
const isLoadingSignal = signal27(false);
|
|
4926
|
+
const reportSignal = signal27(undefined);
|
|
4927
|
+
const updatedAtSignal = signal27(undefined);
|
|
4928
|
+
const sync = () => {
|
|
4929
|
+
const snapshot = store.getSnapshot();
|
|
4930
|
+
errorSignal.set(snapshot.error);
|
|
4931
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
4932
|
+
reportSignal.set(snapshot.report);
|
|
4933
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
4934
|
+
};
|
|
4935
|
+
const unsubscribe = store.subscribe(sync);
|
|
4936
|
+
sync();
|
|
4937
|
+
store.refresh().catch(() => {});
|
|
4938
|
+
return {
|
|
4939
|
+
close: () => {
|
|
4940
|
+
unsubscribe();
|
|
4941
|
+
store.close();
|
|
4942
|
+
},
|
|
4943
|
+
current: computed26(() => reportSignal()?.current),
|
|
4944
|
+
error: computed26(() => errorSignal()),
|
|
4945
|
+
isLoading: computed26(() => isLoadingSignal()),
|
|
4946
|
+
refresh: store.refresh,
|
|
4947
|
+
report: computed26(() => reportSignal()),
|
|
4948
|
+
updatedAt: computed26(() => updatedAtSignal())
|
|
4949
|
+
};
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
VoiceAgentSquadStatusService = __decorateElement(_init, 0, "VoiceAgentSquadStatusService", _dec, VoiceAgentSquadStatusService);
|
|
4953
|
+
__runInitializers(_init, 1, VoiceAgentSquadStatusService);
|
|
4954
|
+
__decoratorMetadata(_init, VoiceAgentSquadStatusService);
|
|
4955
|
+
let _VoiceAgentSquadStatusService = VoiceAgentSquadStatusService;
|
|
4956
|
+
// src/angular/voice-turn-latency.service.ts
|
|
4957
|
+
import { computed as computed27, Injectable as Injectable28, signal as signal28 } from "@angular/core";
|
|
4958
|
+
|
|
4959
|
+
// src/client/turnLatency.ts
|
|
4960
|
+
var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) => {
|
|
4961
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4962
|
+
const response = await fetchImpl(path);
|
|
4963
|
+
if (!response.ok) {
|
|
4964
|
+
throw new Error(`Voice turn latency failed: HTTP ${response.status}`);
|
|
4965
|
+
}
|
|
4966
|
+
return await response.json();
|
|
4967
|
+
};
|
|
4968
|
+
var runVoiceTurnLatencyProof = async (path, options = {}) => {
|
|
4969
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4970
|
+
const response = await fetchImpl(path, { method: "POST" });
|
|
4971
|
+
if (!response.ok) {
|
|
4972
|
+
throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
|
|
4973
|
+
}
|
|
4974
|
+
return response.json();
|
|
4975
|
+
};
|
|
4976
|
+
var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
|
|
4977
|
+
const listeners = new Set;
|
|
4978
|
+
let closed = false;
|
|
4979
|
+
let timer;
|
|
4980
|
+
let snapshot = {
|
|
4981
|
+
error: null,
|
|
4982
|
+
isLoading: false
|
|
4983
|
+
};
|
|
4984
|
+
const emit = () => {
|
|
4985
|
+
for (const listener of listeners) {
|
|
4986
|
+
listener();
|
|
4987
|
+
}
|
|
4988
|
+
};
|
|
4989
|
+
const refresh = async () => {
|
|
4990
|
+
if (closed) {
|
|
4991
|
+
return snapshot.report;
|
|
4992
|
+
}
|
|
4993
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
4994
|
+
emit();
|
|
4995
|
+
try {
|
|
4996
|
+
const report = await fetchVoiceTurnLatency(path, options);
|
|
4997
|
+
snapshot = {
|
|
4998
|
+
error: null,
|
|
4999
|
+
isLoading: false,
|
|
5000
|
+
report,
|
|
5001
|
+
updatedAt: Date.now()
|
|
5002
|
+
};
|
|
5003
|
+
emit();
|
|
5004
|
+
return report;
|
|
5005
|
+
} catch (error) {
|
|
5006
|
+
snapshot = {
|
|
5007
|
+
...snapshot,
|
|
5008
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5009
|
+
isLoading: false
|
|
5010
|
+
};
|
|
5011
|
+
emit();
|
|
5012
|
+
throw error;
|
|
5013
|
+
}
|
|
5014
|
+
};
|
|
5015
|
+
const runProof = async () => {
|
|
5016
|
+
if (!options.proofPath) {
|
|
5017
|
+
throw new Error("Voice turn latency proof path is not configured.");
|
|
5018
|
+
}
|
|
5019
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
5020
|
+
emit();
|
|
5021
|
+
try {
|
|
5022
|
+
await runVoiceTurnLatencyProof(options.proofPath, options);
|
|
5023
|
+
return await refresh();
|
|
5024
|
+
} catch (error) {
|
|
1508
5025
|
snapshot = {
|
|
1509
5026
|
...snapshot,
|
|
1510
5027
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -1532,6 +5049,7 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1532
5049
|
getServerSnapshot: () => snapshot,
|
|
1533
5050
|
getSnapshot: () => snapshot,
|
|
1534
5051
|
refresh,
|
|
5052
|
+
runProof,
|
|
1535
5053
|
subscribe: (listener) => {
|
|
1536
5054
|
listeners.add(listener);
|
|
1537
5055
|
return () => {
|
|
@@ -1541,24 +5059,24 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1541
5059
|
};
|
|
1542
5060
|
};
|
|
1543
5061
|
|
|
1544
|
-
// src/angular/voice-
|
|
5062
|
+
// src/angular/voice-turn-latency.service.ts
|
|
1545
5063
|
var _dec = [
|
|
1546
|
-
|
|
5064
|
+
Injectable28({ providedIn: "root" })
|
|
1547
5065
|
];
|
|
1548
5066
|
var _init = __decoratorStart(undefined);
|
|
1549
5067
|
|
|
1550
|
-
class
|
|
1551
|
-
connect(path = "/api/
|
|
1552
|
-
const store =
|
|
1553
|
-
const errorSignal =
|
|
1554
|
-
const isLoadingSignal =
|
|
1555
|
-
const
|
|
1556
|
-
const updatedAtSignal =
|
|
5068
|
+
class VoiceTurnLatencyService {
|
|
5069
|
+
connect(path = "/api/turn-latency", options = {}) {
|
|
5070
|
+
const store = createVoiceTurnLatencyStore(path, options);
|
|
5071
|
+
const errorSignal = signal28(null);
|
|
5072
|
+
const isLoadingSignal = signal28(false);
|
|
5073
|
+
const reportSignal = signal28(undefined);
|
|
5074
|
+
const updatedAtSignal = signal28(undefined);
|
|
1557
5075
|
const sync = () => {
|
|
1558
5076
|
const snapshot = store.getSnapshot();
|
|
1559
5077
|
errorSignal.set(snapshot.error);
|
|
1560
5078
|
isLoadingSignal.set(snapshot.isLoading);
|
|
1561
|
-
|
|
5079
|
+
reportSignal.set(snapshot.report);
|
|
1562
5080
|
updatedAtSignal.set(snapshot.updatedAt);
|
|
1563
5081
|
};
|
|
1564
5082
|
const unsubscribe = store.subscribe(sync);
|
|
@@ -1569,20 +5087,143 @@ class VoiceProviderStatusService {
|
|
|
1569
5087
|
unsubscribe();
|
|
1570
5088
|
store.close();
|
|
1571
5089
|
},
|
|
1572
|
-
error:
|
|
1573
|
-
isLoading:
|
|
1574
|
-
providers: computed4(() => providersSignal()),
|
|
5090
|
+
error: computed27(() => errorSignal()),
|
|
5091
|
+
isLoading: computed27(() => isLoadingSignal()),
|
|
1575
5092
|
refresh: store.refresh,
|
|
1576
|
-
|
|
5093
|
+
report: computed27(() => reportSignal()),
|
|
5094
|
+
runProof: store.runProof,
|
|
5095
|
+
updatedAt: computed27(() => updatedAtSignal())
|
|
1577
5096
|
};
|
|
1578
5097
|
}
|
|
1579
5098
|
}
|
|
1580
|
-
|
|
1581
|
-
__runInitializers(_init, 1,
|
|
1582
|
-
__decoratorMetadata(_init,
|
|
1583
|
-
let
|
|
5099
|
+
VoiceTurnLatencyService = __decorateElement(_init, 0, "VoiceTurnLatencyService", _dec, VoiceTurnLatencyService);
|
|
5100
|
+
__runInitializers(_init, 1, VoiceTurnLatencyService);
|
|
5101
|
+
__decoratorMetadata(_init, VoiceTurnLatencyService);
|
|
5102
|
+
let _VoiceTurnLatencyService = VoiceTurnLatencyService;
|
|
5103
|
+
// src/angular/voice-turn-quality.service.ts
|
|
5104
|
+
import { computed as computed28, Injectable as Injectable29, signal as signal29 } from "@angular/core";
|
|
5105
|
+
|
|
5106
|
+
// src/client/turnQuality.ts
|
|
5107
|
+
var fetchVoiceTurnQuality = async (path = "/api/turn-quality", options = {}) => {
|
|
5108
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
5109
|
+
const response = await fetchImpl(path);
|
|
5110
|
+
if (!response.ok) {
|
|
5111
|
+
throw new Error(`Voice turn quality failed: HTTP ${response.status}`);
|
|
5112
|
+
}
|
|
5113
|
+
return await response.json();
|
|
5114
|
+
};
|
|
5115
|
+
var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) => {
|
|
5116
|
+
const listeners = new Set;
|
|
5117
|
+
let closed = false;
|
|
5118
|
+
let timer;
|
|
5119
|
+
let snapshot = {
|
|
5120
|
+
error: null,
|
|
5121
|
+
isLoading: false
|
|
5122
|
+
};
|
|
5123
|
+
const emit = () => {
|
|
5124
|
+
for (const listener of listeners) {
|
|
5125
|
+
listener();
|
|
5126
|
+
}
|
|
5127
|
+
};
|
|
5128
|
+
const refresh = async () => {
|
|
5129
|
+
if (closed) {
|
|
5130
|
+
return snapshot.report;
|
|
5131
|
+
}
|
|
5132
|
+
snapshot = {
|
|
5133
|
+
...snapshot,
|
|
5134
|
+
error: null,
|
|
5135
|
+
isLoading: true
|
|
5136
|
+
};
|
|
5137
|
+
emit();
|
|
5138
|
+
try {
|
|
5139
|
+
const report = await fetchVoiceTurnQuality(path, options);
|
|
5140
|
+
snapshot = {
|
|
5141
|
+
error: null,
|
|
5142
|
+
isLoading: false,
|
|
5143
|
+
report,
|
|
5144
|
+
updatedAt: Date.now()
|
|
5145
|
+
};
|
|
5146
|
+
emit();
|
|
5147
|
+
return report;
|
|
5148
|
+
} catch (error) {
|
|
5149
|
+
snapshot = {
|
|
5150
|
+
...snapshot,
|
|
5151
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5152
|
+
isLoading: false
|
|
5153
|
+
};
|
|
5154
|
+
emit();
|
|
5155
|
+
throw error;
|
|
5156
|
+
}
|
|
5157
|
+
};
|
|
5158
|
+
const close = () => {
|
|
5159
|
+
closed = true;
|
|
5160
|
+
if (timer) {
|
|
5161
|
+
clearInterval(timer);
|
|
5162
|
+
timer = undefined;
|
|
5163
|
+
}
|
|
5164
|
+
listeners.clear();
|
|
5165
|
+
};
|
|
5166
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
5167
|
+
timer = setInterval(() => {
|
|
5168
|
+
refresh().catch(() => {});
|
|
5169
|
+
}, options.intervalMs);
|
|
5170
|
+
}
|
|
5171
|
+
return {
|
|
5172
|
+
close,
|
|
5173
|
+
getServerSnapshot: () => snapshot,
|
|
5174
|
+
getSnapshot: () => snapshot,
|
|
5175
|
+
refresh,
|
|
5176
|
+
subscribe: (listener) => {
|
|
5177
|
+
listeners.add(listener);
|
|
5178
|
+
return () => {
|
|
5179
|
+
listeners.delete(listener);
|
|
5180
|
+
};
|
|
5181
|
+
}
|
|
5182
|
+
};
|
|
5183
|
+
};
|
|
5184
|
+
|
|
5185
|
+
// src/angular/voice-turn-quality.service.ts
|
|
5186
|
+
var _dec = [
|
|
5187
|
+
Injectable29({ providedIn: "root" })
|
|
5188
|
+
];
|
|
5189
|
+
var _init = __decoratorStart(undefined);
|
|
5190
|
+
|
|
5191
|
+
class VoiceTurnQualityService {
|
|
5192
|
+
connect(path = "/api/turn-quality", options = {}) {
|
|
5193
|
+
const store = createVoiceTurnQualityStore(path, options);
|
|
5194
|
+
const errorSignal = signal29(null);
|
|
5195
|
+
const isLoadingSignal = signal29(false);
|
|
5196
|
+
const reportSignal = signal29(undefined);
|
|
5197
|
+
const updatedAtSignal = signal29(undefined);
|
|
5198
|
+
const sync = () => {
|
|
5199
|
+
const snapshot = store.getSnapshot();
|
|
5200
|
+
errorSignal.set(snapshot.error);
|
|
5201
|
+
isLoadingSignal.set(snapshot.isLoading);
|
|
5202
|
+
reportSignal.set(snapshot.report);
|
|
5203
|
+
updatedAtSignal.set(snapshot.updatedAt);
|
|
5204
|
+
};
|
|
5205
|
+
const unsubscribe = store.subscribe(sync);
|
|
5206
|
+
sync();
|
|
5207
|
+
store.refresh().catch(() => {});
|
|
5208
|
+
return {
|
|
5209
|
+
close: () => {
|
|
5210
|
+
unsubscribe();
|
|
5211
|
+
store.close();
|
|
5212
|
+
},
|
|
5213
|
+
error: computed28(() => errorSignal()),
|
|
5214
|
+
isLoading: computed28(() => isLoadingSignal()),
|
|
5215
|
+
refresh: store.refresh,
|
|
5216
|
+
report: computed28(() => reportSignal()),
|
|
5217
|
+
updatedAt: computed28(() => updatedAtSignal())
|
|
5218
|
+
};
|
|
5219
|
+
}
|
|
5220
|
+
}
|
|
5221
|
+
VoiceTurnQualityService = __decorateElement(_init, 0, "VoiceTurnQualityService", _dec, VoiceTurnQualityService);
|
|
5222
|
+
__runInitializers(_init, 1, VoiceTurnQualityService);
|
|
5223
|
+
__decoratorMetadata(_init, VoiceTurnQualityService);
|
|
5224
|
+
let _VoiceTurnQualityService = VoiceTurnQualityService;
|
|
1584
5225
|
// src/angular/voice-workflow-status.service.ts
|
|
1585
|
-
import { computed as
|
|
5226
|
+
import { computed as computed29, Injectable as Injectable30, signal as signal30 } from "@angular/core";
|
|
1586
5227
|
|
|
1587
5228
|
// src/client/workflowStatus.ts
|
|
1588
5229
|
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
@@ -1665,17 +5306,17 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
|
|
|
1665
5306
|
|
|
1666
5307
|
// src/angular/voice-workflow-status.service.ts
|
|
1667
5308
|
var _dec = [
|
|
1668
|
-
|
|
5309
|
+
Injectable30({ providedIn: "root" })
|
|
1669
5310
|
];
|
|
1670
5311
|
var _init = __decoratorStart(undefined);
|
|
1671
5312
|
|
|
1672
5313
|
class VoiceWorkflowStatusService {
|
|
1673
5314
|
connect(path = "/evals/scenarios/json", options = {}) {
|
|
1674
5315
|
const store = createVoiceWorkflowStatusStore(path, options);
|
|
1675
|
-
const errorSignal =
|
|
1676
|
-
const isLoadingSignal =
|
|
1677
|
-
const reportSignal =
|
|
1678
|
-
const updatedAtSignal =
|
|
5316
|
+
const errorSignal = signal30(null);
|
|
5317
|
+
const isLoadingSignal = signal30(false);
|
|
5318
|
+
const reportSignal = signal30(undefined);
|
|
5319
|
+
const updatedAtSignal = signal30(undefined);
|
|
1679
5320
|
const sync = () => {
|
|
1680
5321
|
const snapshot = store.getSnapshot();
|
|
1681
5322
|
errorSignal.set(snapshot.error);
|
|
@@ -1693,11 +5334,11 @@ class VoiceWorkflowStatusService {
|
|
|
1693
5334
|
unsubscribe();
|
|
1694
5335
|
store.close();
|
|
1695
5336
|
},
|
|
1696
|
-
error:
|
|
1697
|
-
isLoading:
|
|
5337
|
+
error: computed29(() => errorSignal()),
|
|
5338
|
+
isLoading: computed29(() => isLoadingSignal()),
|
|
1698
5339
|
refresh: store.refresh,
|
|
1699
|
-
report:
|
|
1700
|
-
updatedAt:
|
|
5340
|
+
report: computed29(() => reportSignal()),
|
|
5341
|
+
updatedAt: computed29(() => updatedAtSignal())
|
|
1701
5342
|
};
|
|
1702
5343
|
}
|
|
1703
5344
|
}
|
|
@@ -1707,8 +5348,33 @@ __decoratorMetadata(_init, VoiceWorkflowStatusService);
|
|
|
1707
5348
|
let _VoiceWorkflowStatusService = VoiceWorkflowStatusService;
|
|
1708
5349
|
export {
|
|
1709
5350
|
VoiceWorkflowStatusService,
|
|
5351
|
+
VoiceWidgetService,
|
|
5352
|
+
VoiceTurnQualityService,
|
|
5353
|
+
VoiceTurnLatencyService,
|
|
5354
|
+
VoiceTraceTimelineService,
|
|
1710
5355
|
VoiceStreamService,
|
|
5356
|
+
VoiceSessionSnapshotService,
|
|
5357
|
+
VoiceSessionObservabilityService,
|
|
5358
|
+
VoiceRoutingStatusService,
|
|
5359
|
+
VoiceReplayTimelineService,
|
|
5360
|
+
VoiceReconnectProfileEvidenceService,
|
|
5361
|
+
VoiceReadinessFailuresService,
|
|
1711
5362
|
VoiceProviderStatusService,
|
|
5363
|
+
VoiceProviderContractsService,
|
|
5364
|
+
VoiceProviderCapabilitiesService,
|
|
5365
|
+
VoiceProofTrendsService,
|
|
5366
|
+
VoiceProfileComparisonService,
|
|
5367
|
+
VoicePlatformCoverageService,
|
|
5368
|
+
VoiceOpsStatusService,
|
|
5369
|
+
VoiceOpsActionCenterService,
|
|
5370
|
+
VoiceLiveOpsService,
|
|
5371
|
+
VoiceLiveCallViewerService,
|
|
5372
|
+
VoiceLiveAgentConsoleService,
|
|
5373
|
+
VoiceDeliveryRuntimeService,
|
|
5374
|
+
VoiceCostDashboardService,
|
|
1712
5375
|
VoiceControllerService,
|
|
1713
|
-
|
|
5376
|
+
VoiceCampaignDialerProofService,
|
|
5377
|
+
VoiceCallPlayerService,
|
|
5378
|
+
VoiceCallDebuggerService,
|
|
5379
|
+
VoiceAgentSquadStatusService
|
|
1714
5380
|
};
|