@absolutejs/voice 0.0.22-beta.54 → 0.0.22-beta.540

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.
Files changed (493) hide show
  1. package/README.md +4518 -951
  2. package/dist/angular/index.d.ts +36 -5
  3. package/dist/angular/index.js +4189 -390
  4. package/dist/angular/voice-agent-squad-status.service.d.ts +12 -0
  5. package/dist/angular/voice-call-debugger.service.d.ts +12 -0
  6. package/dist/angular/voice-call-player.service.d.ts +19 -0
  7. package/dist/angular/voice-campaign-dialer-proof.service.d.ts +14 -0
  8. package/dist/angular/voice-controller.service.d.ts +3 -1
  9. package/dist/angular/voice-cost-dashboard.service.d.ts +15 -0
  10. package/dist/angular/voice-delivery-runtime.service.d.ts +16 -0
  11. package/dist/angular/voice-live-agent-console.service.d.ts +16 -0
  12. package/dist/angular/voice-live-call-viewer.service.d.ts +16 -0
  13. package/dist/angular/voice-live-ops.service.d.ts +11 -0
  14. package/dist/angular/voice-ops-action-center.service.d.ts +13 -0
  15. package/dist/angular/voice-ops-status.service.d.ts +12 -0
  16. package/dist/angular/voice-platform-coverage.service.d.ts +12 -0
  17. package/dist/angular/voice-profile-comparison.service.d.ts +12 -0
  18. package/dist/angular/voice-proof-trends.service.d.ts +12 -0
  19. package/dist/angular/voice-provider-capabilities.service.d.ts +12 -0
  20. package/dist/angular/voice-provider-contracts.service.d.ts +12 -0
  21. package/dist/angular/voice-provider-status.service.d.ts +2 -2
  22. package/dist/angular/voice-readiness-failures.service.d.ts +13 -0
  23. package/dist/angular/voice-reconnect-profile-evidence.service.d.ts +12 -0
  24. package/dist/angular/voice-replay-timeline.service.d.ts +13 -0
  25. package/dist/angular/voice-routing-status.service.d.ts +11 -0
  26. package/dist/angular/voice-session-observability.service.d.ts +12 -0
  27. package/dist/angular/voice-session-snapshot.service.d.ts +13 -0
  28. package/dist/angular/voice-stream.service.d.ts +4 -1
  29. package/dist/angular/voice-trace-timeline.service.d.ts +12 -0
  30. package/dist/angular/voice-turn-latency.service.d.ts +13 -0
  31. package/dist/angular/voice-turn-quality.service.d.ts +12 -0
  32. package/dist/angular/voice-widget.service.d.ts +18 -0
  33. package/dist/angular/voice-workflow-status.service.d.ts +2 -2
  34. package/dist/client/actions.d.ts +95 -1
  35. package/dist/client/agentSquadStatus.d.ts +37 -0
  36. package/dist/client/agentSquadStatusWidget.d.ts +24 -0
  37. package/dist/client/audioPlayer.d.ts +2 -2
  38. package/dist/client/bargeInMonitor.d.ts +7 -0
  39. package/dist/client/browserMedia.d.ts +8 -0
  40. package/dist/client/browserNoiseSuppression.d.ts +42 -0
  41. package/dist/client/browserVoiceSupport.d.ts +22 -0
  42. package/dist/client/callDebugger.d.ts +21 -0
  43. package/dist/client/callDebuggerWidget.d.ts +30 -0
  44. package/dist/client/callPlayer.d.ts +41 -0
  45. package/dist/client/campaignDialerProof.d.ts +25 -0
  46. package/dist/client/connection.d.ts +4 -3
  47. package/dist/client/controller.d.ts +1 -1
  48. package/dist/client/conversationAnalytics.d.ts +30 -0
  49. package/dist/client/costDashboard.d.ts +27 -0
  50. package/dist/client/createVoiceStream.d.ts +1 -1
  51. package/dist/client/deliveryRuntime.d.ts +36 -0
  52. package/dist/client/deliveryRuntimeWidget.d.ts +37 -0
  53. package/dist/client/duplex.d.ts +2 -2
  54. package/dist/client/htmx.d.ts +1 -1
  55. package/dist/client/htmxAttributes.d.ts +24 -0
  56. package/dist/client/htmxBootstrap.js +1029 -73
  57. package/dist/client/htmxDashboardRenderers.d.ts +71 -0
  58. package/dist/client/index.d.ts +106 -15
  59. package/dist/client/index.js +10494 -279
  60. package/dist/client/liveAgentConsole.d.ts +28 -0
  61. package/dist/client/liveCallViewer.d.ts +42 -0
  62. package/dist/client/liveOps.d.ts +22 -0
  63. package/dist/client/liveOpsWidget.d.ts +23 -0
  64. package/dist/client/liveTurnLatency.d.ts +41 -0
  65. package/dist/client/microphone.d.ts +4 -4
  66. package/dist/client/opsActionCenter.d.ts +56 -0
  67. package/dist/client/opsActionCenterWidget.d.ts +29 -0
  68. package/dist/client/opsActionHistory.d.ts +21 -0
  69. package/dist/client/opsActionHistoryWidget.d.ts +11 -0
  70. package/dist/client/opsStatus.d.ts +21 -0
  71. package/dist/client/opsStatusWidget.d.ts +10 -10
  72. package/dist/client/platformCoverage.d.ts +21 -0
  73. package/dist/client/platformCoverageWidget.d.ts +38 -0
  74. package/dist/client/profileComparison.d.ts +21 -0
  75. package/dist/client/profileComparisonWidget.d.ts +41 -0
  76. package/dist/client/profileSwitchRecommendation.d.ts +21 -0
  77. package/dist/client/profileSwitchRecommendationWidget.d.ts +12 -0
  78. package/dist/client/proofTrends.d.ts +21 -0
  79. package/dist/client/proofTrendsWidget.d.ts +38 -0
  80. package/dist/client/providerCapabilities.d.ts +21 -0
  81. package/dist/client/providerCapabilitiesWidget.d.ts +32 -0
  82. package/dist/client/providerContracts.d.ts +21 -0
  83. package/dist/client/providerContractsWidget.d.ts +37 -0
  84. package/dist/client/providerSimulationControls.d.ts +33 -0
  85. package/dist/client/providerSimulationControlsWidget.d.ts +20 -0
  86. package/dist/client/providerStatus.d.ts +5 -3
  87. package/dist/client/providerStatusWidget.d.ts +32 -0
  88. package/dist/client/reactiveSource.d.ts +8 -0
  89. package/dist/client/readinessFailures.d.ts +21 -0
  90. package/dist/client/readinessFailuresWidget.d.ts +42 -0
  91. package/dist/client/reconnectProfileEvidence.d.ts +21 -0
  92. package/dist/client/reconnectProfileEvidenceWidget.d.ts +39 -0
  93. package/dist/client/replayTimeline.d.ts +26 -0
  94. package/dist/client/routingStatus.d.ts +21 -0
  95. package/dist/client/routingStatusWidget.d.ts +32 -0
  96. package/dist/client/sessionObservability.d.ts +21 -0
  97. package/dist/client/sessionObservabilityWidget.d.ts +31 -0
  98. package/dist/client/sessionSnapshot.d.ts +23 -0
  99. package/dist/client/sessionSnapshotWidget.d.ts +33 -0
  100. package/dist/client/store.d.ts +1 -1
  101. package/dist/client/traceTimeline.d.ts +21 -0
  102. package/dist/client/traceTimelineWidget.d.ts +36 -0
  103. package/dist/client/turnLatency.d.ts +24 -0
  104. package/dist/client/turnLatencyWidget.d.ts +33 -0
  105. package/dist/client/turnQuality.d.ts +21 -0
  106. package/dist/client/turnQualityWidget.d.ts +32 -0
  107. package/dist/client/voiceWidgetView.d.ts +48 -0
  108. package/dist/client/workflowStatus.d.ts +5 -3
  109. package/dist/{agent.d.ts → core/agent.d.ts} +81 -6
  110. package/dist/core/agentPerformanceReport.d.ts +40 -0
  111. package/dist/core/agentSquadContract.d.ts +98 -0
  112. package/dist/core/agentState.d.ts +12 -0
  113. package/dist/core/agentTools.d.ts +132 -0
  114. package/dist/core/aiScorecard.d.ts +32 -0
  115. package/dist/core/aiVoiceModel.d.ts +15 -0
  116. package/dist/core/amdDetector.d.ts +25 -0
  117. package/dist/{assistant.d.ts → core/assistant.d.ts} +14 -14
  118. package/dist/core/assistantExperiment.d.ts +42 -0
  119. package/dist/{assistantHealth.d.ts → core/assistantHealth.d.ts} +9 -9
  120. package/dist/{assistantMemory.d.ts → core/assistantMemory.d.ts} +10 -10
  121. package/dist/core/assistantMode.d.ts +22 -0
  122. package/dist/{audioConditioning.d.ts → core/audioConditioning.d.ts} +2 -2
  123. package/dist/core/audit.d.ts +131 -0
  124. package/dist/core/auditDeliveryRoutes.d.ts +85 -0
  125. package/dist/core/auditExport.d.ts +34 -0
  126. package/dist/core/auditRoutes.d.ts +66 -0
  127. package/dist/core/auditSinks.d.ts +151 -0
  128. package/dist/core/backchannel.d.ts +18 -0
  129. package/dist/core/bargeInRoutes.d.ts +56 -0
  130. package/dist/core/bookingFlow.d.ts +43 -0
  131. package/dist/core/browserCallProfiles.d.ts +120 -0
  132. package/dist/core/browserMediaRoutes.d.ts +62 -0
  133. package/dist/core/calendarAdapter.d.ts +47 -0
  134. package/dist/core/calendarSlots.d.ts +35 -0
  135. package/dist/core/callDebugger.d.ts +66 -0
  136. package/dist/core/callDisposition.d.ts +38 -0
  137. package/dist/core/callQuota.d.ts +54 -0
  138. package/dist/core/callScorecard.d.ts +53 -0
  139. package/dist/core/callerCRMLinker.d.ts +29 -0
  140. package/dist/core/callerMemory.d.ts +37 -0
  141. package/dist/core/callingWindow.d.ts +26 -0
  142. package/dist/core/campaign.d.ts +795 -0
  143. package/dist/core/campaignControls.d.ts +37 -0
  144. package/dist/core/campaignDialers.d.ts +111 -0
  145. package/dist/core/campaignTemplate.d.ts +16 -0
  146. package/dist/core/competitiveCoverage.d.ts +141 -0
  147. package/dist/core/conversationSimulator.d.ts +73 -0
  148. package/dist/{correction.d.ts → core/correction.d.ts} +5 -4
  149. package/dist/core/costAccounting.d.ts +76 -0
  150. package/dist/core/costPredictor.d.ts +74 -0
  151. package/dist/core/crmCallLogger.d.ts +37 -0
  152. package/dist/core/crmContract.d.ts +70 -0
  153. package/dist/core/dataControl.d.ts +180 -0
  154. package/dist/core/defineVoiceAssistant.d.ts +68 -0
  155. package/dist/core/deliveryRuntime.d.ts +159 -0
  156. package/dist/core/deliverySinkRoutes.d.ts +117 -0
  157. package/dist/core/demoReadyRoutes.d.ts +98 -0
  158. package/dist/{diagnosticsRoutes.d.ts → core/diagnosticsRoutes.d.ts} +2 -2
  159. package/dist/core/dncRegistry.d.ts +38 -0
  160. package/dist/core/dtmfCollector.d.ts +37 -0
  161. package/dist/{evalRoutes.d.ts → core/evalRoutes.d.ts} +26 -20
  162. package/dist/{fileStore.d.ts → core/fileStore.d.ts} +34 -20
  163. package/dist/core/guardrails.d.ts +128 -0
  164. package/dist/{handoff.d.ts → core/handoff.d.ts} +10 -10
  165. package/dist/{handoffHealth.d.ts → core/handoffHealth.d.ts} +9 -9
  166. package/dist/core/holdAudio.d.ts +23 -0
  167. package/dist/{htmx.d.ts → core/htmx.d.ts} +2 -2
  168. package/dist/core/htmxDashboardRoutes.d.ts +250 -0
  169. package/dist/core/iceServers.d.ts +34 -0
  170. package/dist/core/incidentBundle.d.ts +119 -0
  171. package/dist/core/incidentTimeline.d.ts +260 -0
  172. package/dist/core/ivrPlan.d.ts +40 -0
  173. package/dist/core/latencySlo.d.ts +56 -0
  174. package/dist/core/liveCoach.d.ts +43 -0
  175. package/dist/core/liveLatency.d.ts +78 -0
  176. package/dist/core/liveOps.d.ts +190 -0
  177. package/dist/core/llmJudge.d.ts +45 -0
  178. package/dist/{logger.d.ts → core/logger.d.ts} +1 -2
  179. package/dist/core/mcpToolset.d.ts +58 -0
  180. package/dist/core/mediaPipelineRoutes.d.ts +171 -0
  181. package/dist/core/mediaPipelineSurfaces.d.ts +48 -0
  182. package/dist/{memoryStore.d.ts → core/memoryStore.d.ts} +1 -1
  183. package/dist/core/midCallSummary.d.ts +27 -0
  184. package/dist/{modelAdapters.d.ts → core/modelAdapters.d.ts} +59 -7
  185. package/dist/core/monitor.d.ts +148 -0
  186. package/dist/core/multilingualProof.d.ts +77 -0
  187. package/dist/core/noShowPredictor.d.ts +46 -0
  188. package/dist/core/oauth2TokenSource.d.ts +21 -0
  189. package/dist/core/observabilityExport.d.ts +501 -0
  190. package/dist/core/openaiTTS.d.ts +18 -0
  191. package/dist/core/operationalStatus.d.ts +87 -0
  192. package/dist/core/operationsRecord.d.ts +371 -0
  193. package/dist/{ops.d.ts → core/ops.d.ts} +70 -70
  194. package/dist/core/opsActionAuditRoutes.d.ts +99 -0
  195. package/dist/{opsConsoleRoutes.d.ts → core/opsConsoleRoutes.d.ts} +11 -8
  196. package/dist/{opsPresets.d.ts → core/opsPresets.d.ts} +2 -2
  197. package/dist/core/opsRecovery.d.ts +137 -0
  198. package/dist/{opsRuntime.d.ts → core/opsRuntime.d.ts} +6 -6
  199. package/dist/{opsSinks.d.ts → core/opsSinks.d.ts} +19 -19
  200. package/dist/core/opsStatus.d.ts +76 -0
  201. package/dist/core/opsStatusRoutes.d.ts +33 -0
  202. package/dist/{opsWebhook.d.ts → core/opsWebhook.d.ts} +15 -15
  203. package/dist/core/otelExporter.d.ts +83 -0
  204. package/dist/core/outcomeContract.d.ts +146 -0
  205. package/dist/{outcomeRecipes.d.ts → core/outcomeRecipes.d.ts} +4 -4
  206. package/dist/core/pathway.d.ts +94 -0
  207. package/dist/core/pathwayCompiler.d.ts +31 -0
  208. package/dist/core/pathwayGenerator.d.ts +27 -0
  209. package/dist/core/pathwayRuntime.d.ts +57 -0
  210. package/dist/core/pathwaySlotCollector.d.ts +29 -0
  211. package/dist/core/pathwayVisualizer.d.ts +8 -0
  212. package/dist/core/phoneAgent.d.ts +139 -0
  213. package/dist/core/phoneAgentProductionSmoke.d.ts +115 -0
  214. package/dist/core/phoneProvisioning.d.ts +29 -0
  215. package/dist/core/platformCoverage.d.ts +91 -0
  216. package/dist/{plugin.d.ts → core/plugin.d.ts} +2 -2
  217. package/dist/core/postCallAnalysis.d.ts +98 -0
  218. package/dist/core/postCallSurvey.d.ts +41 -0
  219. package/dist/{postgresStore.d.ts → core/postgresStore.d.ts} +20 -9
  220. package/dist/{presets.d.ts → core/presets.d.ts} +3 -3
  221. package/dist/core/productionReadiness.d.ts +757 -0
  222. package/dist/core/profileSwitchRecommendation.d.ts +350 -0
  223. package/dist/core/promptInjectionGuard.d.ts +30 -0
  224. package/dist/core/proofAssertions.d.ts +32 -0
  225. package/dist/core/proofPack.d.ts +211 -0
  226. package/dist/core/proofRunner.d.ts +79 -0
  227. package/dist/core/proofTrends.d.ts +966 -0
  228. package/dist/{providerAdapters.d.ts → core/providerAdapters.d.ts} +16 -5
  229. package/dist/core/providerCapabilities.d.ts +92 -0
  230. package/dist/core/providerDecisionTraces.d.ts +130 -0
  231. package/dist/{providerHealth.d.ts → core/providerHealth.d.ts} +15 -5
  232. package/dist/core/providerOrchestration.d.ts +109 -0
  233. package/dist/core/providerRouterTraces.d.ts +35 -0
  234. package/dist/core/providerRoutingContract.d.ts +71 -0
  235. package/dist/core/providerSlo.d.ts +142 -0
  236. package/dist/core/providerStackRecommendations.d.ts +188 -0
  237. package/dist/core/qualityDriftDetector.d.ts +44 -0
  238. package/dist/{qualityRoutes.d.ts → core/qualityRoutes.d.ts} +7 -7
  239. package/dist/{queue.d.ts → core/queue.d.ts} +48 -39
  240. package/dist/core/ragTool.d.ts +52 -0
  241. package/dist/core/readinessProfiles.d.ts +45 -0
  242. package/dist/core/realtimeChannel.d.ts +136 -0
  243. package/dist/core/realtimeProviderContracts.d.ts +133 -0
  244. package/dist/core/reconnectContract.d.ts +177 -0
  245. package/dist/core/recordingRedaction.d.ts +47 -0
  246. package/dist/core/recordingStore.d.ts +60 -0
  247. package/dist/core/redaction.d.ts +13 -0
  248. package/dist/core/reminderScheduler.d.ts +43 -0
  249. package/dist/{resilienceRoutes.d.ts → core/resilienceRoutes.d.ts} +45 -5
  250. package/dist/core/retention.d.ts +37 -0
  251. package/dist/core/retryPolicy.d.ts +38 -0
  252. package/dist/core/routeAuth.d.ts +58 -0
  253. package/dist/{routing.d.ts → core/routing.d.ts} +2 -2
  254. package/dist/{runtimeOps.d.ts → core/runtimeOps.d.ts} +3 -3
  255. package/dist/{s3Store.d.ts → core/s3Store.d.ts} +12 -3
  256. package/dist/core/scorecardCalibration.d.ts +31 -0
  257. package/dist/core/semanticTurn.d.ts +27 -0
  258. package/dist/{session.d.ts → core/session.d.ts} +1 -1
  259. package/dist/core/sessionObservability.d.ts +145 -0
  260. package/dist/{sessionReplay.d.ts → core/sessionReplay.d.ts} +31 -19
  261. package/dist/core/sessionSnapshot.d.ts +109 -0
  262. package/dist/core/simulationSuite.d.ts +144 -0
  263. package/dist/core/sloCalibration.d.ts +185 -0
  264. package/dist/{sqliteStore.d.ts → core/sqliteStore.d.ts} +20 -9
  265. package/dist/{store.d.ts → core/store.d.ts} +1 -1
  266. package/dist/core/supervisorPermissions.d.ts +33 -0
  267. package/dist/core/supervisorPresence.d.ts +49 -0
  268. package/dist/core/telephonyMediaRoutes.d.ts +72 -0
  269. package/dist/core/telephonyOutcome.d.ts +269 -0
  270. package/dist/core/toolContract.d.ts +161 -0
  271. package/dist/core/toolRuntime.d.ts +50 -0
  272. package/dist/{trace.d.ts → core/trace.d.ts} +61 -22
  273. package/dist/core/traceDeliveryRoutes.d.ts +86 -0
  274. package/dist/core/traceTimeline.d.ts +97 -0
  275. package/dist/core/transcriptAnnotator.d.ts +41 -0
  276. package/dist/{turnDetection.d.ts → core/turnDetection.d.ts} +1 -1
  277. package/dist/core/turnLatency.d.ts +95 -0
  278. package/dist/core/turnProfiles.d.ts +3 -0
  279. package/dist/core/turnQuality.d.ts +94 -0
  280. package/dist/{types.d.ts → core/types.d.ts} +416 -81
  281. package/dist/core/vapiAdapter.d.ts +160 -0
  282. package/dist/core/variableAnalytics.d.ts +47 -0
  283. package/dist/core/voiceConfiguration.d.ts +8 -0
  284. package/dist/core/voiceMonitoring.d.ts +444 -0
  285. package/dist/core/webhookFanout.d.ts +48 -0
  286. package/dist/core/webhookVerification.d.ts +27 -0
  287. package/dist/core/whisperChannel.d.ts +50 -0
  288. package/dist/{workflowContract.d.ts → core/workflowContract.d.ts} +21 -21
  289. package/dist/core/zeroDataRetention.d.ts +31 -0
  290. package/dist/drizzle/assistantMemory.d.ts +112 -0
  291. package/dist/drizzle/eval.d.ts +61 -0
  292. package/dist/drizzle/handoff.d.ts +62 -0
  293. package/dist/drizzle/incidentBundle.d.ts +61 -0
  294. package/dist/drizzle/index.d.ts +1105 -0
  295. package/dist/drizzle/index.js +3059 -0
  296. package/dist/drizzle/observabilityExport.d.ts +61 -0
  297. package/dist/drizzle/proofTrends.d.ts +126 -0
  298. package/dist/drizzle/runtimeStorage.d.ts +1315 -0
  299. package/dist/drizzle/shared.d.ts +76 -0
  300. package/dist/embed/index.d.ts +38 -0
  301. package/dist/embed/index.js +1710 -0
  302. package/dist/embed/voice-widget.js +10 -0
  303. package/dist/index.d.ts +369 -74
  304. package/dist/index.js +45779 -7413
  305. package/dist/internal/evidence.d.ts +10 -0
  306. package/dist/internal/html.d.ts +6 -0
  307. package/dist/internal/status.d.ts +7 -0
  308. package/dist/react/VoiceAgentSquadStatus.d.ts +5 -0
  309. package/dist/react/VoiceCallDebuggerLaunch.d.ts +6 -0
  310. package/dist/react/VoiceCallPlayer.d.ts +11 -0
  311. package/dist/react/VoiceCostDashboard.d.ts +10 -0
  312. package/dist/react/VoiceDeliveryRuntime.d.ts +7 -0
  313. package/dist/react/VoiceLiveAgentConsole.d.ts +11 -0
  314. package/dist/react/VoiceLiveCallViewer.d.ts +9 -0
  315. package/dist/react/VoiceOpsActionCenter.d.ts +5 -0
  316. package/dist/react/VoiceOpsStatus.d.ts +1 -1
  317. package/dist/react/VoicePlatformCoverage.d.ts +6 -0
  318. package/dist/react/VoiceProfileComparison.d.ts +6 -0
  319. package/dist/react/VoiceProfileSwitchRecommendation.d.ts +6 -0
  320. package/dist/react/VoiceProofTrends.d.ts +6 -0
  321. package/dist/react/VoiceProviderCapabilities.d.ts +6 -0
  322. package/dist/react/VoiceProviderContracts.d.ts +6 -0
  323. package/dist/react/VoiceProviderSimulationControls.d.ts +5 -0
  324. package/dist/react/VoiceProviderStatus.d.ts +6 -0
  325. package/dist/react/VoiceReadinessFailures.d.ts +6 -0
  326. package/dist/react/VoiceReconnectProfileEvidence.d.ts +6 -0
  327. package/dist/react/VoiceReplayTimeline.d.ts +6 -0
  328. package/dist/react/VoiceRoutingStatus.d.ts +6 -0
  329. package/dist/react/VoiceSessionObservability.d.ts +6 -0
  330. package/dist/react/VoiceSessionSnapshot.d.ts +6 -0
  331. package/dist/react/VoiceTraceTimeline.d.ts +6 -0
  332. package/dist/react/VoiceTurnLatency.d.ts +6 -0
  333. package/dist/react/VoiceTurnQuality.d.ts +6 -0
  334. package/dist/react/VoiceWidget.d.ts +13 -0
  335. package/dist/react/index.d.ts +80 -6
  336. package/dist/react/index.js +12900 -320
  337. package/dist/react/useVoiceAgentSquadStatus.d.ts +8 -0
  338. package/dist/react/useVoiceCallDebugger.d.ts +8 -0
  339. package/dist/react/useVoiceCampaignDialerProof.d.ts +10 -0
  340. package/dist/react/useVoiceController.d.ts +4 -1
  341. package/dist/react/useVoiceDeliveryRuntime.d.ts +13 -0
  342. package/dist/react/useVoiceLiveOps.d.ts +9 -0
  343. package/dist/react/useVoiceOpsActionCenter.d.ts +11 -0
  344. package/dist/react/useVoiceOpsStatus.d.ts +8 -0
  345. package/dist/react/useVoicePlatformCoverage.d.ts +8 -0
  346. package/dist/react/useVoiceProfileComparison.d.ts +8 -0
  347. package/dist/react/useVoiceProfileSwitchRecommendation.d.ts +8 -0
  348. package/dist/react/useVoiceProofTrends.d.ts +8 -0
  349. package/dist/react/useVoiceProviderCapabilities.d.ts +8 -0
  350. package/dist/react/useVoiceProviderContracts.d.ts +8 -0
  351. package/dist/react/useVoiceProviderSimulationControls.d.ts +10 -0
  352. package/dist/react/useVoiceProviderStatus.d.ts +1 -1
  353. package/dist/react/useVoiceReadinessFailures.d.ts +8 -0
  354. package/dist/react/useVoiceReconnectProfileEvidence.d.ts +8 -0
  355. package/dist/react/useVoiceRoutingStatus.d.ts +8 -0
  356. package/dist/react/useVoiceSessionObservability.d.ts +8 -0
  357. package/dist/react/useVoiceSessionSnapshot.d.ts +9 -0
  358. package/dist/react/useVoiceStream.d.ts +4 -1
  359. package/dist/react/useVoiceTraceTimeline.d.ts +8 -0
  360. package/dist/react/useVoiceTurnLatency.d.ts +9 -0
  361. package/dist/react/useVoiceTurnQuality.d.ts +8 -0
  362. package/dist/react/useVoiceWorkflowStatus.d.ts +1 -1
  363. package/dist/svelte/createVoiceAgentSquadStatus.d.ts +9 -0
  364. package/dist/svelte/createVoiceCallDebugger.d.ts +10 -0
  365. package/dist/svelte/createVoiceCallPlayer.d.ts +33 -0
  366. package/dist/svelte/createVoiceCampaignDialerProof.d.ts +9 -0
  367. package/dist/svelte/createVoiceCostDashboard.d.ts +13 -0
  368. package/dist/svelte/createVoiceDeliveryRuntime.d.ts +11 -0
  369. package/dist/svelte/createVoiceLiveAgentConsole.d.ts +23 -0
  370. package/dist/svelte/createVoiceLiveCallViewer.d.ts +26 -0
  371. package/dist/svelte/createVoiceLiveOps.d.ts +13 -0
  372. package/dist/svelte/createVoiceOpsActionCenter.d.ts +10 -0
  373. package/dist/svelte/createVoiceOpsStatus.d.ts +4 -4
  374. package/dist/svelte/createVoicePlatformCoverage.d.ts +7 -0
  375. package/dist/svelte/createVoiceProfileComparison.d.ts +7 -0
  376. package/dist/svelte/createVoiceProofTrends.d.ts +7 -0
  377. package/dist/svelte/createVoiceProviderCapabilities.d.ts +10 -0
  378. package/dist/svelte/createVoiceProviderContracts.d.ts +10 -0
  379. package/dist/svelte/createVoiceProviderSimulationControls.d.ts +11 -0
  380. package/dist/svelte/createVoiceProviderStatus.d.ts +5 -3
  381. package/dist/svelte/createVoiceReadinessFailures.d.ts +7 -0
  382. package/dist/svelte/createVoiceReconnectProfileEvidence.d.ts +7 -0
  383. package/dist/svelte/createVoiceReplayTimeline.d.ts +13 -0
  384. package/dist/svelte/createVoiceRoutingStatus.d.ts +10 -0
  385. package/dist/svelte/createVoiceSessionObservability.d.ts +10 -0
  386. package/dist/svelte/createVoiceSessionSnapshot.d.ts +11 -0
  387. package/dist/svelte/createVoiceStream.d.ts +1 -1
  388. package/dist/svelte/createVoiceTraceTimeline.d.ts +10 -0
  389. package/dist/svelte/createVoiceTurnLatency.d.ts +11 -0
  390. package/dist/svelte/createVoiceTurnQuality.d.ts +10 -0
  391. package/dist/svelte/createVoiceWidget.d.ts +19 -0
  392. package/dist/svelte/createVoiceWorkflowStatus.d.ts +2 -2
  393. package/dist/svelte/index.d.ts +37 -6
  394. package/dist/svelte/index.js +7047 -768
  395. package/dist/telephony/contract.d.ts +61 -0
  396. package/dist/telephony/matrix.d.ts +97 -0
  397. package/dist/telephony/plivo.d.ts +303 -0
  398. package/dist/telephony/response.d.ts +1 -1
  399. package/dist/telephony/security.d.ts +182 -0
  400. package/dist/telephony/telnyx.d.ts +291 -0
  401. package/dist/telephony/twilio.d.ts +149 -15
  402. package/dist/testing/accuracy.d.ts +1 -1
  403. package/dist/testing/benchmark.d.ts +15 -15
  404. package/dist/testing/corrected.d.ts +9 -9
  405. package/dist/testing/duplex.d.ts +5 -5
  406. package/dist/testing/fixtures.d.ts +4 -4
  407. package/dist/testing/index.d.ts +13 -13
  408. package/dist/testing/index.js +5756 -636
  409. package/dist/testing/ioProviderSimulator.d.ts +5 -5
  410. package/dist/testing/providerSimulator.d.ts +5 -5
  411. package/dist/testing/review.d.ts +8 -8
  412. package/dist/testing/sessionBenchmark.d.ts +13 -13
  413. package/dist/testing/stt.d.ts +3 -3
  414. package/dist/testing/telephony.d.ts +27 -2
  415. package/dist/testing/tts.d.ts +2 -2
  416. package/dist/vue/VoiceCallDebuggerLaunch.d.ts +72 -0
  417. package/dist/vue/VoiceCallPlayer.d.ts +40 -0
  418. package/dist/vue/VoiceCostDashboard.d.ts +57 -0
  419. package/dist/vue/VoiceDeliveryRuntime.d.ts +34 -0
  420. package/dist/vue/VoiceLiveAgentConsole.d.ts +50 -0
  421. package/dist/vue/VoiceLiveCallViewer.d.ts +35 -0
  422. package/dist/vue/VoiceOpsActionCenter.d.ts +13 -0
  423. package/dist/vue/VoiceOpsStatus.d.ts +4 -0
  424. package/dist/vue/VoicePlatformCoverage.d.ts +27 -0
  425. package/dist/vue/VoiceProofTrends.d.ts +25 -0
  426. package/dist/vue/VoiceProviderCapabilities.d.ts +55 -0
  427. package/dist/vue/VoiceProviderContracts.d.ts +25 -0
  428. package/dist/vue/VoiceProviderSimulationControls.d.ts +88 -0
  429. package/dist/vue/VoiceProviderStatus.d.ts +55 -0
  430. package/dist/vue/VoiceReadinessFailures.d.ts +25 -0
  431. package/dist/vue/VoiceReconnectProfileEvidence.d.ts +25 -0
  432. package/dist/vue/VoiceReplayTimeline.d.ts +17 -0
  433. package/dist/vue/VoiceRoutingStatus.d.ts +55 -0
  434. package/dist/vue/VoiceSessionObservability.d.ts +27 -0
  435. package/dist/vue/VoiceSessionSnapshot.d.ts +72 -0
  436. package/dist/vue/VoiceTurnLatency.d.ts +73 -0
  437. package/dist/vue/VoiceTurnQuality.d.ts +55 -0
  438. package/dist/vue/VoiceWidget.d.ts +77 -0
  439. package/dist/vue/index.d.ts +49 -6
  440. package/dist/vue/index.js +12193 -402
  441. package/dist/vue/useVoiceAgentSquadStatus.d.ts +9 -0
  442. package/dist/vue/useVoiceCallDebugger.d.ts +10 -0
  443. package/dist/vue/useVoiceCampaignDialerProof.d.ts +11 -0
  444. package/dist/vue/useVoiceController.d.ts +9 -7
  445. package/dist/vue/useVoiceDeliveryRuntime.d.ts +13 -0
  446. package/dist/vue/useVoiceLiveOps.d.ts +9 -0
  447. package/dist/vue/useVoiceOpsActionCenter.d.ts +11 -0
  448. package/dist/vue/useVoiceOpsStatus.d.ts +9 -0
  449. package/dist/vue/useVoicePlatformCoverage.d.ts +9 -0
  450. package/dist/vue/useVoiceProfileComparison.d.ts +9 -0
  451. package/dist/vue/useVoiceProofTrends.d.ts +9 -0
  452. package/dist/vue/useVoiceProviderCapabilities.d.ts +9 -0
  453. package/dist/vue/useVoiceProviderContracts.d.ts +9 -0
  454. package/dist/vue/useVoiceProviderSimulationControls.d.ts +24 -0
  455. package/dist/vue/useVoiceProviderStatus.d.ts +3 -3
  456. package/dist/vue/useVoiceReadinessFailures.d.ts +959 -0
  457. package/dist/vue/useVoiceReconnectProfileEvidence.d.ts +9 -0
  458. package/dist/vue/useVoiceRoutingStatus.d.ts +8 -0
  459. package/dist/vue/useVoiceSessionObservability.d.ts +9 -0
  460. package/dist/vue/useVoiceSessionSnapshot.d.ts +10 -0
  461. package/dist/vue/useVoiceStream.d.ts +9 -6
  462. package/dist/vue/useVoiceTraceTimeline.d.ts +9 -0
  463. package/dist/vue/useVoiceTurnLatency.d.ts +10 -0
  464. package/dist/vue/useVoiceTurnQuality.d.ts +9 -0
  465. package/dist/vue/useVoiceWorkflowStatus.d.ts +3 -3
  466. package/package.json +154 -256
  467. package/dist/angular/voice-app-kit-status.service.d.ts +0 -12
  468. package/dist/angular/voice-ops-status.component.d.ts +0 -15
  469. package/dist/appKit.d.ts +0 -92
  470. package/dist/client/appKitStatus.d.ts +0 -19
  471. package/dist/react/useVoiceAppKitStatus.d.ts +0 -8
  472. package/dist/svelte/createVoiceAppKitStatus.d.ts +0 -8
  473. package/dist/turnProfiles.d.ts +0 -6
  474. package/dist/vue/useVoiceAppKitStatus.d.ts +0 -9
  475. package/fixtures/README.md +0 -57
  476. package/fixtures/manifest.json +0 -199
  477. package/fixtures/pcm/dialogue-three-clean.pcm +0 -0
  478. package/fixtures/pcm/dialogue-three-mixed.pcm +0 -0
  479. package/fixtures/pcm/dialogue-two-clean.pcm +0 -0
  480. package/fixtures/pcm/dialogue-two-noisy.pcm +0 -0
  481. package/fixtures/pcm/multiturn-three-mixed.pcm +0 -0
  482. package/fixtures/pcm/multiturn-two-clean.pcm +0 -0
  483. package/fixtures/pcm/quietly-alone-clean.pcm +0 -0
  484. package/fixtures/pcm/rainstorms-noisy.pcm +0 -0
  485. package/fixtures/pcm/stella-bulgaria-bulgarian20.pcm +0 -0
  486. package/fixtures/pcm/stella-ghana-english507.pcm +0 -0
  487. package/fixtures/pcm/stella-india-english37.pcm +0 -0
  488. package/fixtures/pcm/stella-jamaica-jamaican-creole-english1.pcm +0 -0
  489. package/fixtures/pcm/stella-liberia-liberian-pidgin-english2.pcm +0 -0
  490. package/fixtures/pcm/stella-pakistan-english519.pcm +0 -0
  491. package/fixtures/pcm/stella-sierra-leone-krio5.pcm +0 -0
  492. package/fixtures/pcm/stella-singapore-english655.pcm +0 -0
  493. package/fixtures/pcm/traveled-back-route-clean.pcm +0 -0
@@ -0,0 +1,3059 @@
1
+ // @bun
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __name = (target, name) => {
6
+ Object.defineProperty(target, "name", {
7
+ value: name,
8
+ enumerable: false,
9
+ configurable: true
10
+ });
11
+ return target;
12
+ };
13
+ var __returnValue = (v) => v;
14
+ function __exportSetter(name, newValue) {
15
+ this[name] = __returnValue.bind(null, newValue);
16
+ }
17
+ var __export = (target, all) => {
18
+ for (var name in all)
19
+ __defProp(target, name, {
20
+ get: all[name],
21
+ enumerable: true,
22
+ configurable: true,
23
+ set: __exportSetter.bind(all, name)
24
+ });
25
+ };
26
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
27
+ var __typeError = (msg) => {
28
+ throw TypeError(msg);
29
+ };
30
+ var __defNormalProp = (obj, key, value) => (key in obj) ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
31
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
32
+ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
33
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
34
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
35
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
36
+ var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
37
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
38
+ var __expectFn = (fn) => fn !== undefined && typeof fn !== "function" ? __typeError("Function expected") : fn;
39
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({
40
+ kind: __decoratorStrings[kind],
41
+ name,
42
+ metadata,
43
+ addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null))
44
+ });
45
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
46
+ var __runInitializers = (array, flags, self, value) => {
47
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length;i < n; i++)
48
+ flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
49
+ return value;
50
+ };
51
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
52
+ var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
53
+ var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
54
+ var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
55
+ var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : {
56
+ get [name]() {
57
+ return __privateGet(this, extra);
58
+ },
59
+ set [name](x) {
60
+ __privateSet(this, extra, x);
61
+ }
62
+ }, name));
63
+ k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
64
+ for (var i = decorators.length - 1;i >= 0; i--) {
65
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
66
+ if (k) {
67
+ ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => (name in x) };
68
+ if (k ^ 3)
69
+ access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
70
+ if (k > 2)
71
+ access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
72
+ }
73
+ it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? undefined : { get: desc.get, set: desc.set } : target, ctx);
74
+ done._ = 1;
75
+ if (k ^ 4 || it === undefined)
76
+ __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
77
+ else if (typeof it !== "object" || it === null)
78
+ __typeError("Object expected");
79
+ else
80
+ __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
81
+ }
82
+ return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
83
+ };
84
+ var __require = import.meta.require;
85
+
86
+ // src/drizzle/assistantMemory.ts
87
+ import { and, desc, eq } from "drizzle-orm";
88
+ import { bigint, jsonb, pgTable, text } from "drizzle-orm/pg-core";
89
+
90
+ // src/core/assistantMemory.ts
91
+ var createMemoryId = (input) => `${input.assistantId}:${input.namespace}:${input.key}`;
92
+ var createVoiceAssistantMemoryHandle = async (input) => {
93
+ const namespace = await resolveVoiceAssistantMemoryNamespace({
94
+ assistantId: input.assistantId,
95
+ context: input.context,
96
+ memory: input.memory,
97
+ session: input.session
98
+ });
99
+ const trace = async (event) => {
100
+ await input.trace?.append({
101
+ at: Date.now(),
102
+ payload: {
103
+ assistantId: input.assistantId,
104
+ namespace,
105
+ ...event
106
+ },
107
+ scenarioId: input.session.scenarioId,
108
+ sessionId: input.session.id,
109
+ type: "assistant.memory"
110
+ });
111
+ };
112
+ return {
113
+ namespace,
114
+ delete: async (key) => {
115
+ await input.memory.store.delete({
116
+ assistantId: input.assistantId,
117
+ key,
118
+ namespace
119
+ });
120
+ await trace({
121
+ action: "delete",
122
+ key
123
+ });
124
+ },
125
+ get: async (key) => {
126
+ const record = await input.memory.store.get({
127
+ assistantId: input.assistantId,
128
+ key,
129
+ namespace
130
+ });
131
+ await trace({
132
+ action: "get",
133
+ found: Boolean(record),
134
+ key
135
+ });
136
+ return record?.value;
137
+ },
138
+ list: async () => {
139
+ const records = await input.memory.store.list({
140
+ assistantId: input.assistantId,
141
+ namespace
142
+ });
143
+ await trace({
144
+ action: "list",
145
+ count: records.length
146
+ });
147
+ return records;
148
+ },
149
+ set: async (key, value, metadata) => {
150
+ const record = await input.memory.store.set({
151
+ assistantId: input.assistantId,
152
+ key,
153
+ metadata,
154
+ namespace,
155
+ value
156
+ });
157
+ await trace({
158
+ action: "set",
159
+ key
160
+ });
161
+ return record;
162
+ }
163
+ };
164
+ };
165
+ var createVoiceAssistantMemoryRecord = (input) => {
166
+ const now = Date.now();
167
+ return {
168
+ ...input,
169
+ createdAt: input.createdAt ?? input.updatedAt ?? now,
170
+ updatedAt: input.updatedAt ?? now
171
+ };
172
+ };
173
+ var createVoiceMemoryAssistantMemoryStore = () => {
174
+ const records = new Map;
175
+ return {
176
+ delete: async (input) => {
177
+ records.delete(createMemoryId(input));
178
+ },
179
+ get: async (input) => records.get(createMemoryId(input)),
180
+ list: async (input) => [...records.values()].filter((record) => record.assistantId === input.assistantId && (input.namespace === undefined || record.namespace === input.namespace)).sort((left, right) => right.updatedAt - left.updatedAt),
181
+ set: async (input) => {
182
+ const id = createMemoryId(input);
183
+ const existing = records.get(id);
184
+ const record = createVoiceAssistantMemoryRecord({
185
+ ...input,
186
+ createdAt: input.createdAt ?? existing?.createdAt,
187
+ updatedAt: input.updatedAt
188
+ });
189
+ records.set(id, record);
190
+ return record;
191
+ }
192
+ };
193
+ };
194
+ var resolveVoiceAssistantMemoryNamespace = async (input) => typeof input.memory.namespace === "function" ? await input.memory.namespace(input) : input.memory.namespace;
195
+
196
+ // src/drizzle/assistantMemory.ts
197
+ var voiceAssistantMemoryTable = pgTable("voice_assistant_memory", {
198
+ assistantId: text("assistant_id").notNull(),
199
+ id: text("id").primaryKey(),
200
+ key: text("key").notNull(),
201
+ namespace: text("namespace").notNull(),
202
+ payload: jsonb("payload").notNull(),
203
+ sortAt: bigint("sort_at", { mode: "number" }).notNull()
204
+ });
205
+ var voiceAssistantMemoryId = (input) => JSON.stringify([input.assistantId, input.namespace, input.key]);
206
+ var createDrizzleAssistantMemoryStore = (db) => {
207
+ const get = async (input) => {
208
+ const rows = await db.select({ payload: voiceAssistantMemoryTable.payload }).from(voiceAssistantMemoryTable).where(eq(voiceAssistantMemoryTable.id, voiceAssistantMemoryId(input))).limit(1);
209
+ return rows[0]?.payload;
210
+ };
211
+ return {
212
+ get,
213
+ delete: async (input) => {
214
+ await db.delete(voiceAssistantMemoryTable).where(eq(voiceAssistantMemoryTable.id, voiceAssistantMemoryId(input)));
215
+ },
216
+ list: async (input) => {
217
+ const rows = await db.select({ payload: voiceAssistantMemoryTable.payload }).from(voiceAssistantMemoryTable).where(input.namespace === undefined ? eq(voiceAssistantMemoryTable.assistantId, input.assistantId) : and(eq(voiceAssistantMemoryTable.assistantId, input.assistantId), eq(voiceAssistantMemoryTable.namespace, input.namespace))).orderBy(desc(voiceAssistantMemoryTable.sortAt));
218
+ return rows.map((row) => row.payload);
219
+ },
220
+ set: async (input) => {
221
+ const existing = await get(input);
222
+ const record = createVoiceAssistantMemoryRecord({
223
+ ...input,
224
+ createdAt: input.createdAt ?? existing?.createdAt,
225
+ updatedAt: input.updatedAt
226
+ });
227
+ await db.insert(voiceAssistantMemoryTable).values({
228
+ assistantId: record.assistantId,
229
+ id: voiceAssistantMemoryId(record),
230
+ key: record.key,
231
+ namespace: record.namespace,
232
+ payload: record,
233
+ sortAt: record.updatedAt
234
+ }).onConflictDoUpdate({
235
+ set: {
236
+ payload: record,
237
+ sortAt: record.updatedAt
238
+ },
239
+ target: voiceAssistantMemoryTable.id
240
+ });
241
+ return record;
242
+ }
243
+ };
244
+ };
245
+ var createVoiceDrizzleAssistantMemoryStore = (options) => createDrizzleAssistantMemoryStore(options.db);
246
+
247
+ // src/drizzle/shared.ts
248
+ import { desc as desc2, eq as eq2 } from "drizzle-orm";
249
+ import {
250
+ bigint as bigint2,
251
+ jsonb as jsonb2,
252
+ pgTable as pgTable2,
253
+ text as text2
254
+ } from "drizzle-orm/pg-core";
255
+ var voiceDocumentTable = (name) => pgTable2(name, {
256
+ id: text2("id").primaryKey(),
257
+ payload: jsonb2("payload").notNull(),
258
+ sortAt: bigint2("sort_at", { mode: "number" }).notNull()
259
+ });
260
+ var createVoiceDrizzleRecordStore = (input) => {
261
+ const get = async (id) => {
262
+ const rows = await input.db.select({ payload: input.table.payload }).from(input.table).where(eq2(input.table.id, id)).limit(1);
263
+ return rows[0]?.payload;
264
+ };
265
+ const list = async () => {
266
+ const rows = await input.db.select({ payload: input.table.payload }).from(input.table).orderBy(desc2(input.table.sortAt), desc2(input.table.id));
267
+ return rows.map((row) => row.payload);
268
+ };
269
+ const set = async (id, value) => {
270
+ const decorated = input.decorate(id, value);
271
+ await input.db.insert(input.table).values({
272
+ id,
273
+ payload: decorated,
274
+ sortAt: input.getSortAt(decorated)
275
+ }).onConflictDoUpdate({
276
+ set: {
277
+ payload: decorated,
278
+ sortAt: input.getSortAt(decorated)
279
+ },
280
+ target: input.table.id
281
+ });
282
+ };
283
+ const remove = async (id) => {
284
+ await input.db.delete(input.table).where(eq2(input.table.id, id));
285
+ };
286
+ return { get, list, remove, set };
287
+ };
288
+
289
+ // src/drizzle/eval.ts
290
+ var voiceEvalBaselineTable = voiceDocumentTable("voice_eval_baseline");
291
+ var VOICE_EVAL_BASELINE_ID = "baseline";
292
+ var createDrizzleEvalBaselineStore = (db) => {
293
+ const store = createVoiceDrizzleRecordStore({
294
+ db,
295
+ decorate: (_id, value) => value,
296
+ getSortAt: (value) => value.checkedAt,
297
+ table: voiceEvalBaselineTable
298
+ });
299
+ return {
300
+ get: async () => store.get(VOICE_EVAL_BASELINE_ID),
301
+ set: async (report) => {
302
+ await store.set(VOICE_EVAL_BASELINE_ID, report);
303
+ }
304
+ };
305
+ };
306
+ var createVoiceDrizzleEvalBaselineStore = (options) => createDrizzleEvalBaselineStore(options.db);
307
+
308
+ // src/drizzle/handoff.ts
309
+ var voiceHandoffDeliveriesTable = voiceDocumentTable("voice_handoff_deliveries");
310
+ var createDrizzleHandoffDeliveryStore = (db) => createVoiceDrizzleRecordStore({
311
+ db,
312
+ decorate: (_id, value) => value,
313
+ getSortAt: (value) => value.createdAt,
314
+ table: voiceHandoffDeliveriesTable
315
+ });
316
+ var createVoiceDrizzleHandoffDeliveryStore = (options) => createDrizzleHandoffDeliveryStore(options.db);
317
+
318
+ // src/drizzle/incidentBundle.ts
319
+ var voiceIncidentBundlesTable = voiceDocumentTable("voice_incident_bundles");
320
+ var matchesIncidentBundleFilter = (artifact, filter) => {
321
+ if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
322
+ return false;
323
+ }
324
+ if (typeof filter.expiredAt === "number" && (artifact.expiresAt === undefined || artifact.expiresAt > filter.expiredAt)) {
325
+ return false;
326
+ }
327
+ return true;
328
+ };
329
+ var createVoiceDrizzleIncidentBundleStore = (options) => {
330
+ const store = createVoiceDrizzleRecordStore({
331
+ db: options.db,
332
+ decorate: (id, value) => ({
333
+ ...value,
334
+ id
335
+ }),
336
+ getSortAt: (value) => value.createdAt,
337
+ table: voiceIncidentBundlesTable
338
+ });
339
+ return {
340
+ get: store.get,
341
+ remove: store.remove,
342
+ set: store.set,
343
+ list: async (filter = {}) => (await store.list()).filter((artifact) => matchesIncidentBundleFilter(artifact, filter))
344
+ };
345
+ };
346
+
347
+ // src/drizzle/observabilityExport.ts
348
+ var voiceObservabilityExportDeliveryReceiptsTable = voiceDocumentTable("voice_observability_export_receipts");
349
+ var createVoiceDrizzleObservabilityExportDeliveryReceiptStore = (options) => createVoiceDrizzleRecordStore({
350
+ db: options.db,
351
+ decorate: (id, value) => ({
352
+ ...value,
353
+ id
354
+ }),
355
+ getSortAt: (value) => value.checkedAt,
356
+ table: voiceObservabilityExportDeliveryReceiptsTable
357
+ });
358
+
359
+ // src/drizzle/proofTrends.ts
360
+ var voiceRealCallProfileEvidenceTable = voiceDocumentTable("voice_real_call_profile_evidence");
361
+ var voiceRealCallProfileRecoveryJobsTable = voiceDocumentTable("voice_real_call_profile_recovery_jobs");
362
+ var parseRealCallProfileEvidenceBoundary = (value) => {
363
+ if (value === undefined) {
364
+ return;
365
+ }
366
+ if (value instanceof Date) {
367
+ return value.getTime();
368
+ }
369
+ if (typeof value === "number") {
370
+ return value;
371
+ }
372
+ return Date.parse(value);
373
+ };
374
+ var readRealCallProfileEvidenceSortTime = (evidence, fallback) => Date.parse(evidence.generatedAt ?? fallback) || Date.parse(fallback);
375
+ var matchesRealCallProfileEvidenceListOptions = (record, input) => {
376
+ const evidenceTime = readRealCallProfileEvidenceSortTime(record, record.createdAt);
377
+ const since = parseRealCallProfileEvidenceBoundary(input.since);
378
+ const until = parseRealCallProfileEvidenceBoundary(input.until);
379
+ return (!input.profileId || record.profileId === input.profileId) && (!input.sessionId || record.sessionId === input.sessionId) && (since === undefined || Number.isNaN(since) || evidenceTime >= since) && (until === undefined || Number.isNaN(until) || evidenceTime <= until);
380
+ };
381
+ var matchesRealCallProfileRecoveryJobListOptions = (job, input) => (!input.actionId || job.actionId === input.actionId) && (!input.status || job.status === input.status);
382
+ var createDrizzleRealCallProfileRecoveryJobStore = (db, options = {}) => {
383
+ const store = createVoiceDrizzleRecordStore({
384
+ db,
385
+ decorate: (_id, value) => value,
386
+ getSortAt: (value) => Date.parse(value.updatedAt) || Date.now(),
387
+ table: voiceRealCallProfileRecoveryJobsTable
388
+ });
389
+ const now = () => (options.now ?? (() => new Date))().toISOString();
390
+ const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
391
+ return {
392
+ get: store.get,
393
+ create: async (input) => {
394
+ const createdAt = input.createdAt ?? now();
395
+ const job = {
396
+ actionId: input.actionId,
397
+ createdAt,
398
+ id: input.id ?? createId(),
399
+ message: input.message,
400
+ status: input.status ?? "queued",
401
+ updatedAt: createdAt
402
+ };
403
+ await store.set(job.id, job);
404
+ return job;
405
+ },
406
+ list: async (input = {}) => {
407
+ const limit = Number.isFinite(input.limit) && input.limit !== undefined && input.limit > 0 ? Math.floor(input.limit) : 50;
408
+ return (await store.list()).filter((job) => matchesRealCallProfileRecoveryJobListOptions(job, input)).slice(0, limit);
409
+ },
410
+ update: async (id, update) => {
411
+ const existing = await store.get(id);
412
+ if (!existing) {
413
+ return;
414
+ }
415
+ const next = {
416
+ ...existing,
417
+ ...update,
418
+ updatedAt: update.updatedAt ?? now()
419
+ };
420
+ await store.set(id, next);
421
+ return next;
422
+ }
423
+ };
424
+ };
425
+ var createDrizzleRealCallProfileEvidenceStore = (db, options = {}) => {
426
+ const store = createVoiceDrizzleRecordStore({
427
+ db,
428
+ decorate: (_id, value) => value,
429
+ getSortAt: (value) => readRealCallProfileEvidenceSortTime(value, value.createdAt),
430
+ table: voiceRealCallProfileEvidenceTable
431
+ });
432
+ const now = () => (options.now ?? (() => new Date))().toISOString();
433
+ const createId = () => `${options.idPrefix ?? "voice-profile-evidence"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
434
+ return {
435
+ get: store.get,
436
+ remove: store.remove,
437
+ append: async (input) => {
438
+ const record = {
439
+ ...input,
440
+ createdAt: input.createdAt ?? now(),
441
+ id: input.id ?? createId()
442
+ };
443
+ await store.set(record.id, record);
444
+ return record;
445
+ },
446
+ list: async (input = {}) => {
447
+ const limit = Number.isFinite(input.limit) && input.limit !== undefined && input.limit > 0 ? Math.floor(input.limit) : 500;
448
+ return (await store.list()).filter((record) => matchesRealCallProfileEvidenceListOptions(record, input)).slice(0, limit);
449
+ }
450
+ };
451
+ };
452
+ var createVoiceDrizzleRealCallProfileEvidenceStore = (options) => createDrizzleRealCallProfileEvidenceStore(options.db, {
453
+ idPrefix: options.idPrefix,
454
+ now: options.now
455
+ });
456
+ var createVoiceDrizzleRealCallProfileRecoveryJobStore = (options) => createDrizzleRealCallProfileRecoveryJobStore(options.db, {
457
+ idPrefix: options.idPrefix,
458
+ now: options.now
459
+ });
460
+
461
+ // src/core/audit.ts
462
+ var includes = (filter, value) => {
463
+ if (!filter) {
464
+ return true;
465
+ }
466
+ if (!value) {
467
+ return false;
468
+ }
469
+ return Array.isArray(filter) ? filter.includes(value) : filter === value;
470
+ };
471
+ var createVoiceAuditEvent = (event) => ({
472
+ ...event,
473
+ at: event.at ?? Date.now(),
474
+ id: event.id ?? crypto.randomUUID()
475
+ });
476
+ var createVoiceAuditLogger = (store) => ({
477
+ handoff: (input) => recordVoiceHandoffAuditEvent({ ...input, store }),
478
+ operatorAction: (input) => recordVoiceOperatorAuditEvent({ ...input, store }),
479
+ providerCall: (input) => recordVoiceProviderAuditEvent({ ...input, store }),
480
+ record: (event) => recordVoiceAuditEvent(store, event),
481
+ retention: (input) => recordVoiceRetentionAuditEvent({ ...input, store }),
482
+ toolCall: (input) => recordVoiceToolAuditEvent({ ...input, store })
483
+ });
484
+ var createVoiceMemoryAuditEventStore = () => {
485
+ const events = new Map;
486
+ return {
487
+ append: (event) => {
488
+ const stored = createVoiceAuditEvent(event);
489
+ events.set(stored.id, stored);
490
+ return stored;
491
+ },
492
+ get: (id) => events.get(id),
493
+ list: (filter) => filterVoiceAuditEvents([...events.values()], filter)
494
+ };
495
+ };
496
+ var createVoiceScopedAuditEventStore = (store, scope) => {
497
+ const upstreamFilter = (filter = {}) => {
498
+ const next = { ...filter };
499
+ delete next.limit;
500
+ if (scope.actorId !== undefined) {
501
+ delete next.actorId;
502
+ }
503
+ if (scope.outcome !== undefined) {
504
+ delete next.outcome;
505
+ }
506
+ if (scope.resourceId !== undefined) {
507
+ delete next.resourceId;
508
+ }
509
+ if (scope.resourceType !== undefined) {
510
+ delete next.resourceType;
511
+ }
512
+ if (scope.sessionId !== undefined) {
513
+ delete next.sessionId;
514
+ }
515
+ if (scope.traceId !== undefined) {
516
+ delete next.traceId;
517
+ }
518
+ if (scope.type !== undefined) {
519
+ delete next.type;
520
+ }
521
+ return next;
522
+ };
523
+ const scopedFilter = (filter = {}) => ({
524
+ ...filter,
525
+ ...scope
526
+ });
527
+ return {
528
+ append: (event) => store.append(event),
529
+ get: (id) => store.get(id),
530
+ list: async (filter) => filterVoiceAuditEvents(await store.list(upstreamFilter(filter)), scopedFilter(filter))
531
+ };
532
+ };
533
+ var filterVoiceAuditEvents = (events, filter = {}) => {
534
+ const sorted = events.filter((event) => {
535
+ if (!includes(filter.type, event.type)) {
536
+ return false;
537
+ }
538
+ if (!includes(filter.outcome, event.outcome)) {
539
+ return false;
540
+ }
541
+ if (filter.actorId && event.actor?.id !== filter.actorId) {
542
+ return false;
543
+ }
544
+ if (filter.resourceId && event.resource?.id !== filter.resourceId) {
545
+ return false;
546
+ }
547
+ if (filter.resourceType && event.resource?.type !== filter.resourceType) {
548
+ return false;
549
+ }
550
+ if (filter.sessionId && event.sessionId !== filter.sessionId) {
551
+ return false;
552
+ }
553
+ if (filter.traceId && event.traceId !== filter.traceId) {
554
+ return false;
555
+ }
556
+ if (typeof filter.after === "number" && event.at <= filter.after) {
557
+ return false;
558
+ }
559
+ if (typeof filter.afterOrAt === "number" && event.at < filter.afterOrAt) {
560
+ return false;
561
+ }
562
+ if (typeof filter.before === "number" && event.at >= filter.before) {
563
+ return false;
564
+ }
565
+ if (typeof filter.beforeOrAt === "number" && event.at > filter.beforeOrAt) {
566
+ return false;
567
+ }
568
+ return true;
569
+ }).sort((left, right) => left.at - right.at || left.id.localeCompare(right.id));
570
+ return typeof filter.limit === "number" && filter.limit >= 0 ? sorted.slice(0, filter.limit) : sorted;
571
+ };
572
+ var recordVoiceAuditEvent = (store, event) => store.append(createVoiceAuditEvent(event));
573
+ var recordVoiceHandoffAuditEvent = (input) => recordVoiceAuditEvent(input.store, {
574
+ action: "handoff",
575
+ actor: input.actor,
576
+ metadata: input.metadata,
577
+ outcome: input.outcome,
578
+ payload: {
579
+ fromAgentId: input.fromAgentId,
580
+ reason: input.reason,
581
+ target: input.target,
582
+ toAgentId: input.toAgentId
583
+ },
584
+ resource: {
585
+ id: input.toAgentId ?? input.target,
586
+ type: "handoff"
587
+ },
588
+ sessionId: input.sessionId,
589
+ traceId: input.traceId,
590
+ type: "handoff"
591
+ });
592
+ var recordVoiceOperatorAuditEvent = (input) => recordVoiceAuditEvent(input.store, {
593
+ action: input.action,
594
+ actor: input.actor,
595
+ metadata: input.metadata,
596
+ outcome: input.outcome ?? "success",
597
+ payload: input.payload,
598
+ resource: input.resource,
599
+ sessionId: input.sessionId,
600
+ traceId: input.traceId,
601
+ type: "operator.action"
602
+ });
603
+ var recordVoiceProviderAuditEvent = (input) => recordVoiceAuditEvent(input.store, {
604
+ action: `${input.kind}.provider.call`,
605
+ actor: input.actor,
606
+ metadata: input.metadata,
607
+ outcome: input.outcome,
608
+ payload: {
609
+ cost: input.cost,
610
+ elapsedMs: input.elapsedMs,
611
+ error: input.error,
612
+ kind: input.kind,
613
+ model: input.model,
614
+ provider: input.provider
615
+ },
616
+ resource: {
617
+ id: input.provider,
618
+ type: "provider"
619
+ },
620
+ sessionId: input.sessionId,
621
+ traceId: input.traceId,
622
+ type: "provider.call"
623
+ });
624
+ var recordVoiceRetentionAuditEvent = (input) => recordVoiceAuditEvent(input.store, {
625
+ action: input.dryRun ? "retention.plan" : "retention.apply",
626
+ actor: input.actor ?? {
627
+ id: "voice-retention",
628
+ kind: "system"
629
+ },
630
+ metadata: input.metadata,
631
+ outcome: "success",
632
+ payload: {
633
+ deletedCount: input.report.deletedCount,
634
+ dryRun: input.dryRun,
635
+ scopes: input.report.scopes
636
+ },
637
+ resource: {
638
+ type: "retention-policy"
639
+ },
640
+ type: "retention.policy"
641
+ });
642
+ var recordVoiceToolAuditEvent = (input) => recordVoiceAuditEvent(input.store, {
643
+ action: "tool.call",
644
+ actor: input.actor,
645
+ metadata: input.metadata,
646
+ outcome: input.outcome,
647
+ payload: {
648
+ elapsedMs: input.elapsedMs,
649
+ error: input.error,
650
+ toolCallId: input.toolCallId,
651
+ toolName: input.toolName
652
+ },
653
+ resource: {
654
+ id: input.toolName,
655
+ type: "tool"
656
+ },
657
+ sessionId: input.sessionId,
658
+ traceId: input.traceId,
659
+ type: "tool.call"
660
+ });
661
+
662
+ // src/core/ops.ts
663
+ var createVoiceExternalObjectMap = (input) => {
664
+ const at = input.at ?? Date.now();
665
+ return {
666
+ createdAt: at,
667
+ externalId: input.externalId,
668
+ id: createVoiceExternalObjectMapId(input),
669
+ provider: input.provider,
670
+ sinkId: input.sinkId,
671
+ sourceId: input.sourceId,
672
+ sourceType: input.sourceType,
673
+ updatedAt: at
674
+ };
675
+ };
676
+ var createVoiceExternalObjectMapId = (input) => [
677
+ input.provider,
678
+ input.sinkId ?? "default",
679
+ encodeURIComponent(input.sourceId)
680
+ ].join(":");
681
+ var sleep = async (delayMs) => {
682
+ if (delayMs <= 0) {
683
+ return;
684
+ }
685
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
686
+ };
687
+ var toHex = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
688
+ var signVoiceIntegrationWebhookBody = async (input) => {
689
+ const encoder = new TextEncoder;
690
+ const key = await crypto.subtle.importKey("raw", encoder.encode(input.secret), {
691
+ hash: "SHA-256",
692
+ name: "HMAC"
693
+ }, false, ["sign"]);
694
+ const payload = encoder.encode(`${input.timestamp}.${input.body}`);
695
+ const signature = await crypto.subtle.sign("HMAC", key, payload);
696
+ return `sha256=${toHex(new Uint8Array(signature))}`;
697
+ };
698
+ var createVoiceWebhookDeliveryError = (input) => {
699
+ if (input.response) {
700
+ const statusText = input.response.statusText?.trim();
701
+ return `Attempt ${input.attempt} failed with webhook response ${input.response.status}${statusText ? ` ${statusText}` : ""}.`;
702
+ }
703
+ if (input.error instanceof Error) {
704
+ return `Attempt ${input.attempt} failed: ${input.error.message}`;
705
+ }
706
+ return `Attempt ${input.attempt} failed: ${String(input.error)}`;
707
+ };
708
+ var deliverVoiceIntegrationEvent = async (input) => {
709
+ const previousAttempts = input.event.deliveryAttempts ?? 0;
710
+ const matchesConfiguredTypes = input.webhook.eventTypes === undefined ? true : input.webhook.eventTypes.includes(input.event.type);
711
+ if (!matchesConfiguredTypes) {
712
+ return {
713
+ ...input.event,
714
+ deliveryAttempts: 0,
715
+ deliveryError: undefined,
716
+ deliveryStatus: "skipped"
717
+ };
718
+ }
719
+ const fetchImpl = input.webhook.fetch ?? globalThis.fetch;
720
+ if (typeof fetchImpl !== "function") {
721
+ return {
722
+ ...input.event,
723
+ deliveredTo: input.webhook.url,
724
+ deliveryAttempts: 0,
725
+ deliveryError: "Webhook delivery failed: fetch is not available in this runtime.",
726
+ deliveryStatus: "failed"
727
+ };
728
+ }
729
+ const maxRetries = Math.max(0, input.webhook.retries ?? 0);
730
+ const backoffMs = Math.max(0, input.webhook.backoffMs ?? 250);
731
+ const timeoutMs = Math.max(0, input.webhook.timeoutMs ?? 1e4);
732
+ const body = JSON.stringify({
733
+ createdAt: input.event.createdAt,
734
+ id: input.event.id,
735
+ payload: input.event.payload,
736
+ type: input.event.type
737
+ });
738
+ let lastError = "Webhook delivery failed.";
739
+ for (let attempt = 1;attempt <= maxRetries + 1; attempt += 1) {
740
+ let controller;
741
+ let timeout;
742
+ try {
743
+ const headers = {
744
+ "content-type": "application/json",
745
+ ...input.webhook.headers
746
+ };
747
+ if (input.webhook.signingSecret) {
748
+ const timestamp = String(Date.now());
749
+ headers["x-absolutejs-timestamp"] = timestamp;
750
+ headers["x-absolutejs-signature"] = await signVoiceIntegrationWebhookBody({
751
+ body,
752
+ secret: input.webhook.signingSecret,
753
+ timestamp
754
+ });
755
+ }
756
+ controller = timeoutMs > 0 ? new AbortController : undefined;
757
+ const activeController = controller;
758
+ timeout = activeController && timeoutMs > 0 ? setTimeout(() => activeController.abort(), timeoutMs) : undefined;
759
+ const response = await fetchImpl(input.webhook.url, {
760
+ body,
761
+ headers,
762
+ method: "POST",
763
+ signal: controller?.signal
764
+ });
765
+ if (response.ok) {
766
+ if (timeout) {
767
+ clearTimeout(timeout);
768
+ }
769
+ return {
770
+ ...input.event,
771
+ deliveredAt: Date.now(),
772
+ deliveredTo: input.webhook.url,
773
+ deliveryAttempts: previousAttempts + attempt,
774
+ deliveryError: undefined,
775
+ deliveryStatus: "delivered"
776
+ };
777
+ }
778
+ lastError = createVoiceWebhookDeliveryError({
779
+ attempt,
780
+ error: new Error(`HTTP ${response.status}`),
781
+ response
782
+ });
783
+ } catch (error) {
784
+ lastError = createVoiceWebhookDeliveryError({
785
+ attempt,
786
+ error
787
+ });
788
+ } finally {
789
+ if (timeout) {
790
+ clearTimeout(timeout);
791
+ }
792
+ }
793
+ if (attempt <= maxRetries) {
794
+ await sleep(backoffMs * attempt);
795
+ }
796
+ }
797
+ return {
798
+ ...input.event,
799
+ deliveredTo: input.webhook.url,
800
+ deliveryAttempts: previousAttempts + maxRetries + 1,
801
+ deliveryError: lastError,
802
+ deliveryStatus: "failed"
803
+ };
804
+ };
805
+ var ensureTaskHistory = (task, entry) => ({
806
+ ...task,
807
+ history: [
808
+ ...task.history ?? [],
809
+ {
810
+ ...entry,
811
+ at: entry.at ?? Date.now()
812
+ }
813
+ ],
814
+ updatedAt: Date.now()
815
+ });
816
+ var buildVoiceOpsTaskFromReview = (review) => {
817
+ const createdAt = review.generatedAt ?? Date.now();
818
+ const common = {
819
+ createdAt,
820
+ history: [
821
+ {
822
+ actor: "system",
823
+ at: createdAt,
824
+ detail: review.postCall?.summary,
825
+ type: "created"
826
+ }
827
+ ],
828
+ id: `${review.id}:ops`,
829
+ intakeId: review.id,
830
+ outcome: review.summary.outcome,
831
+ recommendedAction: review.postCall?.recommendedAction ?? "Review the voice artifact and decide the next operator action.",
832
+ reviewId: review.id,
833
+ status: "open",
834
+ target: review.postCall?.target,
835
+ updatedAt: createdAt
836
+ };
837
+ switch (review.summary.outcome) {
838
+ case "voicemail":
839
+ return {
840
+ ...common,
841
+ description: review.postCall?.summary ?? "Caller reached voicemail and needs a callback follow-up.",
842
+ kind: "callback",
843
+ title: review.postCall?.target ? `Call back voicemail from ${review.postCall.target}` : "Call back voicemail lead"
844
+ };
845
+ case "no-answer":
846
+ return {
847
+ ...common,
848
+ description: review.postCall?.summary ?? "Live contact was not established and should be retried.",
849
+ kind: "callback",
850
+ title: "Retry no-answer call"
851
+ };
852
+ case "escalated":
853
+ return {
854
+ ...common,
855
+ description: review.postCall?.summary ?? "The automated path escalated this call for human review.",
856
+ kind: "escalation",
857
+ title: "Review escalated call"
858
+ };
859
+ case "transferred":
860
+ return {
861
+ ...common,
862
+ description: review.postCall?.summary ?? "The call was transferred and should be verified downstream.",
863
+ kind: "transfer-check",
864
+ title: review.postCall?.target ? `Verify transfer to ${review.postCall.target}` : "Verify call transfer"
865
+ };
866
+ case "failed":
867
+ return {
868
+ ...common,
869
+ description: review.postCall?.summary ?? "The call failed and needs operator review before retry.",
870
+ kind: "retry-review",
871
+ title: "Inspect failed call before retry"
872
+ };
873
+ default:
874
+ return null;
875
+ }
876
+ };
877
+ var withVoiceIntegrationEventId = (id, event) => ({
878
+ ...event,
879
+ id
880
+ });
881
+ var withVoiceOpsTaskId = (id, task) => ({
882
+ ...task,
883
+ id
884
+ });
885
+ var DEFAULT_VOICE_OPS_TASK_POLICIES = {
886
+ escalated: {
887
+ dueInMs: 10 * 60000,
888
+ name: "escalation-rapid-response",
889
+ priority: "urgent"
890
+ },
891
+ failed: {
892
+ dueInMs: 15 * 60000,
893
+ name: "failed-call-review",
894
+ priority: "high"
895
+ },
896
+ "no-answer": {
897
+ dueInMs: 2 * 60 * 60000,
898
+ name: "no-answer-retry",
899
+ priority: "normal"
900
+ },
901
+ transferred: {
902
+ dueInMs: 20 * 60000,
903
+ name: "transfer-verification",
904
+ priority: "normal"
905
+ },
906
+ voicemail: {
907
+ dueInMs: 30 * 60000,
908
+ name: "voicemail-callback",
909
+ priority: "high"
910
+ }
911
+ };
912
+ var applyVoiceOpsTaskAssignmentRule = (task, rule, input = {}) => {
913
+ const updatedTask = {
914
+ ...task,
915
+ assignee: rule.assign ?? task.assignee,
916
+ priority: rule.priority ?? task.priority,
917
+ queue: rule.queue ?? task.queue,
918
+ recommendedAction: rule.recommendedAction ?? task.recommendedAction,
919
+ title: rule.title ?? task.title
920
+ };
921
+ return ensureTaskHistory(updatedTask, {
922
+ actor: input.actor ?? "system",
923
+ at: input.at,
924
+ detail: input.detail ?? rule.description ?? (rule.name ? `Applied assignment rule ${rule.name}` : "Applied assignment rule"),
925
+ type: "assigned"
926
+ });
927
+ };
928
+ var applyVoiceOpsTaskPolicy = (task, policy, input = {}) => {
929
+ const at = input.at ?? Date.now();
930
+ const updatedTask = {
931
+ ...task,
932
+ assignee: policy.assignee ?? task.assignee,
933
+ dueAt: typeof policy.dueInMs === "number" ? at + Math.max(0, policy.dueInMs) : task.dueAt,
934
+ policyName: policy.name ?? task.policyName,
935
+ priority: policy.priority ?? task.priority,
936
+ queue: policy.queue ?? task.queue,
937
+ recommendedAction: policy.recommendedAction ?? task.recommendedAction,
938
+ target: policy.target ?? task.target,
939
+ title: policy.title ?? task.title
940
+ };
941
+ return ensureTaskHistory(updatedTask, {
942
+ actor: input.actor ?? "system",
943
+ at,
944
+ detail: input.detail ?? (policy.name ? `Applied ops policy ${policy.name}` : "Applied ops task policy"),
945
+ type: "policy-applied"
946
+ });
947
+ };
948
+ var assignVoiceOpsTask = (task, owner, input = {}) => {
949
+ const normalizedOwner = owner.trim() || "ops";
950
+ return ensureTaskHistory({
951
+ ...task,
952
+ assignee: normalizedOwner
953
+ }, {
954
+ actor: input.actor ?? normalizedOwner,
955
+ at: input.at,
956
+ detail: `Assigned to ${normalizedOwner}`,
957
+ type: "assigned"
958
+ });
959
+ };
960
+ var buildVoiceOpsTaskFromSLABreach = (task, policy = {}) => {
961
+ const createdAt = task.slaBreachedAt ?? Date.now();
962
+ const followUp = withVoiceOpsTaskId(`${task.id}:sla`, {
963
+ assignee: policy.assignee ?? task.assignee,
964
+ createdAt,
965
+ description: policy.description ?? `Task ${task.id} breached its SLA and needs operator follow-up.`,
966
+ dueAt: typeof policy.dueInMs === "number" ? createdAt + Math.max(0, policy.dueInMs) : undefined,
967
+ history: [
968
+ {
969
+ actor: "system",
970
+ at: createdAt,
971
+ detail: policy.name ?? (task.policyName ? `Created from SLA breach on policy ${task.policyName}` : "Created from SLA breach"),
972
+ type: "created"
973
+ }
974
+ ],
975
+ kind: task.kind,
976
+ intakeId: task.intakeId,
977
+ outcome: task.outcome,
978
+ priority: policy.priority ?? "urgent",
979
+ policyName: policy.name ?? `${task.policyName ?? task.kind}:sla`,
980
+ queue: policy.queue ?? task.queue,
981
+ recommendedAction: policy.recommendedAction ?? `Review overdue task ${task.id} and decide the next operator action.`,
982
+ reviewId: task.reviewId,
983
+ status: "open",
984
+ target: task.target,
985
+ title: policy.title ?? `SLA follow-up for ${task.title}`,
986
+ updatedAt: createdAt
987
+ });
988
+ return followUp;
989
+ };
990
+ var claimVoiceOpsTask = (task, workerId, input = {
991
+ leaseMs: 30000
992
+ }) => {
993
+ const at = input.at ?? Date.now();
994
+ const leaseMs = Math.max(1, input.leaseMs);
995
+ return ensureTaskHistory({
996
+ ...task,
997
+ claimExpiresAt: at + leaseMs,
998
+ claimedAt: at,
999
+ claimedBy: workerId,
1000
+ status: task.status === "done" ? task.status : "in-progress"
1001
+ }, {
1002
+ actor: input.actor ?? workerId,
1003
+ at,
1004
+ detail: input.detail ?? `Claimed by ${workerId}`,
1005
+ type: "claimed"
1006
+ });
1007
+ };
1008
+ var completeVoiceOpsTask = (task, input = {}) => ensureTaskHistory({
1009
+ ...task,
1010
+ claimExpiresAt: undefined,
1011
+ claimedAt: undefined,
1012
+ claimedBy: undefined,
1013
+ lastProcessedAt: input.at ?? Date.now(),
1014
+ processingError: undefined,
1015
+ status: "done"
1016
+ }, {
1017
+ actor: input.actor ?? task.assignee ?? "ops",
1018
+ at: input.at,
1019
+ detail: input.detail ?? "Marked done",
1020
+ type: "completed"
1021
+ });
1022
+ var createVoiceCallCompletedEvent = (input) => createVoiceIntegrationEvent("call.completed", {
1023
+ call: input.session.call,
1024
+ disposition: input.disposition ?? input.session.call?.disposition,
1025
+ scenarioId: input.session.scenarioId,
1026
+ sessionId: input.session.id,
1027
+ sessionSummary: input.sessionSummary,
1028
+ status: input.session.status,
1029
+ turnCount: input.session.turns.length
1030
+ }, {
1031
+ id: `${input.session.id}:call.completed`
1032
+ });
1033
+ var createVoiceIntegrationEvent = (type, payload, input = {}) => ({
1034
+ createdAt: input.createdAt ?? Date.now(),
1035
+ id: input.id ?? crypto.randomUUID(),
1036
+ payload,
1037
+ type
1038
+ });
1039
+ var createVoiceReviewSavedEvent = (review) => createVoiceIntegrationEvent("review.saved", {
1040
+ elapsedMs: review.summary.elapsedMs,
1041
+ firstTurnLatencyMs: review.summary.firstTurnLatencyMs,
1042
+ outcome: review.summary.outcome,
1043
+ postCall: review.postCall,
1044
+ reviewId: review.id,
1045
+ title: review.title
1046
+ }, {
1047
+ id: `${review.id}:review.saved`
1048
+ });
1049
+ var createVoiceTaskCreatedEvent = (task) => createVoiceIntegrationEvent("task.created", {
1050
+ assignee: task.assignee,
1051
+ dueAt: task.dueAt,
1052
+ kind: task.kind,
1053
+ outcome: task.outcome,
1054
+ priority: task.priority,
1055
+ queue: task.queue,
1056
+ recommendedAction: task.recommendedAction,
1057
+ reviewId: task.reviewId,
1058
+ status: task.status,
1059
+ target: task.target,
1060
+ taskId: task.id,
1061
+ title: task.title
1062
+ }, {
1063
+ id: `${task.id}:task.created:${task.updatedAt}`
1064
+ });
1065
+ var createVoiceTaskSLABreachedEvent = (task) => createVoiceIntegrationEvent("task.sla_breached", {
1066
+ assignee: task.assignee,
1067
+ dueAt: task.dueAt,
1068
+ kind: task.kind,
1069
+ outcome: task.outcome,
1070
+ priority: task.priority,
1071
+ queue: task.queue,
1072
+ recommendedAction: task.recommendedAction,
1073
+ reviewId: task.reviewId,
1074
+ slaBreachedAt: task.slaBreachedAt,
1075
+ status: task.status,
1076
+ target: task.target,
1077
+ taskId: task.id,
1078
+ title: task.title
1079
+ }, {
1080
+ id: `${task.id}:task.sla_breached:${task.slaBreachedAt ?? task.updatedAt}`
1081
+ });
1082
+ var createVoiceTaskUpdatedEvent = (task) => createVoiceIntegrationEvent("task.updated", {
1083
+ assignee: task.assignee,
1084
+ dueAt: task.dueAt,
1085
+ history: task.history,
1086
+ kind: task.kind,
1087
+ outcome: task.outcome,
1088
+ priority: task.priority,
1089
+ queue: task.queue,
1090
+ recommendedAction: task.recommendedAction,
1091
+ reviewId: task.reviewId,
1092
+ slaBreachedAt: task.slaBreachedAt,
1093
+ status: task.status,
1094
+ target: task.target,
1095
+ taskId: task.id,
1096
+ title: task.title,
1097
+ updatedAt: task.updatedAt
1098
+ }, {
1099
+ id: `${task.id}:task.updated:${task.updatedAt}`
1100
+ });
1101
+ var deadLetterVoiceOpsTask = (task, input = {}) => {
1102
+ const at = input.at ?? Date.now();
1103
+ return ensureTaskHistory({
1104
+ ...task,
1105
+ claimExpiresAt: undefined,
1106
+ claimedAt: undefined,
1107
+ claimedBy: undefined,
1108
+ deadLetteredAt: at,
1109
+ lastProcessedAt: at,
1110
+ status: "open"
1111
+ }, {
1112
+ actor: input.actor ?? task.assignee ?? "ops",
1113
+ at,
1114
+ detail: input.detail ?? "Task moved to dead-letter queue",
1115
+ type: "dead-lettered"
1116
+ });
1117
+ };
1118
+ var failVoiceOpsTask = (task, input = {}) => {
1119
+ const at = input.at ?? Date.now();
1120
+ const detail = input.detail ?? input.error ?? "Task processing failed";
1121
+ return ensureTaskHistory({
1122
+ ...task,
1123
+ lastProcessedAt: at,
1124
+ processingAttempts: (task.processingAttempts ?? 0) + 1,
1125
+ processingError: input.error ?? detail,
1126
+ status: task.status === "done" ? task.status : "open"
1127
+ }, {
1128
+ actor: input.actor ?? task.claimedBy ?? task.assignee ?? "ops",
1129
+ at,
1130
+ detail,
1131
+ type: "failed"
1132
+ });
1133
+ };
1134
+ var hasVoiceOpsTaskSLABreach = (task) => typeof task.slaBreachedAt === "number";
1135
+ var heartbeatVoiceOpsTask = (task, workerId, input = {
1136
+ leaseMs: 30000
1137
+ }) => {
1138
+ if (task.claimedBy && task.claimedBy !== workerId) {
1139
+ throw new Error(`Cannot heartbeat task ${task.id}: claimed by ${task.claimedBy}, not ${workerId}.`);
1140
+ }
1141
+ const at = input.at ?? Date.now();
1142
+ const leaseMs = Math.max(1, input.leaseMs);
1143
+ return ensureTaskHistory({
1144
+ ...task,
1145
+ claimExpiresAt: at + leaseMs,
1146
+ claimedAt: task.claimedAt ?? at,
1147
+ claimedBy: workerId
1148
+ }, {
1149
+ actor: input.actor ?? workerId,
1150
+ at,
1151
+ detail: input.detail ?? `Heartbeat from ${workerId}`,
1152
+ type: "heartbeat"
1153
+ });
1154
+ };
1155
+ var isVoiceOpsTaskOverdue = (task, input = {}) => typeof task.dueAt === "number" && task.status !== "done" && task.dueAt <= (input.at ?? Date.now());
1156
+ var listVoiceOpsTasks = (tasks) => [...tasks].sort((left, right) => right.createdAt - left.createdAt);
1157
+ var markVoiceOpsTaskSLABreached = (task, input = {}) => {
1158
+ const at = input.at ?? Date.now();
1159
+ if (hasVoiceOpsTaskSLABreach(task)) {
1160
+ return task;
1161
+ }
1162
+ return ensureTaskHistory({
1163
+ ...task,
1164
+ slaBreachedAt: at
1165
+ }, {
1166
+ actor: input.actor ?? "system",
1167
+ at,
1168
+ detail: input.detail ?? "Task breached its SLA",
1169
+ type: "sla-breached"
1170
+ });
1171
+ };
1172
+ var matchesVoiceOpsTaskAssignmentRule = (task, rule) => {
1173
+ const { when } = rule;
1174
+ if (!when) {
1175
+ return true;
1176
+ }
1177
+ if (when.assignee !== undefined && task.assignee !== when.assignee) {
1178
+ return false;
1179
+ }
1180
+ if (when.kind !== undefined && task.kind !== when.kind) {
1181
+ return false;
1182
+ }
1183
+ if (when.outcome !== undefined && task.outcome !== when.outcome) {
1184
+ return false;
1185
+ }
1186
+ if (when.policyName !== undefined && task.policyName !== when.policyName) {
1187
+ return false;
1188
+ }
1189
+ if (when.priority !== undefined && task.priority !== when.priority) {
1190
+ return false;
1191
+ }
1192
+ if (when.queue !== undefined && task.queue !== when.queue) {
1193
+ return false;
1194
+ }
1195
+ if (when.status !== undefined && task.status !== when.status) {
1196
+ return false;
1197
+ }
1198
+ return true;
1199
+ };
1200
+ var reopenVoiceOpsTask = (task, input = {}) => ensureTaskHistory({
1201
+ ...task,
1202
+ claimExpiresAt: undefined,
1203
+ claimedAt: undefined,
1204
+ claimedBy: undefined,
1205
+ deadLetteredAt: undefined,
1206
+ processingError: undefined,
1207
+ status: "open"
1208
+ }, {
1209
+ actor: input.actor ?? task.assignee ?? "ops",
1210
+ at: input.at,
1211
+ detail: input.detail ?? "Task reopened",
1212
+ type: "reopened"
1213
+ });
1214
+ var requeueVoiceOpsTask = (task, input = {}) => ensureTaskHistory({
1215
+ ...task,
1216
+ claimExpiresAt: undefined,
1217
+ claimedAt: undefined,
1218
+ claimedBy: undefined,
1219
+ processingError: undefined,
1220
+ status: "open"
1221
+ }, {
1222
+ actor: input.actor ?? task.claimedBy ?? task.assignee ?? "ops",
1223
+ at: input.at,
1224
+ detail: input.detail ?? "Task requeued",
1225
+ type: "requeued"
1226
+ });
1227
+ var resolveVoiceOpsTaskAgeBucket = (task, input = {}) => {
1228
+ const at = input.at ?? Date.now();
1229
+ const freshMs = Math.max(0, input.agingMs ?? 30 * 60000);
1230
+ const staleMs = Math.max(freshMs, input.staleMs ?? 4 * 60 * 60000);
1231
+ const dueSoonMs = Math.max(0, input.dueSoonMs ?? 15 * 60000);
1232
+ const ageMs = Math.max(0, at - task.createdAt);
1233
+ if (isVoiceOpsTaskOverdue(task, { at })) {
1234
+ return ageMs >= staleMs ? "stale" : "overdue";
1235
+ }
1236
+ if (typeof task.dueAt === "number" && task.status !== "done" && task.dueAt - at <= dueSoonMs) {
1237
+ return "due-soon";
1238
+ }
1239
+ if (ageMs >= staleMs) {
1240
+ return "stale";
1241
+ }
1242
+ if (ageMs >= freshMs) {
1243
+ return "aging";
1244
+ }
1245
+ return "fresh";
1246
+ };
1247
+ var resolveVoiceOpsTaskAssignment = (input) => input.rules?.find((rule) => matchesVoiceOpsTaskAssignmentRule(input.task, rule));
1248
+ var resolveVoiceOpsTaskPolicy = (input) => {
1249
+ const { disposition } = input;
1250
+ if (!disposition) {
1251
+ return;
1252
+ }
1253
+ const defaultPolicy = DEFAULT_VOICE_OPS_TASK_POLICIES[disposition];
1254
+ const customPolicy = input.policies?.[disposition];
1255
+ if (!defaultPolicy && !customPolicy) {
1256
+ return;
1257
+ }
1258
+ return {
1259
+ ...defaultPolicy,
1260
+ ...customPolicy
1261
+ };
1262
+ };
1263
+ var startVoiceOpsTask = (task, input = {}) => ensureTaskHistory({
1264
+ ...task,
1265
+ status: "in-progress"
1266
+ }, {
1267
+ actor: input.actor ?? task.assignee ?? "ops",
1268
+ at: input.at,
1269
+ detail: input.detail ?? "Work started",
1270
+ type: "started"
1271
+ });
1272
+ var summarizeVoiceOpsTaskAnalytics = (tasks, input = {}) => {
1273
+ const at = input.at ?? Date.now();
1274
+ const agingBuckets = new Map;
1275
+ const assignees = new Map;
1276
+ const workers = new Map;
1277
+ let totalCompleted = 0;
1278
+ let totalOverdue = 0;
1279
+ for (const task of tasks) {
1280
+ const bucket = resolveVoiceOpsTaskAgeBucket(task, { ...input, at });
1281
+ agingBuckets.set(bucket, (agingBuckets.get(bucket) ?? 0) + 1);
1282
+ if (task.assignee) {
1283
+ const assignee = assignees.get(task.assignee) ?? {
1284
+ claimed: 0,
1285
+ completed: 0,
1286
+ completionMsTotal: 0,
1287
+ completionSamples: 0,
1288
+ inProgress: 0,
1289
+ open: 0,
1290
+ overdue: 0,
1291
+ total: 0
1292
+ };
1293
+ assignee.total += 1;
1294
+ if (task.status === "open") {
1295
+ assignee.open += 1;
1296
+ } else if (task.status === "in-progress") {
1297
+ assignee.inProgress += 1;
1298
+ } else if (task.status === "done") {
1299
+ assignee.completed += 1;
1300
+ }
1301
+ if (task.claimedBy && (!task.claimExpiresAt || task.claimExpiresAt > at)) {
1302
+ assignee.claimed += 1;
1303
+ }
1304
+ if (isVoiceOpsTaskOverdue(task, { at })) {
1305
+ assignee.overdue += 1;
1306
+ }
1307
+ const completedAt = task.history.findLast((entry) => entry.type === "completed")?.at;
1308
+ if (task.status === "done" && typeof completedAt === "number") {
1309
+ assignee.completionMsTotal += Math.max(0, completedAt - task.createdAt);
1310
+ assignee.completionSamples += 1;
1311
+ }
1312
+ assignees.set(task.assignee, assignee);
1313
+ }
1314
+ if (isVoiceOpsTaskOverdue(task, { at })) {
1315
+ totalOverdue += 1;
1316
+ }
1317
+ if (task.status === "done") {
1318
+ totalCompleted += 1;
1319
+ }
1320
+ for (const entry of task.history) {
1321
+ if (!["claimed", "heartbeat", "completed", "failed", "requeued"].includes(entry.type)) {
1322
+ continue;
1323
+ }
1324
+ const worker = workers.get(entry.actor) ?? {
1325
+ activeClaims: 0,
1326
+ completed: 0,
1327
+ failed: 0,
1328
+ heartbeats: 0,
1329
+ requeued: 0,
1330
+ totalClaims: 0
1331
+ };
1332
+ if (entry.type === "claimed") {
1333
+ worker.totalClaims += 1;
1334
+ } else if (entry.type === "heartbeat") {
1335
+ worker.heartbeats += 1;
1336
+ } else if (entry.type === "completed") {
1337
+ worker.completed += 1;
1338
+ } else if (entry.type === "failed") {
1339
+ worker.failed += 1;
1340
+ } else if (entry.type === "requeued") {
1341
+ worker.requeued += 1;
1342
+ }
1343
+ workers.set(entry.actor, worker);
1344
+ }
1345
+ if (task.claimedBy && (!task.claimExpiresAt || task.claimExpiresAt > at)) {
1346
+ const worker = workers.get(task.claimedBy) ?? {
1347
+ activeClaims: 0,
1348
+ completed: 0,
1349
+ failed: 0,
1350
+ heartbeats: 0,
1351
+ requeued: 0,
1352
+ totalClaims: 0
1353
+ };
1354
+ worker.activeClaims += 1;
1355
+ workers.set(task.claimedBy, worker);
1356
+ }
1357
+ }
1358
+ return {
1359
+ agingBuckets: [...agingBuckets.entries()].sort((left, right) => right[1] - left[1]),
1360
+ assignees: [...assignees.entries()].map(([assignee, value]) => ({
1361
+ assignee,
1362
+ averageCompletionMs: value.completionSamples > 0 ? value.completionMsTotal / value.completionSamples : undefined,
1363
+ claimed: value.claimed,
1364
+ completed: value.completed,
1365
+ inProgress: value.inProgress,
1366
+ open: value.open,
1367
+ overdue: value.overdue,
1368
+ total: value.total
1369
+ })).sort((left, right) => right.total - left.total),
1370
+ totalCompleted,
1371
+ totalOverdue,
1372
+ totalTasks: tasks.length,
1373
+ workers: [...workers.entries()].map(([workerId, value]) => ({
1374
+ activeClaims: value.activeClaims,
1375
+ completed: value.completed,
1376
+ failed: value.failed,
1377
+ heartbeats: value.heartbeats,
1378
+ requeued: value.requeued,
1379
+ totalClaims: value.totalClaims,
1380
+ workerId
1381
+ })).sort((left, right) => right.totalClaims - left.totalClaims)
1382
+ };
1383
+ };
1384
+ var summarizeVoiceOpsTasks = (tasks) => {
1385
+ const summary = {
1386
+ byClaimedBy: new Map,
1387
+ byKind: new Map,
1388
+ byOutcome: new Map,
1389
+ byPriority: new Map,
1390
+ byQueue: new Map,
1391
+ claimed: 0,
1392
+ done: 0,
1393
+ inProgress: 0,
1394
+ open: 0,
1395
+ overdue: 0,
1396
+ topAssignees: new Map,
1397
+ topQueues: new Map,
1398
+ topTargets: new Map,
1399
+ total: tasks.length
1400
+ };
1401
+ for (const task of tasks) {
1402
+ if (task.status === "open") {
1403
+ summary.open += 1;
1404
+ } else if (task.status === "in-progress") {
1405
+ summary.inProgress += 1;
1406
+ } else if (task.status === "done") {
1407
+ summary.done += 1;
1408
+ }
1409
+ if (task.claimedBy && (!task.claimExpiresAt || task.claimExpiresAt > Date.now())) {
1410
+ summary.claimed += 1;
1411
+ summary.byClaimedBy.set(task.claimedBy, (summary.byClaimedBy.get(task.claimedBy) ?? 0) + 1);
1412
+ }
1413
+ summary.byKind.set(task.kind, (summary.byKind.get(task.kind) ?? 0) + 1);
1414
+ if (task.outcome) {
1415
+ summary.byOutcome.set(task.outcome, (summary.byOutcome.get(task.outcome) ?? 0) + 1);
1416
+ }
1417
+ if (task.target) {
1418
+ summary.topTargets.set(task.target, (summary.topTargets.get(task.target) ?? 0) + 1);
1419
+ }
1420
+ if (task.assignee) {
1421
+ summary.topAssignees.set(task.assignee, (summary.topAssignees.get(task.assignee) ?? 0) + 1);
1422
+ }
1423
+ if (task.priority) {
1424
+ summary.byPriority.set(task.priority, (summary.byPriority.get(task.priority) ?? 0) + 1);
1425
+ }
1426
+ if (task.queue) {
1427
+ summary.byQueue.set(task.queue, (summary.byQueue.get(task.queue) ?? 0) + 1);
1428
+ summary.topQueues.set(task.queue, (summary.topQueues.get(task.queue) ?? 0) + 1);
1429
+ }
1430
+ if (isVoiceOpsTaskOverdue(task)) {
1431
+ summary.overdue += 1;
1432
+ }
1433
+ }
1434
+ return {
1435
+ byClaimedBy: [...summary.byClaimedBy.entries()].sort((left, right) => right[1] - left[1]),
1436
+ byKind: [...summary.byKind.entries()].sort((left, right) => right[1] - left[1]),
1437
+ byOutcome: [...summary.byOutcome.entries()].sort((left, right) => right[1] - left[1]),
1438
+ byPriority: [...summary.byPriority.entries()].sort((left, right) => right[1] - left[1]),
1439
+ byQueue: [...summary.byQueue.entries()].sort((left, right) => right[1] - left[1]),
1440
+ claimed: summary.claimed,
1441
+ done: summary.done,
1442
+ inProgress: summary.inProgress,
1443
+ open: summary.open,
1444
+ overdue: summary.overdue,
1445
+ topAssignees: [...summary.topAssignees.entries()].sort((left, right) => right[1] - left[1]),
1446
+ topQueues: [...summary.topQueues.entries()].sort((left, right) => right[1] - left[1]),
1447
+ topTargets: [...summary.topTargets.entries()].sort((left, right) => right[1] - left[1]),
1448
+ total: summary.total
1449
+ };
1450
+ };
1451
+
1452
+ // src/core/store.ts
1453
+ var createId = () => crypto.randomUUID();
1454
+ var createVoiceSessionRecord = (id, scenarioId) => ({
1455
+ committedTurnIds: [],
1456
+ createdAt: Date.now(),
1457
+ currentTurn: {
1458
+ finalText: "",
1459
+ lastSpeechAt: undefined,
1460
+ lastTranscriptAt: undefined,
1461
+ partialEndedAt: undefined,
1462
+ partialStartedAt: undefined,
1463
+ partialText: "",
1464
+ silenceStartedAt: undefined,
1465
+ transcripts: []
1466
+ },
1467
+ id,
1468
+ scenarioId,
1469
+ reconnect: { attempts: 0 },
1470
+ status: "active",
1471
+ transcripts: [],
1472
+ turns: [],
1473
+ lastCommittedTurn: {
1474
+ committedAt: 0,
1475
+ signature: "",
1476
+ text: "",
1477
+ transcriptIds: []
1478
+ }
1479
+ });
1480
+ var resetVoiceSessionRecord = (id, existing, scenarioId) => ({
1481
+ ...createVoiceSessionRecord(id, scenarioId),
1482
+ metadata: existing?.metadata
1483
+ });
1484
+ var toVoiceSessionSummary = (session) => ({
1485
+ createdAt: session.createdAt,
1486
+ id: session.id,
1487
+ lastActivityAt: session.lastActivityAt,
1488
+ status: session.status,
1489
+ turnCount: session.turns.length
1490
+ });
1491
+
1492
+ // src/internal/html.ts
1493
+ var escapeHtml = (value) => String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1494
+
1495
+ // src/core/trace.ts
1496
+ var createVoiceTraceEvent = (event) => ({
1497
+ ...event,
1498
+ at: event.at,
1499
+ id: event.id ?? createVoiceTraceEventId({
1500
+ at: event.at,
1501
+ sessionId: event.sessionId,
1502
+ turnId: event.turnId,
1503
+ type: event.type
1504
+ })
1505
+ });
1506
+ var createVoiceTraceEventId = (event) => [
1507
+ event.sessionId,
1508
+ event.turnId ?? "session",
1509
+ event.type,
1510
+ String(event.at ?? Date.now()),
1511
+ crypto.randomUUID()
1512
+ ].map(encodeURIComponent).join(":");
1513
+ var createVoiceTraceSinkDeliveryId = (events) => {
1514
+ const firstEvent = events[0];
1515
+ return [
1516
+ firstEvent?.sessionId ?? "trace",
1517
+ firstEvent?.traceId ?? "sink",
1518
+ String(firstEvent?.at ?? Date.now()),
1519
+ crypto.randomUUID()
1520
+ ].map(encodeURIComponent).join(":");
1521
+ };
1522
+ var createVoiceTraceSinkDeliveryRecord = (input) => {
1523
+ const createdAt = input.createdAt ?? Date.now();
1524
+ return {
1525
+ createdAt,
1526
+ deliveredAt: input.deliveredAt,
1527
+ deliveryAttempts: input.deliveryAttempts,
1528
+ deliveryError: input.deliveryError,
1529
+ deliveryStatus: input.deliveryStatus ?? "pending",
1530
+ events: input.events,
1531
+ id: input.id ?? createVoiceTraceSinkDeliveryId(input.events),
1532
+ sinkDeliveries: input.sinkDeliveries,
1533
+ updatedAt: input.updatedAt ?? createdAt
1534
+ };
1535
+ };
1536
+ var matchesTraceFilter = (event, filter) => {
1537
+ if (filter.sessionId !== undefined && event.sessionId !== filter.sessionId) {
1538
+ return false;
1539
+ }
1540
+ if (filter.turnId !== undefined && event.turnId !== filter.turnId) {
1541
+ return false;
1542
+ }
1543
+ if (filter.scenarioId !== undefined && event.scenarioId !== filter.scenarioId) {
1544
+ return false;
1545
+ }
1546
+ if (filter.traceId !== undefined && event.traceId !== filter.traceId) {
1547
+ return false;
1548
+ }
1549
+ if (filter.type !== undefined) {
1550
+ const types = Array.isArray(filter.type) ? filter.type : [filter.type];
1551
+ if (!types.includes(event.type)) {
1552
+ return false;
1553
+ }
1554
+ }
1555
+ return true;
1556
+ };
1557
+ var createVoiceProofTraceStore = (options = {}) => {
1558
+ const proofStore = options.proofStore ?? createVoiceMemoryTraceEventStore();
1559
+ const scopedProofStore = options.scope ? createVoiceScopedTraceEventStore(proofStore, options.scope) : proofStore;
1560
+ return {
1561
+ append: async (event) => {
1562
+ const stored = await proofStore.append(event);
1563
+ await options.mirrorStore?.append(stored);
1564
+ return stored;
1565
+ },
1566
+ get: async (id) => await proofStore.get(id) ?? await options.mirrorStore?.get(id),
1567
+ list: (filter) => scopedProofStore.list(filter),
1568
+ remove: async (id) => {
1569
+ await Promise.all([
1570
+ proofStore.remove(id),
1571
+ options.mirrorStore?.remove(id) ?? Promise.resolve()
1572
+ ]);
1573
+ }
1574
+ };
1575
+ };
1576
+ var createVoiceScopedTraceEventStore = (store, scope) => {
1577
+ const upstreamFilter = (filter = {}) => {
1578
+ const next = { ...filter };
1579
+ delete next.limit;
1580
+ if (scope.scenarioId !== undefined) {
1581
+ delete next.scenarioId;
1582
+ }
1583
+ if (scope.sessionId !== undefined) {
1584
+ delete next.sessionId;
1585
+ }
1586
+ if (scope.traceId !== undefined) {
1587
+ delete next.traceId;
1588
+ }
1589
+ if (scope.turnId !== undefined) {
1590
+ delete next.turnId;
1591
+ }
1592
+ if (scope.type !== undefined) {
1593
+ delete next.type;
1594
+ }
1595
+ return next;
1596
+ };
1597
+ const scopedFilter = (filter = {}) => ({
1598
+ ...filter,
1599
+ ...scope
1600
+ });
1601
+ return {
1602
+ append: (event) => store.append(event),
1603
+ get: (id) => store.get(id),
1604
+ list: async (filter) => filterVoiceTraceEvents(await store.list(upstreamFilter(filter)), scopedFilter(filter)),
1605
+ remove: (id) => store.remove(id)
1606
+ };
1607
+ };
1608
+ var filterVoiceTraceEvents = (events, filter = {}) => {
1609
+ const sorted = events.filter((event) => matchesTraceFilter(event, filter)).sort((left, right) => left.at - right.at || left.id.localeCompare(right.id));
1610
+ return typeof filter.limit === "number" && filter.limit >= 0 ? sorted.slice(0, filter.limit) : sorted;
1611
+ };
1612
+ var isPruneTimeMatch = (event, options) => {
1613
+ if (typeof options.before === "number" && event.at >= options.before) {
1614
+ return false;
1615
+ }
1616
+ if (typeof options.beforeOrAt === "number" && event.at > options.beforeOrAt) {
1617
+ return false;
1618
+ }
1619
+ return true;
1620
+ };
1621
+ var pruneVoiceTraceEvents = async (options) => {
1622
+ const events = await options.store.list(options.filter);
1623
+ const deleted = selectVoiceTraceEventsForPrune(events, options);
1624
+ if (!options.dryRun) {
1625
+ await Promise.all(deleted.map((event) => options.store.remove(event.id)));
1626
+ }
1627
+ return {
1628
+ deleted,
1629
+ deletedCount: deleted.length,
1630
+ dryRun: Boolean(options.dryRun),
1631
+ scannedCount: events.length
1632
+ };
1633
+ };
1634
+ var selectVoiceTraceEventsForPrune = (events, options = {}) => {
1635
+ let candidates = filterVoiceTraceEvents(events, options.filter).filter((event) => isPruneTimeMatch(event, options));
1636
+ if (typeof options.keepNewest === "number" && options.keepNewest >= 0) {
1637
+ const newestIds = new Set([...candidates].sort((left, right) => right.at - left.at || right.id.localeCompare(left.id)).slice(0, options.keepNewest).map((event) => event.id));
1638
+ candidates = candidates.filter((event) => !newestIds.has(event.id));
1639
+ }
1640
+ return typeof options.limit === "number" && options.limit >= 0 ? candidates.slice(0, options.limit) : candidates;
1641
+ };
1642
+ var sleep2 = async (delayMs) => {
1643
+ if (delayMs <= 0) {
1644
+ return;
1645
+ }
1646
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1647
+ };
1648
+ var toHex2 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
1649
+ var signVoiceTraceSinkBody = async (input) => {
1650
+ const encoder = new TextEncoder;
1651
+ const key = await crypto.subtle.importKey("raw", encoder.encode(input.secret), {
1652
+ hash: "SHA-256",
1653
+ name: "HMAC"
1654
+ }, false, ["sign"]);
1655
+ const payload = encoder.encode(`${input.timestamp}.${input.body}`);
1656
+ const signature = await crypto.subtle.sign("HMAC", key, payload);
1657
+ return `sha256=${toHex2(new Uint8Array(signature))}`;
1658
+ };
1659
+ var createVoiceTraceSinkDeliveryError = (input) => {
1660
+ if (input.response) {
1661
+ const statusText = input.response.statusText?.trim();
1662
+ return `Attempt ${input.attempt} failed with trace sink response ${input.response.status}${statusText ? ` ${statusText}` : ""}.`;
1663
+ }
1664
+ if (input.error instanceof Error) {
1665
+ return `Attempt ${input.attempt} failed: ${input.error.message}`;
1666
+ }
1667
+ return `Attempt ${input.attempt} failed: ${String(input.error)}`;
1668
+ };
1669
+ var normalizeVoiceTraceS3KeyPrefix = (prefix) => prefix?.trim().replace(/^\/+|\/+$/g, "") ?? "voice/trace-deliveries";
1670
+ var createVoiceTraceS3ObjectKey = (prefix, events) => {
1671
+ const firstEvent = events[0];
1672
+ const safeSessionId = encodeURIComponent(firstEvent?.sessionId ?? "trace");
1673
+ const safeEventId = encodeURIComponent(firstEvent?.id ?? crypto.randomUUID());
1674
+ return `${prefix}/${safeSessionId}/${Date.now()}-${safeEventId}.json`;
1675
+ };
1676
+ var resolveVoiceS3DeliveredTo = (options, key) => {
1677
+ const { bucket } = options;
1678
+ return bucket ? `s3://${bucket}/${key}` : `s3://${key}`;
1679
+ };
1680
+ var aggregateVoiceTraceSinkDeliveryStatus = (deliveries) => {
1681
+ const statuses = Object.values(deliveries).map((delivery) => delivery.status);
1682
+ if (statuses.length === 0 || statuses.every((status) => status === "skipped")) {
1683
+ return "skipped";
1684
+ }
1685
+ if (statuses.some((status) => status === "failed")) {
1686
+ return "failed";
1687
+ }
1688
+ return "delivered";
1689
+ };
1690
+ var createVoiceTraceHTTPSink = (options) => ({
1691
+ eventTypes: options.eventTypes,
1692
+ id: options.id,
1693
+ kind: options.kind ?? "http",
1694
+ deliver: async ({ events }) => {
1695
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1696
+ if (typeof fetchImpl !== "function") {
1697
+ return {
1698
+ attempts: 0,
1699
+ deliveredTo: options.url,
1700
+ error: "Trace sink delivery failed: fetch is not available in this runtime.",
1701
+ eventCount: events.length,
1702
+ status: "failed"
1703
+ };
1704
+ }
1705
+ const maxRetries = Math.max(0, options.retries ?? 0);
1706
+ const backoffMs = Math.max(0, options.backoffMs ?? 250);
1707
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 1e4);
1708
+ const payload = options.body ? await options.body({ events }) : {
1709
+ eventCount: events.length,
1710
+ events,
1711
+ source: "absolutejs-voice"
1712
+ };
1713
+ const body = JSON.stringify(payload);
1714
+ let lastError = "Trace sink delivery failed.";
1715
+ for (let attempt = 1;attempt <= maxRetries + 1; attempt += 1) {
1716
+ let controller;
1717
+ let timeout;
1718
+ try {
1719
+ const headers = {
1720
+ "content-type": "application/json",
1721
+ ...options.headers
1722
+ };
1723
+ if (options.signingSecret) {
1724
+ const timestamp = String(Date.now());
1725
+ headers["x-absolutejs-timestamp"] = timestamp;
1726
+ headers["x-absolutejs-signature"] = await signVoiceTraceSinkBody({
1727
+ body,
1728
+ secret: options.signingSecret,
1729
+ timestamp
1730
+ });
1731
+ }
1732
+ controller = timeoutMs > 0 ? new AbortController : undefined;
1733
+ if (controller && timeoutMs > 0) {
1734
+ timeout = setTimeout(() => controller?.abort(), timeoutMs);
1735
+ }
1736
+ const response = await fetchImpl(options.url, {
1737
+ body,
1738
+ headers,
1739
+ method: options.method ?? "POST",
1740
+ signal: controller?.signal
1741
+ });
1742
+ if (response.ok) {
1743
+ let responseBody;
1744
+ try {
1745
+ responseBody = await response.clone().json();
1746
+ } catch {
1747
+ responseBody = undefined;
1748
+ }
1749
+ return {
1750
+ attempts: attempt,
1751
+ deliveredAt: Date.now(),
1752
+ deliveredTo: options.url,
1753
+ eventCount: events.length,
1754
+ responseBody,
1755
+ status: "delivered"
1756
+ };
1757
+ }
1758
+ lastError = createVoiceTraceSinkDeliveryError({
1759
+ attempt,
1760
+ response
1761
+ });
1762
+ } catch (error) {
1763
+ lastError = createVoiceTraceSinkDeliveryError({
1764
+ attempt,
1765
+ error
1766
+ });
1767
+ } finally {
1768
+ if (timeout) {
1769
+ clearTimeout(timeout);
1770
+ }
1771
+ }
1772
+ if (attempt <= maxRetries) {
1773
+ await sleep2(backoffMs * attempt);
1774
+ }
1775
+ }
1776
+ return {
1777
+ attempts: maxRetries + 1,
1778
+ deliveredTo: options.url,
1779
+ error: lastError,
1780
+ eventCount: events.length,
1781
+ status: "failed"
1782
+ };
1783
+ }
1784
+ });
1785
+ var createVoiceTraceS3Sink = (options) => {
1786
+ const client = options.client ?? new Bun.S3Client(options);
1787
+ const keyPrefix = normalizeVoiceTraceS3KeyPrefix(options.keyPrefix);
1788
+ return {
1789
+ eventTypes: options.eventTypes,
1790
+ id: options.id,
1791
+ kind: options.kind ?? "s3",
1792
+ deliver: async ({ events }) => {
1793
+ const key = createVoiceTraceS3ObjectKey(keyPrefix, events);
1794
+ const payload = options.body ? await options.body({ events, key }) : {
1795
+ eventCount: events.length,
1796
+ events,
1797
+ key,
1798
+ source: "absolutejs-voice"
1799
+ };
1800
+ try {
1801
+ const file = client.file(key, options);
1802
+ await file.write(JSON.stringify(payload), {
1803
+ type: options.contentType ?? "application/json"
1804
+ });
1805
+ return {
1806
+ attempts: 1,
1807
+ deliveredAt: Date.now(),
1808
+ deliveredTo: resolveVoiceS3DeliveredTo(options, key),
1809
+ eventCount: events.length,
1810
+ responseBody: { key },
1811
+ status: "delivered"
1812
+ };
1813
+ } catch (error) {
1814
+ return {
1815
+ attempts: 1,
1816
+ deliveredTo: resolveVoiceS3DeliveredTo(options, key),
1817
+ error: error instanceof Error ? error.message : String(error),
1818
+ eventCount: events.length,
1819
+ status: "failed"
1820
+ };
1821
+ }
1822
+ }
1823
+ };
1824
+ };
1825
+ var createVoiceTraceSinkStore = (options) => {
1826
+ const deliver = async (event) => {
1827
+ const result = await deliverVoiceTraceEventsToSinks({
1828
+ events: [event],
1829
+ redact: options.redact,
1830
+ sinks: options.sinks
1831
+ });
1832
+ await options.onDelivery?.(result);
1833
+ };
1834
+ return {
1835
+ append: async (event) => {
1836
+ const stored = await options.store.append(event);
1837
+ if (options.deliveryQueue) {
1838
+ const delivery2 = createVoiceTraceSinkDeliveryRecord({
1839
+ events: [stored]
1840
+ });
1841
+ await options.deliveryQueue.set(delivery2.id, delivery2);
1842
+ return stored;
1843
+ }
1844
+ const delivery = deliver(stored);
1845
+ if (options.awaitDelivery) {
1846
+ await delivery;
1847
+ } else {
1848
+ delivery.catch((error) => {
1849
+ options.onError?.(error);
1850
+ });
1851
+ }
1852
+ return stored;
1853
+ },
1854
+ get: (id) => options.store.get(id),
1855
+ list: (filter) => options.store.list(filter),
1856
+ remove: (id) => options.store.remove(id)
1857
+ };
1858
+ };
1859
+ var deliverVoiceTraceEventsToSinks = async (input) => {
1860
+ const events = input.redact ? redactVoiceTraceEvents(input.events, input.redact) : input.events;
1861
+ const sinkDeliveries = {};
1862
+ for (const sink of input.sinks) {
1863
+ const sinkEvents = sink.eventTypes?.length ? events.filter((event) => sink.eventTypes?.includes(event.type)) : events;
1864
+ if (sinkEvents.length === 0) {
1865
+ sinkDeliveries[sink.id] = {
1866
+ attempts: 0,
1867
+ eventCount: 0,
1868
+ status: "skipped"
1869
+ };
1870
+ continue;
1871
+ }
1872
+ try {
1873
+ sinkDeliveries[sink.id] = await sink.deliver({
1874
+ events: sinkEvents
1875
+ });
1876
+ } catch (error) {
1877
+ sinkDeliveries[sink.id] = {
1878
+ attempts: 1,
1879
+ error: error instanceof Error ? error.message : String(error),
1880
+ eventCount: sinkEvents.length,
1881
+ status: "failed"
1882
+ };
1883
+ }
1884
+ }
1885
+ return {
1886
+ deliveredAt: Date.now(),
1887
+ eventCount: events.length,
1888
+ sinkDeliveries,
1889
+ status: aggregateVoiceTraceSinkDeliveryStatus(sinkDeliveries)
1890
+ };
1891
+ };
1892
+ var normalizeVoiceProfileTraceTaggerProfile = (profile) => typeof profile === "string" ? { id: profile } : profile?.id ? profile : undefined;
1893
+ var createVoiceMemoryTraceEventStore = () => {
1894
+ const events = new Map;
1895
+ const append = async (event) => {
1896
+ const stored = createVoiceTraceEvent(event);
1897
+ events.set(stored.id, stored);
1898
+ return stored;
1899
+ };
1900
+ const get = async (id) => events.get(id);
1901
+ const list = async (filter) => filterVoiceTraceEvents([...events.values()], filter);
1902
+ const remove = async (id) => {
1903
+ events.delete(id);
1904
+ };
1905
+ return { append, get, list, remove };
1906
+ };
1907
+ var createVoiceMemoryTraceSinkDeliveryStore = () => {
1908
+ const deliveries = new Map;
1909
+ return {
1910
+ get: async (id) => deliveries.get(id),
1911
+ list: async () => [...deliveries.values()].sort((left, right) => left.createdAt - right.createdAt || left.id.localeCompare(right.id)),
1912
+ remove: async (id) => {
1913
+ deliveries.delete(id);
1914
+ },
1915
+ set: async (id, delivery) => {
1916
+ deliveries.set(id, delivery);
1917
+ }
1918
+ };
1919
+ };
1920
+ var createVoiceProfileTraceTagger = (options) => {
1921
+ const profiles = new Map((options.profiles ?? []).map((profile) => [profile.id, profile]));
1922
+ const defaultProfile = normalizeVoiceProfileTraceTaggerProfile(options.defaultProfile);
1923
+ const resolveProfile = async (event) => {
1924
+ const resolved = normalizeVoiceProfileTraceTaggerProfile(await options.resolveProfile?.(event));
1925
+ const profile = resolved ?? defaultProfile;
1926
+ return profile ? profiles.get(profile.id) ?? profile : undefined;
1927
+ };
1928
+ return {
1929
+ append: async (event) => {
1930
+ const profile = await resolveProfile(event);
1931
+ if (!profile) {
1932
+ return options.store.append(event);
1933
+ }
1934
+ const metadata = {
1935
+ ...event.metadata ?? {},
1936
+ benchmarkProfileId: profile.id,
1937
+ profileDescription: event.metadata?.profileDescription ?? profile.description,
1938
+ profileId: profile.id,
1939
+ profileLabel: event.metadata?.profileLabel ?? profile.label
1940
+ };
1941
+ const payload = event.payload && typeof event.payload === "object" ? {
1942
+ ...event.payload,
1943
+ benchmarkProfileId: event.payload.benchmarkProfileId ?? profile.id,
1944
+ profileDescription: event.payload.profileDescription ?? profile.description,
1945
+ profileId: event.payload.profileId ?? profile.id,
1946
+ profileLabel: event.payload.profileLabel ?? profile.label
1947
+ } : event.payload;
1948
+ return options.store.append({
1949
+ ...event,
1950
+ metadata,
1951
+ payload
1952
+ });
1953
+ },
1954
+ get: (id) => options.store.get(id),
1955
+ list: (filter) => options.store.list(filter),
1956
+ remove: (id) => options.store.remove(id)
1957
+ };
1958
+ };
1959
+ var exportVoiceTrace = async (input) => {
1960
+ const events = await input.store.list(input.filter);
1961
+ return {
1962
+ exportedAt: Date.now(),
1963
+ events: input.redact ? redactVoiceTraceEvents(events, input.redact) : events,
1964
+ filter: input.filter,
1965
+ redacted: Boolean(input.redact)
1966
+ };
1967
+ };
1968
+ var toNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
1969
+ var formatTraceValue = (value) => {
1970
+ if (value === undefined || value === null) {
1971
+ return "";
1972
+ }
1973
+ if (typeof value === "string") {
1974
+ return value;
1975
+ }
1976
+ if (typeof value === "number" || typeof value === "boolean") {
1977
+ return String(value);
1978
+ }
1979
+ try {
1980
+ return JSON.stringify(value);
1981
+ } catch {
1982
+ return String(value);
1983
+ }
1984
+ };
1985
+ var DEFAULT_REDACTION_KEYS = [
1986
+ "apiKey",
1987
+ "authorization",
1988
+ "creditCard",
1989
+ "email",
1990
+ "externalId",
1991
+ "password",
1992
+ "phone",
1993
+ "secret",
1994
+ "ssn",
1995
+ "token"
1996
+ ];
1997
+ var DEFAULT_REDACTION_TEXT_KEYS = [
1998
+ "assistantText",
1999
+ "content",
2000
+ "error",
2001
+ "reason",
2002
+ "summary",
2003
+ "text"
2004
+ ];
2005
+ var EMAIL_PATTERN = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
2006
+ var PHONE_PATTERN = /(?<!\d)(?:\+?1[\s.-]?)?(?:\(?\d{3}\)?[\s.-]?)\d{3}[\s.-]?\d{4}(?!\d)/g;
2007
+ var normalizeRedactionKey = (key) => key.trim().toLowerCase().replace(/[^a-z0-9]/g, "");
2008
+ var resolveVoiceTraceRedactionOptions = (options = {}) => ({
2009
+ keys: typeof options === "boolean" ? DEFAULT_REDACTION_KEYS : options.keys ?? DEFAULT_REDACTION_KEYS,
2010
+ redactEmails: typeof options === "boolean" ? true : options.redactEmails ?? true,
2011
+ redactPhoneNumbers: typeof options === "boolean" ? true : options.redactPhoneNumbers ?? true,
2012
+ redactText: typeof options === "boolean" ? true : options.redactText ?? true,
2013
+ replacement: typeof options === "boolean" ? "[redacted]" : options.replacement ?? "[redacted]",
2014
+ textKeys: typeof options === "boolean" ? DEFAULT_REDACTION_TEXT_KEYS : options.textKeys ?? DEFAULT_REDACTION_TEXT_KEYS
2015
+ });
2016
+ var resolveReplacement = (input) => typeof input.options.replacement === "function" ? input.options.replacement({
2017
+ key: input.key,
2018
+ path: input.path,
2019
+ value: input.value
2020
+ }) : input.options.replacement;
2021
+ var redactVoiceTraceText = (value, options = {}, input = {}) => {
2022
+ const resolved = resolveVoiceTraceRedactionOptions(options);
2023
+ let redacted = value;
2024
+ const replacement = resolveReplacement({
2025
+ key: input.key,
2026
+ options: resolved,
2027
+ path: input.path ?? [],
2028
+ value
2029
+ });
2030
+ if (resolved.redactEmails) {
2031
+ redacted = redacted.replace(EMAIL_PATTERN, replacement);
2032
+ }
2033
+ if (resolved.redactPhoneNumbers) {
2034
+ redacted = redacted.replace(PHONE_PATTERN, replacement);
2035
+ }
2036
+ return redacted;
2037
+ };
2038
+ var redactTraceValue = (value, options, path) => {
2039
+ const key = path.at(-1);
2040
+ const normalizedKey = key ? normalizeRedactionKey(key) : undefined;
2041
+ const sensitiveKeys = new Set(options.keys.map(normalizeRedactionKey));
2042
+ const textKeys = new Set(options.textKeys.map(normalizeRedactionKey));
2043
+ if (normalizedKey && sensitiveKeys.has(normalizedKey) && (value === null || ["boolean", "number", "string", "undefined"].includes(typeof value))) {
2044
+ return resolveReplacement({
2045
+ key,
2046
+ options,
2047
+ path,
2048
+ value: String(value ?? "")
2049
+ });
2050
+ }
2051
+ if (typeof value === "string") {
2052
+ const shouldRedactText = options.redactText && (!normalizedKey || textKeys.has(normalizedKey) || path.length === 0);
2053
+ return shouldRedactText ? redactVoiceTraceText(value, options, {
2054
+ key,
2055
+ path
2056
+ }) : value;
2057
+ }
2058
+ if (Array.isArray(value)) {
2059
+ return value.map((item, index) => redactTraceValue(item, options, [...path, String(index)]));
2060
+ }
2061
+ if (typeof value === "object" && value) {
2062
+ return Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [
2063
+ entryKey,
2064
+ redactTraceValue(entryValue, options, [...path, entryKey])
2065
+ ]));
2066
+ }
2067
+ return value;
2068
+ };
2069
+ var evaluateVoiceTrace = (events, options = {}) => {
2070
+ const summary = summarizeVoiceTrace(events);
2071
+ const issues = [];
2072
+ const maxHandoffs = options.maxHandoffs ?? 3;
2073
+ const maxToolErrors = options.maxToolErrors ?? 0;
2074
+ const maxModelCallsPerTurn = options.maxModelCallsPerTurn ?? 6;
2075
+ const turnCountForRatio = Math.max(1, summary.turnCount);
2076
+ if (options.requireCompletedCall !== false && !summary.endedAt) {
2077
+ issues.push({
2078
+ code: "call-not-ended",
2079
+ message: "Trace does not include a call end lifecycle event.",
2080
+ severity: "warning"
2081
+ });
2082
+ }
2083
+ if (summary.failed) {
2084
+ issues.push({
2085
+ code: "session-error",
2086
+ message: "Trace contains a session error or failed call disposition.",
2087
+ severity: "error"
2088
+ });
2089
+ }
2090
+ if (options.requireTranscript !== false && summary.transcriptCount === 0) {
2091
+ issues.push({
2092
+ code: "missing-transcript",
2093
+ message: "Trace does not include any transcript events.",
2094
+ severity: "error"
2095
+ });
2096
+ }
2097
+ if (options.requireTurn !== false && summary.turnCount === 0) {
2098
+ issues.push({
2099
+ code: "missing-turn",
2100
+ message: "Trace does not include any committed turns.",
2101
+ severity: "error"
2102
+ });
2103
+ }
2104
+ if (options.requireAssistantReply !== false && summary.turnCount > 0 && summary.assistantReplyCount === 0) {
2105
+ issues.push({
2106
+ code: "missing-assistant-reply",
2107
+ message: "Trace has committed turns but no assistant replies.",
2108
+ severity: "warning"
2109
+ });
2110
+ }
2111
+ if (summary.toolErrorCount > maxToolErrors) {
2112
+ issues.push({
2113
+ code: "tool-errors",
2114
+ message: `Trace has ${summary.toolErrorCount} tool error(s), above the allowed ${maxToolErrors}.`,
2115
+ severity: "error"
2116
+ });
2117
+ }
2118
+ if (summary.handoffCount > maxHandoffs) {
2119
+ issues.push({
2120
+ code: "too-many-handoffs",
2121
+ message: `Trace has ${summary.handoffCount} handoff(s), above the allowed ${maxHandoffs}.`,
2122
+ severity: "warning"
2123
+ });
2124
+ }
2125
+ if (summary.modelCallCount / turnCountForRatio > maxModelCallsPerTurn) {
2126
+ issues.push({
2127
+ code: "too-many-model-calls",
2128
+ message: `Trace averages more than ${maxModelCallsPerTurn} model calls per committed turn.`,
2129
+ severity: "warning"
2130
+ });
2131
+ }
2132
+ return {
2133
+ issues,
2134
+ pass: !issues.some((issue) => issue.severity === "error"),
2135
+ summary
2136
+ };
2137
+ };
2138
+ var redactVoiceTraceEvent = (event, options = {}) => {
2139
+ const resolved = resolveVoiceTraceRedactionOptions(options);
2140
+ return {
2141
+ ...event,
2142
+ metadata: redactTraceValue(event.metadata, resolved, [
2143
+ "metadata"
2144
+ ]),
2145
+ payload: redactTraceValue(event.payload, resolved, [
2146
+ "payload"
2147
+ ])
2148
+ };
2149
+ };
2150
+ var redactVoiceTraceEvents = (events, options = {}) => events.map((event) => redactVoiceTraceEvent(event, options));
2151
+ var summarizeVoiceTrace = (events) => {
2152
+ const sorted = filterVoiceTraceEvents(events);
2153
+ const firstEvent = sorted[0];
2154
+ const lastEvent = sorted.at(-1);
2155
+ const lifecycleEvents = sorted.filter((event) => event.type === "call.lifecycle");
2156
+ const startEvent = lifecycleEvents.find((event) => event.payload.type === "start");
2157
+ const endEvent = lifecycleEvents.toReversed().find((event) => event.payload.type === "end");
2158
+ const costEvents = sorted.filter((event) => event.type === "turn.cost");
2159
+ const toolEvents = sorted.filter((event) => event.type === "agent.tool");
2160
+ const startedAt = startEvent?.at ?? firstEvent?.at;
2161
+ const endedAt = endEvent?.at ?? lastEvent?.at;
2162
+ const failed = sorted.some((event) => event.type === "session.error") || endEvent?.payload.disposition === "failed";
2163
+ return {
2164
+ assistantReplyCount: sorted.filter((event) => event.type === "turn.assistant").length,
2165
+ callDurationMs: startedAt !== undefined && endedAt !== undefined ? Math.max(0, endedAt - startedAt) : undefined,
2166
+ cost: {
2167
+ estimatedRelativeCostUnits: costEvents.reduce((total, event) => total + toNumber(event.payload.estimatedRelativeCostUnits), 0),
2168
+ totalBillableAudioMs: costEvents.reduce((total, event) => total + toNumber(event.payload.totalBillableAudioMs), 0)
2169
+ },
2170
+ endedAt,
2171
+ errorCount: sorted.filter((event) => event.type === "session.error").length,
2172
+ eventCount: sorted.length,
2173
+ failed,
2174
+ handoffCount: sorted.filter((event) => event.type === "agent.handoff").length,
2175
+ modelCallCount: sorted.filter((event) => event.type === "agent.model").length,
2176
+ sessionId: firstEvent?.sessionId,
2177
+ startedAt,
2178
+ toolCallCount: toolEvents.length,
2179
+ toolErrorCount: toolEvents.filter((event) => event.payload.status === "error").length,
2180
+ traceId: firstEvent?.traceId,
2181
+ transcriptCount: sorted.filter((event) => event.type === "turn.transcript").length,
2182
+ turnCount: sorted.filter((event) => event.type === "turn.committed").length
2183
+ };
2184
+ };
2185
+ var renderTraceEventMarkdown = (event, startedAt) => {
2186
+ const offset = startedAt === undefined ? `${event.at}` : `+${Math.max(0, event.at - startedAt)}ms`;
2187
+ const label = `- ${offset} [${event.type}]`;
2188
+ switch (event.type) {
2189
+ case "turn.transcript":
2190
+ return `${label} ${event.payload.isFinal ? "final" : "partial"} "${formatTraceValue(event.payload.text)}"`;
2191
+ case "turn.committed":
2192
+ return `${label} committed "${formatTraceValue(event.payload.text)}"`;
2193
+ case "turn.assistant":
2194
+ return event.payload.text ? `${label} assistant "${formatTraceValue(event.payload.text)}"` : `${label} ${formatTraceValue(event.payload.status)}`;
2195
+ case "agent.tool":
2196
+ return `${label} ${formatTraceValue(event.payload.toolName)} ${formatTraceValue(event.payload.status)}`;
2197
+ case "agent.context":
2198
+ return `${label} ${formatTraceValue(event.payload.fromAgentId)} -> ${formatTraceValue(event.payload.targetAgentId)} ${formatTraceValue(event.payload.status)}`;
2199
+ case "agent.handoff":
2200
+ return `${label} ${formatTraceValue(event.payload.fromAgentId)} -> ${formatTraceValue(event.payload.targetAgentId)}`;
2201
+ case "session.error":
2202
+ return `${label} ${formatTraceValue(event.payload.error)}`;
2203
+ case "call.lifecycle":
2204
+ return `${label} ${formatTraceValue(event.payload.type)} ${formatTraceValue(event.payload.disposition)}`.trim();
2205
+ default:
2206
+ return `${label} ${formatTraceValue(event.payload)}`;
2207
+ }
2208
+ };
2209
+ var buildVoiceTraceReplay = (events, options = {}) => ({
2210
+ evaluation: evaluateVoiceTrace(options.redact ? redactVoiceTraceEvents(events, options.redact) : events, options.evaluation),
2211
+ html: renderVoiceTraceHTML(events, options),
2212
+ markdown: renderVoiceTraceMarkdown(events, options),
2213
+ summary: summarizeVoiceTrace(options.redact ? redactVoiceTraceEvents(events, options.redact) : events)
2214
+ });
2215
+ var renderVoiceTraceHTML = (events, options = {}) => {
2216
+ const markdown = renderVoiceTraceMarkdown(events, options);
2217
+ const renderEvents = options.redact ? redactVoiceTraceEvents(events, options.redact) : events;
2218
+ const summary = summarizeVoiceTrace(renderEvents);
2219
+ const evaluation = evaluateVoiceTrace(renderEvents, options.evaluation);
2220
+ const eventRows = filterVoiceTraceEvents(renderEvents).map((event) => {
2221
+ const offset = summary.startedAt === undefined ? event.at : Math.max(0, event.at - summary.startedAt);
2222
+ return [
2223
+ "<tr>",
2224
+ `<td>${escapeHtml(String(offset))}</td>`,
2225
+ `<td>${escapeHtml(event.type)}</td>`,
2226
+ `<td>${escapeHtml(event.turnId ?? "")}</td>`,
2227
+ `<td><code>${escapeHtml(JSON.stringify(event.payload))}</code></td>`,
2228
+ "</tr>"
2229
+ ].join("");
2230
+ }).join(`
2231
+ `);
2232
+ return [
2233
+ "<!doctype html>",
2234
+ '<html lang="en">',
2235
+ "<head>",
2236
+ '<meta charset="utf-8" />',
2237
+ '<meta name="viewport" content="width=device-width, initial-scale=1" />',
2238
+ `<title>${escapeHtml(options.title ?? "Voice Trace")}</title>`,
2239
+ "<style>",
2240
+ "body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}",
2241
+ "main{max-width:1100px;margin:auto}",
2242
+ ".summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;margin:1rem 0}",
2243
+ ".card{background:white;border:1px solid #ded9cc;border-radius:12px;padding:1rem}",
2244
+ ".pass{color:#126b3a}.fail{color:#9d2222}",
2245
+ "table{border-collapse:collapse;width:100%;background:white;border:1px solid #ded9cc}",
2246
+ "th,td{border-bottom:1px solid #eee8dc;padding:.65rem;text-align:left;vertical-align:top}",
2247
+ "code{white-space:pre-wrap;word-break:break-word}",
2248
+ "pre{background:#181713;color:#f8f7f2;padding:1rem;border-radius:12px;overflow:auto}",
2249
+ "</style>",
2250
+ "</head>",
2251
+ "<body><main>",
2252
+ `<h1>${escapeHtml(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
2253
+ `<p class="${evaluation.pass ? "pass" : "fail"}">QA: ${evaluation.pass ? "pass" : "fail"}</p>`,
2254
+ '<section class="summary">',
2255
+ `<div class="card"><strong>Events</strong><br>${summary.eventCount}</div>`,
2256
+ `<div class="card"><strong>Turns</strong><br>${summary.turnCount}</div>`,
2257
+ `<div class="card"><strong>Transcripts</strong><br>${summary.transcriptCount}</div>`,
2258
+ `<div class="card"><strong>Tool errors</strong><br>${summary.toolErrorCount}</div>`,
2259
+ `<div class="card"><strong>Cost units</strong><br>${summary.cost.estimatedRelativeCostUnits}</div>`,
2260
+ "</section>",
2261
+ "<h2>Timeline</h2>",
2262
+ "<table><thead><tr><th>Offset ms</th><th>Type</th><th>Turn</th><th>Payload</th></tr></thead><tbody>",
2263
+ eventRows,
2264
+ "</tbody></table>",
2265
+ "<h2>Markdown Export</h2>",
2266
+ `<pre>${escapeHtml(markdown)}</pre>`,
2267
+ "</main></body></html>"
2268
+ ].join(`
2269
+ `);
2270
+ };
2271
+ var renderVoiceTraceMarkdown = (events, options = {}) => {
2272
+ const sorted = filterVoiceTraceEvents(options.redact ? redactVoiceTraceEvents(events, options.redact) : events);
2273
+ const summary = summarizeVoiceTrace(sorted);
2274
+ const evaluation = evaluateVoiceTrace(sorted, options.evaluation);
2275
+ const lines = [
2276
+ `# ${options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim()}`,
2277
+ "",
2278
+ `Pass: ${evaluation.pass ? "yes" : "no"}`,
2279
+ `Session: ${summary.sessionId ?? "unknown"}`,
2280
+ `Events: ${summary.eventCount}`,
2281
+ `Turns: ${summary.turnCount}`,
2282
+ `Transcripts: ${summary.transcriptCount}`,
2283
+ `Assistant replies: ${summary.assistantReplyCount}`,
2284
+ `Model calls: ${summary.modelCallCount}`,
2285
+ `Tool calls: ${summary.toolCallCount}`,
2286
+ `Handoffs: ${summary.handoffCount}`,
2287
+ `Errors: ${summary.errorCount}`,
2288
+ `Estimated cost units: ${summary.cost.estimatedRelativeCostUnits}`,
2289
+ ""
2290
+ ];
2291
+ if (evaluation.issues.length > 0) {
2292
+ lines.push("## Issues", "");
2293
+ for (const issue of evaluation.issues) {
2294
+ lines.push(`- [${issue.severity}] ${issue.code}: ${issue.message}`);
2295
+ }
2296
+ lines.push("");
2297
+ }
2298
+ lines.push("## Timeline", "");
2299
+ for (const event of sorted) {
2300
+ lines.push(renderTraceEventMarkdown(event, summary.startedAt));
2301
+ }
2302
+ return lines.join(`
2303
+ `);
2304
+ };
2305
+
2306
+ // src/testing/review.ts
2307
+ var roundMetric = (value) => typeof value === "number" ? Math.round(value * 100) / 100 : undefined;
2308
+ var formatMetric = (label, value, unit = "ms") => typeof value === "number" ? `${label}: ${roundMetric(value)}${unit}` : undefined;
2309
+ var findTimelineEvent = (timeline, event, source) => timeline.find((entry) => entry.event === event && (source === undefined || entry.source === source));
2310
+ var formatTimelineText = (entry) => {
2311
+ const parts = [`- ${entry.atMs}ms`, `[${entry.source}]`, entry.event];
2312
+ if (entry.text) {
2313
+ parts.push(`"${entry.text}"`);
2314
+ }
2315
+ if (entry.reason) {
2316
+ parts.push(`reason=${entry.reason}`);
2317
+ }
2318
+ if (typeof entry.bytes === "number") {
2319
+ parts.push(`bytes=${entry.bytes}`);
2320
+ }
2321
+ if (typeof entry.confidence === "number") {
2322
+ parts.push(`confidence=${roundMetric(entry.confidence)}`);
2323
+ }
2324
+ if (entry.name) {
2325
+ parts.push(`name=${entry.name}`);
2326
+ }
2327
+ return parts.join(" ");
2328
+ };
2329
+ var isLowSignalTimelineEvent = (entry) => entry.event === "inbound-media" || entry.event === "inbound-silence-pad" || entry.event === "stt-send" || entry.event === "tts-audio";
2330
+ var summarizeTimelineTraffic = (timeline) => {
2331
+ const summaries = new Map;
2332
+ for (const entry of timeline) {
2333
+ const label = entry.event === "inbound-media" ? "inbound media chunks" : entry.event === "inbound-silence-pad" ? "inbound silence padding" : entry.event === "stt-send" ? "STT audio sends" : entry.event === "tts-audio" ? "post-first TTS audio chunks" : undefined;
2334
+ if (!label) {
2335
+ continue;
2336
+ }
2337
+ const summary = summaries.get(label) ?? {
2338
+ audioMs: 0,
2339
+ bytes: 0,
2340
+ count: 0,
2341
+ label
2342
+ };
2343
+ summary.count += 1;
2344
+ summary.bytes += typeof entry.bytes === "number" ? entry.bytes : 0;
2345
+ summary.audioMs = (summary.audioMs ?? 0) + (typeof entry.chunkDurationMs === "number" ? entry.chunkDurationMs : 0);
2346
+ summaries.set(label, summary);
2347
+ }
2348
+ return [...summaries.values()];
2349
+ };
2350
+ var compactTimeline = (timeline) => {
2351
+ const rows = [];
2352
+ let index = 0;
2353
+ while (index < timeline.length) {
2354
+ const current = timeline[index];
2355
+ if (!current) {
2356
+ break;
2357
+ }
2358
+ const isBurstEvent = isLowSignalTimelineEvent(current) || current.event === "media" && current.source === "twilio";
2359
+ if (!isBurstEvent) {
2360
+ rows.push(formatTimelineText(current));
2361
+ index += 1;
2362
+ continue;
2363
+ }
2364
+ let endIndex = index;
2365
+ let totalBytes = typeof current.bytes === "number" ? current.bytes : 0;
2366
+ let totalChunkDurationMs = typeof current.chunkDurationMs === "number" ? current.chunkDurationMs : 0;
2367
+ while (endIndex + 1 < timeline.length) {
2368
+ const next = timeline[endIndex + 1];
2369
+ if (!next) {
2370
+ break;
2371
+ }
2372
+ if (next.event !== current.event || next.source !== current.source) {
2373
+ break;
2374
+ }
2375
+ totalBytes += typeof next.bytes === "number" ? next.bytes : 0;
2376
+ totalChunkDurationMs += typeof next.chunkDurationMs === "number" ? next.chunkDurationMs : 0;
2377
+ endIndex += 1;
2378
+ }
2379
+ const startAt = current.atMs;
2380
+ const endAt = timeline[endIndex]?.atMs ?? current.atMs;
2381
+ const count = endIndex - index + 1;
2382
+ const parts = [
2383
+ `- ${startAt}-${endAt}ms`,
2384
+ `[${current.source}]`,
2385
+ `${current.event} x${count}`
2386
+ ];
2387
+ if (totalBytes > 0) {
2388
+ parts.push(`bytes=${totalBytes}`);
2389
+ }
2390
+ if (totalChunkDurationMs > 0) {
2391
+ parts.push(`audio=${roundMetric(totalChunkDurationMs)}ms`);
2392
+ }
2393
+ rows.push(parts.join(" "));
2394
+ index = endIndex + 1;
2395
+ }
2396
+ return rows;
2397
+ };
2398
+ var createVoiceCallReviewFromLiveTelephonyReport = (report, options = {}) => {
2399
+ const fixture = report.fixtures?.[0];
2400
+ if (!fixture) {
2401
+ throw new Error("Live telephony review requires at least one fixture result.");
2402
+ }
2403
+ const timeline = [...report.trace ?? []].sort((left, right) => left.atMs - right.atMs);
2404
+ const firstPartial = findTimelineEvent(timeline, "partial", "stt");
2405
+ const commitEvent = findTimelineEvent(timeline, "commit", "turn");
2406
+ const firstTtsAudio = findTimelineEvent(timeline, "tts-first-audio", "benchmark");
2407
+ const firstOutboundMedia = findTimelineEvent(timeline, "media", "twilio");
2408
+ const bargeInEvent = findTimelineEvent(timeline, "barge-in", "benchmark");
2409
+ const clearEvent = findTimelineEvent(timeline, "clear", "twilio");
2410
+ const lastSttText = [...timeline].reverse().find((entry) => entry.source === "stt" && (entry.event === "partial" || entry.event === "final") && typeof entry.text === "string" && entry.text.length > 0)?.text ?? undefined;
2411
+ const latencyBreakdown = [
2412
+ typeof firstPartial?.atMs === "number" ? {
2413
+ label: "start to first partial",
2414
+ valueMs: firstPartial.atMs
2415
+ } : undefined,
2416
+ typeof firstPartial?.atMs === "number" && typeof commitEvent?.atMs === "number" ? {
2417
+ label: "first partial to commit",
2418
+ valueMs: commitEvent.atMs - firstPartial.atMs
2419
+ } : undefined,
2420
+ typeof commitEvent?.atMs === "number" && typeof firstTtsAudio?.atMs === "number" ? {
2421
+ label: "commit to first TTS audio",
2422
+ valueMs: firstTtsAudio.atMs - commitEvent.atMs
2423
+ } : undefined,
2424
+ typeof commitEvent?.atMs === "number" && typeof firstOutboundMedia?.atMs === "number" ? {
2425
+ label: "commit to first outbound media",
2426
+ valueMs: firstOutboundMedia.atMs - commitEvent.atMs
2427
+ } : undefined,
2428
+ typeof bargeInEvent?.atMs === "number" && typeof clearEvent?.atMs === "number" ? {
2429
+ label: "barge-in to clear",
2430
+ valueMs: clearEvent.atMs - bargeInEvent.atMs
2431
+ } : undefined
2432
+ ].filter((value) => value !== undefined && value.valueMs >= 0);
2433
+ const notes = [
2434
+ report.variant?.description,
2435
+ firstPartial?.text ? `First partial: "${firstPartial.text}"` : undefined,
2436
+ lastSttText ? `Last STT text: "${lastSttText}"` : undefined
2437
+ ].filter((value) => typeof value === "string" && value.length > 0);
2438
+ return {
2439
+ config: {
2440
+ preset: options.preset,
2441
+ stt: report.variant ? {
2442
+ description: report.variant.description,
2443
+ id: report.variant.id,
2444
+ model: report.variant.model
2445
+ } : undefined,
2446
+ tts: report.ttsConfig,
2447
+ turnDetection: report.turnDetectionConfig
2448
+ },
2449
+ errors: fixture.errors ?? [],
2450
+ expectedText: fixture.expectedText,
2451
+ fixtureId: fixture.fixtureId,
2452
+ generatedAt: report.generatedAt,
2453
+ latencyBreakdown,
2454
+ notes,
2455
+ path: options.path,
2456
+ summary: {
2457
+ clearLatencyMs: roundMetric(fixture.clearLatencyMs),
2458
+ elapsedMs: roundMetric(fixture.elapsedMs),
2459
+ firstOutboundMediaLatencyMs: roundMetric(fixture.firstOutboundMediaLatencyMs),
2460
+ firstTurnLatencyMs: roundMetric(fixture.firstTurnLatencyMs),
2461
+ markLatencyMs: roundMetric(fixture.markLatencyMs),
2462
+ outboundMediaCount: fixture.outboundMediaCount,
2463
+ pass: fixture.passes,
2464
+ termRecall: roundMetric(fixture.termRecall),
2465
+ turnCount: fixture.turnCount,
2466
+ wordErrorRate: roundMetric(fixture.wordErrorRate)
2467
+ },
2468
+ title: fixture.title ?? "Voice Call Review",
2469
+ timeline,
2470
+ transcript: {
2471
+ actual: fixture.actualText,
2472
+ expected: fixture.expectedText
2473
+ }
2474
+ };
2475
+ };
2476
+ var withVoiceCallReviewId = (id, artifact) => ({
2477
+ ...artifact,
2478
+ id
2479
+ });
2480
+ var toErrorMessage = (error) => {
2481
+ if (typeof error === "string" && error.trim().length > 0) {
2482
+ return error;
2483
+ }
2484
+ if (error instanceof Error && error.message.trim().length > 0) {
2485
+ return error.message;
2486
+ }
2487
+ return "Unknown call error";
2488
+ };
2489
+ var createVoiceCallReviewRecorder = (options = {}) => {
2490
+ const now = options.now ?? (() => Date.now());
2491
+ const startedAt = now();
2492
+ const errors = [];
2493
+ const timeline = [];
2494
+ const committedTurns = [];
2495
+ const committedTurnIds = new Set;
2496
+ const push = (source, event, fields = {}) => {
2497
+ timeline.push({
2498
+ atMs: Math.max(0, now() - startedAt),
2499
+ event,
2500
+ source,
2501
+ ...fields
2502
+ });
2503
+ };
2504
+ return {
2505
+ finalize: () => {
2506
+ const sortedTimeline = [...timeline].sort((left, right) => left.atMs - right.atMs);
2507
+ const firstPartial = findTimelineEvent(sortedTimeline, "partial", "stt");
2508
+ const commitEvent = findTimelineEvent(sortedTimeline, "commit", "turn");
2509
+ const firstTtsAudio = findTimelineEvent(sortedTimeline, "tts-first-audio", "benchmark");
2510
+ const firstOutboundMedia = findTimelineEvent(sortedTimeline, "media", "twilio");
2511
+ const bargeInEvent = findTimelineEvent(sortedTimeline, "barge-in", "benchmark");
2512
+ const clearEvent = findTimelineEvent(sortedTimeline, "clear", "twilio");
2513
+ const markEvent = findTimelineEvent(sortedTimeline, "mark", "twilio");
2514
+ const elapsedMs = sortedTimeline.at(-1)?.atMs ?? 0;
2515
+ const lastSttText = [...sortedTimeline].reverse().find((entry) => entry.source === "stt" && (entry.event === "partial" || entry.event === "final") && typeof entry.text === "string" && entry.text.length > 0)?.text ?? undefined;
2516
+ const latencyBreakdown = [
2517
+ typeof firstPartial?.atMs === "number" ? {
2518
+ label: "start to first partial",
2519
+ valueMs: firstPartial.atMs
2520
+ } : undefined,
2521
+ typeof firstPartial?.atMs === "number" && typeof commitEvent?.atMs === "number" ? {
2522
+ label: "first partial to commit",
2523
+ valueMs: commitEvent.atMs - firstPartial.atMs
2524
+ } : undefined,
2525
+ typeof commitEvent?.atMs === "number" && typeof firstTtsAudio?.atMs === "number" ? {
2526
+ label: "commit to first TTS audio",
2527
+ valueMs: firstTtsAudio.atMs - commitEvent.atMs
2528
+ } : undefined,
2529
+ typeof commitEvent?.atMs === "number" && typeof firstOutboundMedia?.atMs === "number" ? {
2530
+ label: "commit to first outbound media",
2531
+ valueMs: firstOutboundMedia.atMs - commitEvent.atMs
2532
+ } : undefined,
2533
+ typeof bargeInEvent?.atMs === "number" && typeof clearEvent?.atMs === "number" ? {
2534
+ label: "barge-in to clear",
2535
+ valueMs: clearEvent.atMs - bargeInEvent.atMs
2536
+ } : undefined
2537
+ ].filter((value) => value !== undefined && value.valueMs >= 0);
2538
+ return {
2539
+ config: options.config,
2540
+ errors,
2541
+ fixtureId: options.fixtureId,
2542
+ generatedAt: now(),
2543
+ latencyBreakdown,
2544
+ notes: [
2545
+ firstPartial?.text ? `First partial: "${firstPartial.text}"` : undefined,
2546
+ lastSttText ? `Last STT text: "${lastSttText}"` : undefined
2547
+ ].filter((value) => typeof value === "string"),
2548
+ path: options.path,
2549
+ summary: {
2550
+ clearLatencyMs: roundMetric(typeof clearEvent?.atMs === "number" && typeof bargeInEvent?.atMs === "number" ? clearEvent.atMs - bargeInEvent.atMs : undefined),
2551
+ elapsedMs: roundMetric(elapsedMs),
2552
+ firstOutboundMediaLatencyMs: roundMetric(firstOutboundMedia?.atMs),
2553
+ firstTurnLatencyMs: roundMetric(commitEvent?.atMs),
2554
+ markLatencyMs: roundMetric(markEvent?.atMs),
2555
+ outboundMediaCount: sortedTimeline.filter((entry) => entry.source === "twilio" && entry.event === "media").length,
2556
+ pass: errors.length === 0,
2557
+ turnCount: committedTurns.length
2558
+ },
2559
+ title: options.title ?? "Voice Call Review",
2560
+ timeline: sortedTimeline,
2561
+ transcript: {
2562
+ actual: committedTurns.join(" ").trim()
2563
+ }
2564
+ };
2565
+ },
2566
+ recordError: (error) => {
2567
+ const message = toErrorMessage(error);
2568
+ errors.push(message);
2569
+ push("turn", "error", {
2570
+ reason: message
2571
+ });
2572
+ },
2573
+ recordTwilioInbound: (input) => {
2574
+ push("twilio", input.event, {
2575
+ bytes: input.bytes,
2576
+ chunkDurationMs: input.chunkDurationMs,
2577
+ name: input.name,
2578
+ reason: input.reason,
2579
+ text: input.text,
2580
+ track: input.track
2581
+ });
2582
+ },
2583
+ recordTwilioOutbound: (input) => {
2584
+ push("twilio", input.event, {
2585
+ bytes: input.bytes,
2586
+ chunkDurationMs: input.chunkDurationMs,
2587
+ name: input.name,
2588
+ reason: input.reason,
2589
+ text: input.text,
2590
+ track: input.track
2591
+ });
2592
+ },
2593
+ recordVoiceMessage: (message) => {
2594
+ switch (message.type) {
2595
+ case "partial":
2596
+ case "final":
2597
+ push("stt", message.type, {
2598
+ confidence: message.transcript.confidence,
2599
+ text: message.transcript.text
2600
+ });
2601
+ return;
2602
+ case "assistant":
2603
+ push("turn", "assistant", {
2604
+ text: message.text
2605
+ });
2606
+ return;
2607
+ case "audio":
2608
+ push("benchmark", timeline.some((entry) => entry.event === "tts-first-audio") ? "tts-audio" : "tts-first-audio", {
2609
+ bytes: Math.floor(message.chunkBase64.length * 3 / 4)
2610
+ });
2611
+ return;
2612
+ case "turn":
2613
+ if (committedTurnIds.has(message.turn.id)) {
2614
+ return;
2615
+ }
2616
+ committedTurnIds.add(message.turn.id);
2617
+ committedTurns.push(message.turn.text);
2618
+ push("turn", "commit", {
2619
+ confidence: message.turn.quality?.averageConfidence,
2620
+ text: message.turn.text
2621
+ });
2622
+ return;
2623
+ case "error":
2624
+ errors.push(message.message);
2625
+ push("turn", "error", {
2626
+ reason: message.message
2627
+ });
2628
+ return;
2629
+ case "complete":
2630
+ push("turn", "complete", {
2631
+ text: message.sessionId
2632
+ });
2633
+ return;
2634
+ case "session":
2635
+ push("turn", "session", {
2636
+ reason: message.status,
2637
+ text: message.sessionId
2638
+ });
2639
+ return;
2640
+ case "pong":
2641
+ push("benchmark", "pong");
2642
+ }
2643
+ }
2644
+ };
2645
+ };
2646
+ var renderConfigSection = (config) => {
2647
+ if (!config) {
2648
+ return "";
2649
+ }
2650
+ return [
2651
+ "## Config",
2652
+ "",
2653
+ "```json",
2654
+ JSON.stringify(config, null, 2),
2655
+ "```"
2656
+ ].join(`
2657
+ `);
2658
+ };
2659
+ var renderTimeline = (timeline) => {
2660
+ const focusedTimeline = timeline.filter((entry) => !isLowSignalTimelineEvent(entry));
2661
+ if (focusedTimeline.length === 0) {
2662
+ return `## Timeline
2663
+
2664
+ _No timeline events captured._`;
2665
+ }
2666
+ const lines = compactTimeline(focusedTimeline);
2667
+ return ["## Timeline", "", ...lines].join(`
2668
+ `);
2669
+ };
2670
+ var renderTransportSummary = (timeline) => {
2671
+ const summaries = summarizeTimelineTraffic(timeline);
2672
+ if (summaries.length === 0) {
2673
+ return "";
2674
+ }
2675
+ return [
2676
+ "## Transport Summary",
2677
+ "",
2678
+ ...summaries.map((summary) => {
2679
+ const parts = [`- ${summary.label}: ${summary.count}`];
2680
+ if (summary.bytes > 0) {
2681
+ parts.push(`${summary.bytes} bytes`);
2682
+ }
2683
+ if ((summary.audioMs ?? 0) > 0) {
2684
+ parts.push(`${roundMetric(summary.audioMs)}ms audio`);
2685
+ }
2686
+ return parts.join(", ");
2687
+ })
2688
+ ].join(`
2689
+ `);
2690
+ };
2691
+ var renderLatencyBreakdown = (breakdown) => {
2692
+ if (breakdown.length === 0) {
2693
+ return "";
2694
+ }
2695
+ return [
2696
+ "## Latency Breakdown",
2697
+ "",
2698
+ ...breakdown.map((entry) => `- ${entry.label}: ${roundMetric(entry.valueMs)}ms`)
2699
+ ].join(`
2700
+ `);
2701
+ };
2702
+ var renderVoiceCallReviewHTML = (artifact) => {
2703
+ const notes = artifact.notes.map((note) => `<li>${escapeHtml(note)}</li>`).join("");
2704
+ const latency = artifact.latencyBreakdown.map((entry) => `<li><strong>${escapeHtml(entry.label)}:</strong> ${roundMetric(entry.valueMs)}ms</li>`).join("");
2705
+ const transport = summarizeTimelineTraffic(artifact.timeline).map((summary) => {
2706
+ const parts = [`${summary.count}`, "events"];
2707
+ if (summary.bytes > 0) {
2708
+ parts.push(`${summary.bytes} bytes`);
2709
+ }
2710
+ if ((summary.audioMs ?? 0) > 0) {
2711
+ parts.push(`${roundMetric(summary.audioMs)}ms audio`);
2712
+ }
2713
+ return `<li><strong>${escapeHtml(summary.label)}:</strong> ${escapeHtml(parts.join(", "))}</li>`;
2714
+ }).join("");
2715
+ const timeline = compactTimeline(artifact.timeline.filter((entry) => !isLowSignalTimelineEvent(entry))).map((line) => `<li>${escapeHtml(line.replace(/^- /u, ""))}</li>`).join("");
2716
+ return `<!doctype html>
2717
+ <html lang="en">
2718
+ <head>
2719
+ <meta charset="utf-8" />
2720
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
2721
+ <title>${escapeHtml(artifact.title)}</title>
2722
+ <style>
2723
+ :root { color-scheme: dark; }
2724
+ body { font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; background: #0b0d10; color: #f4f4f5; }
2725
+ main { max-width: 980px; margin: 0 auto; display: grid; gap: 16px; }
2726
+ section { background: #13161b; border: 1px solid #232833; border-radius: 16px; padding: 18px; }
2727
+ h1, h2 { margin: 0 0 12px; }
2728
+ ul { margin: 0; padding-left: 20px; display: grid; gap: 8px; }
2729
+ code, pre { font-family: ui-monospace, SFMono-Regular, monospace; }
2730
+ pre { white-space: pre-wrap; overflow-wrap: anywhere; background: #0f1217; border-radius: 12px; padding: 14px; border: 1px solid #232833; }
2731
+ .grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
2732
+ .metric { display: grid; gap: 4px; }
2733
+ .label { color: #a1a1aa; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.08em; }
2734
+ .value { font-size: 1.05rem; }
2735
+ </style>
2736
+ </head>
2737
+ <body>
2738
+ <main>
2739
+ <section>
2740
+ <h1>${escapeHtml(artifact.title)}</h1>
2741
+ <div class="grid">
2742
+ <div class="metric"><div class="label">Pass</div><div class="value">${artifact.summary.pass ? "yes" : "no"}</div></div>
2743
+ <div class="metric"><div class="label">First Turn</div><div class="value">${artifact.summary.firstTurnLatencyMs ?? "n/a"}ms</div></div>
2744
+ <div class="metric"><div class="label">First Outbound Media</div><div class="value">${artifact.summary.firstOutboundMediaLatencyMs ?? "n/a"}ms</div></div>
2745
+ <div class="metric"><div class="label">Turn Count</div><div class="value">${artifact.summary.turnCount ?? "n/a"}</div></div>
2746
+ </div>
2747
+ </section>
2748
+ <section>
2749
+ <h2>Transcript</h2>
2750
+ <ul>
2751
+ <li><strong>Expected:</strong> ${escapeHtml(artifact.transcript.expected ?? "n/a")}</li>
2752
+ <li><strong>Actual:</strong> ${escapeHtml(artifact.transcript.actual || "n/a")}</li>
2753
+ </ul>
2754
+ </section>
2755
+ <section>
2756
+ <h2>Notes</h2>
2757
+ <ul>${notes || "<li>No notes.</li>"}</ul>
2758
+ </section>
2759
+ <section>
2760
+ <h2>Latency Breakdown</h2>
2761
+ <ul>${latency || "<li>No latency data.</li>"}</ul>
2762
+ </section>
2763
+ <section>
2764
+ <h2>Transport Summary</h2>
2765
+ <ul>${transport || "<li>No transport data.</li>"}</ul>
2766
+ </section>
2767
+ <section>
2768
+ <h2>Timeline</h2>
2769
+ <ul>${timeline || "<li>No timeline events.</li>"}</ul>
2770
+ </section>
2771
+ <section>
2772
+ <h2>Config</h2>
2773
+ <pre>${escapeHtml(JSON.stringify(artifact.config ?? {}, null, 2))}</pre>
2774
+ </section>
2775
+ </main>
2776
+ </body>
2777
+ </html>`;
2778
+ };
2779
+ var renderVoiceCallReviewMarkdown = (artifact) => {
2780
+ const summaryLines = [
2781
+ `- pass: ${artifact.summary.pass ? "yes" : "no"}`,
2782
+ formatMetric("first turn", artifact.summary.firstTurnLatencyMs),
2783
+ formatMetric("first outbound media", artifact.summary.firstOutboundMediaLatencyMs),
2784
+ formatMetric("mark", artifact.summary.markLatencyMs),
2785
+ formatMetric("clear", artifact.summary.clearLatencyMs),
2786
+ formatMetric("elapsed", artifact.summary.elapsedMs),
2787
+ typeof artifact.summary.wordErrorRate === "number" ? `- word error rate: ${artifact.summary.wordErrorRate}` : undefined,
2788
+ typeof artifact.summary.termRecall === "number" ? `- term recall: ${artifact.summary.termRecall}` : undefined,
2789
+ typeof artifact.summary.turnCount === "number" ? `- turn count: ${artifact.summary.turnCount}` : undefined,
2790
+ typeof artifact.summary.outboundMediaCount === "number" ? `- outbound media count: ${artifact.summary.outboundMediaCount}` : undefined
2791
+ ].filter((value) => typeof value === "string");
2792
+ const notes = artifact.notes.length ? ["## Notes", "", ...artifact.notes.map((note) => `- ${note}`)].join(`
2793
+ `) : "";
2794
+ const errors = artifact.errors.length ? ["## Errors", "", ...artifact.errors.map((error) => `- ${error}`)].join(`
2795
+ `) : "";
2796
+ const latency = renderLatencyBreakdown(artifact.latencyBreakdown);
2797
+ const transportSummary = renderTransportSummary(artifact.timeline);
2798
+ return [
2799
+ `# ${artifact.title}`,
2800
+ "",
2801
+ artifact.path ? `Source: \`${artifact.path}\`` : undefined,
2802
+ artifact.fixtureId ? `Fixture: \`${artifact.fixtureId}\`` : undefined,
2803
+ "",
2804
+ "## Summary",
2805
+ "",
2806
+ ...summaryLines,
2807
+ "",
2808
+ "## Transcript",
2809
+ "",
2810
+ `- expected: ${artifact.transcript.expected ?? "_n/a_"}`,
2811
+ `- actual: ${artifact.transcript.actual}`,
2812
+ "",
2813
+ notes,
2814
+ notes ? "" : undefined,
2815
+ latency,
2816
+ latency ? "" : undefined,
2817
+ transportSummary,
2818
+ transportSummary ? "" : undefined,
2819
+ errors,
2820
+ errors ? "" : undefined,
2821
+ renderConfigSection(artifact.config),
2822
+ renderConfigSection(artifact.config) ? "" : undefined,
2823
+ renderTimeline(artifact.timeline)
2824
+ ].filter((value) => typeof value === "string").join(`
2825
+ `);
2826
+ };
2827
+
2828
+ // src/drizzle/runtimeStorage.ts
2829
+ var voiceAuditDeliveriesTable = voiceDocumentTable("voice_audit_deliveries");
2830
+ var voiceAuditTable = voiceDocumentTable("voice_audit");
2831
+ var voiceCampaignsTable = voiceDocumentTable("voice_campaigns");
2832
+ var voiceEventsTable = voiceDocumentTable("voice_events");
2833
+ var voiceExternalObjectsTable = voiceDocumentTable("voice_external_objects");
2834
+ var voiceReviewsTable = voiceDocumentTable("voice_reviews");
2835
+ var voiceSessionsTable = voiceDocumentTable("voice_sessions");
2836
+ var voiceTasksTable = voiceDocumentTable("voice_tasks");
2837
+ var voiceTelephonyWebhookIdempotencyTable = voiceDocumentTable("voice_telephony_webhook_idempotency");
2838
+ var voiceTraceDeliveriesTable = voiceDocumentTable("voice_trace_deliveries");
2839
+ var voiceTracesTable = voiceDocumentTable("voice_traces");
2840
+ var voiceRuntimeStorageDrizzleSchema = {
2841
+ voiceAudit: voiceAuditTable,
2842
+ voiceAuditDeliveries: voiceAuditDeliveriesTable,
2843
+ voiceCampaigns: voiceCampaignsTable,
2844
+ voiceEvents: voiceEventsTable,
2845
+ voiceExternalObjects: voiceExternalObjectsTable,
2846
+ voiceReviews: voiceReviewsTable,
2847
+ voiceSessions: voiceSessionsTable,
2848
+ voiceTasks: voiceTasksTable,
2849
+ voiceTelephonyWebhookIdempotency: voiceTelephonyWebhookIdempotencyTable,
2850
+ voiceTraceDeliveries: voiceTraceDeliveriesTable,
2851
+ voiceTraces: voiceTracesTable
2852
+ };
2853
+ var createDrizzleSessionStore = (db) => {
2854
+ const store = createVoiceDrizzleRecordStore({
2855
+ db,
2856
+ decorate: (_id, value) => value,
2857
+ getSortAt: (value) => value.lastActivityAt ?? value.createdAt,
2858
+ table: voiceSessionsTable
2859
+ });
2860
+ const getOrCreate = async (id) => {
2861
+ const existing = await store.get(id);
2862
+ if (existing) {
2863
+ return existing;
2864
+ }
2865
+ const session = createVoiceSessionRecord(id);
2866
+ await store.set(id, session);
2867
+ return session;
2868
+ };
2869
+ return {
2870
+ get: store.get,
2871
+ getOrCreate,
2872
+ remove: store.remove,
2873
+ set: store.set,
2874
+ list: async () => (await store.list()).map((session) => toVoiceSessionSummary(session)).sort((first, second) => (second.lastActivityAt ?? second.createdAt) - (first.lastActivityAt ?? first.createdAt))
2875
+ };
2876
+ };
2877
+ var createDrizzleReviewStore = (db) => createVoiceDrizzleRecordStore({
2878
+ db,
2879
+ decorate: (id, value) => withVoiceCallReviewId(id, value),
2880
+ getSortAt: (value) => value.generatedAt ?? 0,
2881
+ table: voiceReviewsTable
2882
+ });
2883
+ var createDrizzleTaskStore = (db) => createVoiceDrizzleRecordStore({
2884
+ db,
2885
+ decorate: (id, value) => withVoiceOpsTaskId(id, value),
2886
+ getSortAt: (value) => value.createdAt,
2887
+ table: voiceTasksTable
2888
+ });
2889
+ var createDrizzleEventStore = (db) => createVoiceDrizzleRecordStore({
2890
+ db,
2891
+ decorate: (id, value) => withVoiceIntegrationEventId(id, value),
2892
+ getSortAt: (value) => value.createdAt,
2893
+ table: voiceEventsTable
2894
+ });
2895
+ var createDrizzleExternalObjectMapStore = (db) => {
2896
+ const store = createVoiceDrizzleRecordStore({
2897
+ db,
2898
+ decorate: (id, value) => ({
2899
+ ...value,
2900
+ id
2901
+ }),
2902
+ getSortAt: (value) => value.updatedAt,
2903
+ table: voiceExternalObjectsTable
2904
+ });
2905
+ const find = async (input) => (await store.list()).find((mapping) => mapping.provider === input.provider && mapping.sourceId === input.sourceId && (input.sinkId === undefined || mapping.sinkId === input.sinkId) && (input.sourceType === undefined || mapping.sourceType === input.sourceType));
2906
+ return {
2907
+ ...store,
2908
+ find
2909
+ };
2910
+ };
2911
+ var createDrizzleTraceEventStore = (db) => {
2912
+ const store = createVoiceDrizzleRecordStore({
2913
+ db,
2914
+ decorate: (_id, value) => value,
2915
+ getSortAt: (value) => value.at,
2916
+ table: voiceTracesTable
2917
+ });
2918
+ const append = async (event) => {
2919
+ const stored = createVoiceTraceEvent(event);
2920
+ await store.set(stored.id, stored);
2921
+ return stored;
2922
+ };
2923
+ return {
2924
+ append,
2925
+ get: store.get,
2926
+ remove: store.remove,
2927
+ list: async (filter) => filterVoiceTraceEvents(await store.list(), filter)
2928
+ };
2929
+ };
2930
+ var createDrizzleTraceSinkDeliveryStore = (db) => createVoiceDrizzleRecordStore({
2931
+ db,
2932
+ decorate: (id, value) => ({
2933
+ ...value,
2934
+ id
2935
+ }),
2936
+ getSortAt: (value) => value.createdAt,
2937
+ table: voiceTraceDeliveriesTable
2938
+ });
2939
+ var createDrizzleAuditEventStore = (db) => {
2940
+ const store = createVoiceDrizzleRecordStore({
2941
+ db,
2942
+ decorate: (_id, value) => value,
2943
+ getSortAt: (value) => value.at,
2944
+ table: voiceAuditTable
2945
+ });
2946
+ const append = async (event) => {
2947
+ const stored = createVoiceAuditEvent(event);
2948
+ await store.set(stored.id, stored);
2949
+ return stored;
2950
+ };
2951
+ return {
2952
+ append,
2953
+ get: store.get,
2954
+ list: async (filter) => filterVoiceAuditEvents(await store.list(), filter)
2955
+ };
2956
+ };
2957
+ var createDrizzleAuditSinkDeliveryStore = (db) => createVoiceDrizzleRecordStore({
2958
+ db,
2959
+ decorate: (id, value) => ({
2960
+ ...value,
2961
+ id
2962
+ }),
2963
+ getSortAt: (value) => value.createdAt,
2964
+ table: voiceAuditDeliveriesTable
2965
+ });
2966
+ var createDrizzleTelephonyWebhookIdempotencyStore = (db) => createVoiceDrizzleRecordStore({
2967
+ db,
2968
+ decorate: (_id, value) => value,
2969
+ getSortAt: (value) => value.updatedAt,
2970
+ table: voiceTelephonyWebhookIdempotencyTable
2971
+ });
2972
+ var createDrizzleCampaignStore = (db) => createVoiceDrizzleRecordStore({
2973
+ db,
2974
+ decorate: (_id, value) => value,
2975
+ getSortAt: (value) => value.campaign.createdAt,
2976
+ table: voiceCampaignsTable
2977
+ });
2978
+ var createVoiceDrizzleAuditEventStore = (options) => createDrizzleAuditEventStore(options.db);
2979
+ var createVoiceDrizzleAuditSinkDeliveryStore = (options) => createDrizzleAuditSinkDeliveryStore(options.db);
2980
+ var createVoiceDrizzleCampaignStore = (options) => createDrizzleCampaignStore(options.db);
2981
+ var createVoiceDrizzleExternalObjectMapStore = (options) => createDrizzleExternalObjectMapStore(options.db);
2982
+ var createVoiceDrizzleIntegrationEventStore = (options) => createDrizzleEventStore(options.db);
2983
+ var createVoiceDrizzleReviewStore = (options) => createDrizzleReviewStore(options.db);
2984
+ var createVoiceDrizzleRuntimeStorage = (options) => ({
2985
+ audit: createDrizzleAuditEventStore(options.db),
2986
+ auditDeliveries: createDrizzleAuditSinkDeliveryStore(options.db),
2987
+ campaigns: createDrizzleCampaignStore(options.db),
2988
+ events: createDrizzleEventStore(options.db),
2989
+ externalObjects: createDrizzleExternalObjectMapStore(options.db),
2990
+ incidentBundles: createVoiceDrizzleIncidentBundleStore({
2991
+ db: options.db
2992
+ }),
2993
+ memories: createVoiceDrizzleAssistantMemoryStore({ db: options.db }),
2994
+ reviews: createDrizzleReviewStore(options.db),
2995
+ session: createDrizzleSessionStore(options.db),
2996
+ tasks: createDrizzleTaskStore(options.db),
2997
+ traceDeliveries: createDrizzleTraceSinkDeliveryStore(options.db),
2998
+ traces: createDrizzleTraceEventStore(options.db)
2999
+ });
3000
+ var createVoiceDrizzleSessionStore = (options) => createDrizzleSessionStore(options.db);
3001
+ var createVoiceDrizzleTaskStore = (options) => createDrizzleTaskStore(options.db);
3002
+ var createVoiceDrizzleTelephonyWebhookIdempotencyStore = (options) => createDrizzleTelephonyWebhookIdempotencyStore(options.db);
3003
+ var createVoiceDrizzleTraceEventStore = (options) => createDrizzleTraceEventStore(options.db);
3004
+ var createVoiceDrizzleTraceSinkDeliveryStore = (options) => createDrizzleTraceSinkDeliveryStore(options.db);
3005
+
3006
+ // src/drizzle/index.ts
3007
+ var voiceDrizzleSchema = {
3008
+ ...voiceRuntimeStorageDrizzleSchema,
3009
+ voiceAssistantMemory: voiceAssistantMemoryTable,
3010
+ voiceEvalBaseline: voiceEvalBaselineTable,
3011
+ voiceHandoffDeliveries: voiceHandoffDeliveriesTable,
3012
+ voiceIncidentBundles: voiceIncidentBundlesTable,
3013
+ voiceObservabilityExportReceipts: voiceObservabilityExportDeliveryReceiptsTable,
3014
+ voiceRealCallProfileEvidence: voiceRealCallProfileEvidenceTable,
3015
+ voiceRealCallProfileRecoveryJobs: voiceRealCallProfileRecoveryJobsTable
3016
+ };
3017
+ export {
3018
+ voiceTracesTable,
3019
+ voiceTraceDeliveriesTable,
3020
+ voiceTelephonyWebhookIdempotencyTable,
3021
+ voiceTasksTable,
3022
+ voiceSessionsTable,
3023
+ voiceRuntimeStorageDrizzleSchema,
3024
+ voiceReviewsTable,
3025
+ voiceRealCallProfileRecoveryJobsTable,
3026
+ voiceRealCallProfileEvidenceTable,
3027
+ voiceObservabilityExportDeliveryReceiptsTable,
3028
+ voiceIncidentBundlesTable,
3029
+ voiceHandoffDeliveriesTable,
3030
+ voiceExternalObjectsTable,
3031
+ voiceEventsTable,
3032
+ voiceEvalBaselineTable,
3033
+ voiceDrizzleSchema,
3034
+ voiceDocumentTable,
3035
+ voiceCampaignsTable,
3036
+ voiceAuditTable,
3037
+ voiceAuditDeliveriesTable,
3038
+ voiceAssistantMemoryTable,
3039
+ createVoiceDrizzleTraceSinkDeliveryStore,
3040
+ createVoiceDrizzleTraceEventStore,
3041
+ createVoiceDrizzleTelephonyWebhookIdempotencyStore,
3042
+ createVoiceDrizzleTaskStore,
3043
+ createVoiceDrizzleSessionStore,
3044
+ createVoiceDrizzleRuntimeStorage,
3045
+ createVoiceDrizzleReviewStore,
3046
+ createVoiceDrizzleRecordStore,
3047
+ createVoiceDrizzleRealCallProfileRecoveryJobStore,
3048
+ createVoiceDrizzleRealCallProfileEvidenceStore,
3049
+ createVoiceDrizzleObservabilityExportDeliveryReceiptStore,
3050
+ createVoiceDrizzleIntegrationEventStore,
3051
+ createVoiceDrizzleIncidentBundleStore,
3052
+ createVoiceDrizzleHandoffDeliveryStore,
3053
+ createVoiceDrizzleExternalObjectMapStore,
3054
+ createVoiceDrizzleEvalBaselineStore,
3055
+ createVoiceDrizzleCampaignStore,
3056
+ createVoiceDrizzleAuditSinkDeliveryStore,
3057
+ createVoiceDrizzleAuditEventStore,
3058
+ createVoiceDrizzleAssistantMemoryStore
3059
+ };