@absolutejs/voice 0.0.22-beta.67 → 0.0.22-beta.670

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