@absolutejs/voice 0.0.22-beta.457 → 0.0.22-beta.459

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.
@@ -6908,12 +6908,17 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
6908
6908
  const tick = () => worker.collect();
6909
6909
  return {
6910
6910
  collect: tick,
6911
- health: () => ({
6912
- ...worker.health(),
6913
- isRunning: isRunning(),
6914
- lastStartedAt,
6915
- lastStoppedAt
6916
- }),
6911
+ health: () => {
6912
+ const health = worker.health();
6913
+ const running = isRunning();
6914
+ return {
6915
+ ...health,
6916
+ isRunning: running,
6917
+ lastStartedAt,
6918
+ lastStoppedAt,
6919
+ status: running && health.status === "idle" ? "running" : health.status
6920
+ };
6921
+ },
6917
6922
  isRunning,
6918
6923
  start: () => {
6919
6924
  if (timer) {
@@ -6936,6 +6941,77 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
6936
6941
  tick
6937
6942
  };
6938
6943
  };
6944
+ var buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck = (health, options = {}) => {
6945
+ const requireRunning = options.requireRunning ?? true;
6946
+ const issues = [];
6947
+ const warnings = [];
6948
+ const now = options.now ?? (() => new Date);
6949
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-evidence-runtime/worker";
6950
+ const href = options.href ?? "/voice/real-call-evidence-runtime";
6951
+ if (health.error) {
6952
+ issues.push(`Real-call evidence auto-collector error: ${health.error}.`);
6953
+ }
6954
+ if (health.status === "fail") {
6955
+ issues.push("Real-call evidence auto-collector is failing.");
6956
+ }
6957
+ if (requireRunning && !health.isRunning) {
6958
+ const message = "Real-call evidence auto-collector is not running; evidence is only collected manually.";
6959
+ if (options.failOnNotRunning) {
6960
+ issues.push(message);
6961
+ } else {
6962
+ warnings.push(message);
6963
+ }
6964
+ }
6965
+ if (health.collectCount === 0) {
6966
+ warnings.push("Real-call evidence auto-collector has not collected yet.");
6967
+ }
6968
+ if (options.maxLastCollectedAgeMs && health.lastCollectedAt) {
6969
+ const ageMs = now().getTime() - new Date(health.lastCollectedAt).getTime();
6970
+ if (Number.isFinite(ageMs) && ageMs > options.maxLastCollectedAgeMs) {
6971
+ const message = `Last real-call evidence auto-collection is ${String(ageMs)}ms old.`;
6972
+ if (options.failOnStale) {
6973
+ issues.push(message);
6974
+ } else {
6975
+ warnings.push(message);
6976
+ }
6977
+ }
6978
+ }
6979
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
6980
+ return {
6981
+ actions: [
6982
+ {
6983
+ description: "Run one collection cycle immediately and update worker health.",
6984
+ href: options.collectHref ?? "/api/voice/real-call-evidence-runtime/collect",
6985
+ label: "Collect real-call evidence",
6986
+ method: "POST"
6987
+ },
6988
+ {
6989
+ description: "Open rolling real-call evidence and inspect worker health.",
6990
+ href,
6991
+ label: "Open real-call evidence runtime"
6992
+ }
6993
+ ],
6994
+ detail: status === "pass" ? `Auto-collector is running with ${String(health.collectCount)} collection(s).` : [...issues, ...warnings].join(" "),
6995
+ gateExplanation: {
6996
+ evidenceHref: sourceHref,
6997
+ observed: health.isRunning ? "running" : "manual",
6998
+ remediation: "Enable the real-call evidence worker loop in production, keep it healthy, and run real traffic so rolling evidence stays fresh.",
6999
+ sourceHref: href,
7000
+ threshold: requireRunning ? "running" : "available",
7001
+ thresholdLabel: "Real-call evidence collection mode",
7002
+ unit: "status"
7003
+ },
7004
+ href,
7005
+ label: options.label ?? "Real-call evidence auto-collector",
7006
+ proofSource: {
7007
+ href: sourceHref,
7008
+ source: health.source,
7009
+ sourceLabel: "Real-call evidence worker health"
7010
+ },
7011
+ status,
7012
+ value: `${health.isRunning ? "running" : "manual"} / ${String(health.collectCount)} collections / ${health.status}`
7013
+ };
7014
+ };
6939
7015
  var realCallProfileTraceSignalTypes = new Set([
6940
7016
  "client.barge_in",
6941
7017
  "client.browser_media",
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ export { assertVoicePlatformCoverage, buildVoicePlatformCoverageSummary, createV
31
31
  export { assertVoiceCompetitiveCoverage, buildVoiceCompetitiveCoverageReport, createVoiceCompetitiveCoverageRoutes, evaluateVoiceCompetitiveCoverage, renderVoiceCompetitiveCoverageHTML, renderVoiceCompetitiveCoverageMarkdown, } from "./competitiveCoverage";
32
32
  export type { VoiceCompetitiveCoverageAssertionInput, VoiceCompetitiveCoverageAssertionReport, VoiceCompetitiveCoverageIssue, VoiceCompetitiveCoverageLevel, VoiceCompetitiveCoverageReport, VoiceCompetitiveCoverageReportInput, VoiceCompetitiveCoverageRoutesOptions, VoiceCompetitiveCoverageStatus, VoiceCompetitiveCoverageSummary, VoiceCompetitiveDepthLevel, VoiceCompetitiveEvidence, VoiceCompetitiveSurface, } from "./competitiveCoverage";
33
33
  export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface, } from "./platformCoverage";
34
- export { assertVoiceProofTrendEvidence, appendVoiceRealCallProfileRecoveryEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileEvidenceFromReconnectProofReports, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileHistoryReportFromStore, buildVoiceRealCallEvidenceRuntimeReadinessCheck, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryJobHistoryCheck, buildVoiceRealCallProfileRecoveryActions, buildVoiceReconnectProfileEvidenceSummary, createVoiceRealCallEvidenceRuntime, createVoiceRealCallEvidenceRuntimeWorker, createVoiceRealCallEvidenceRuntimeWorkerLoop, createVoiceRealCallEvidenceRuntimeRoutes, createVoiceInMemoryRealCallProfileRecoveryJobStore, createVoiceRealCallProfileTraceCollector, createVoiceSQLiteRealCallProfileEvidenceStore, createVoiceSQLiteRealCallProfileRecoveryJobStore, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, createVoiceRealCallProfileRecoveryActionRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromStore, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallEvidenceRuntimeHTML, renderVoiceRealCallEvidenceRuntimeMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, runVoiceRealCallProfileRecoveryLoop, resolveVoiceRealCallProfileProviderRoute, } from "./proofTrends";
34
+ export { assertVoiceProofTrendEvidence, appendVoiceRealCallProfileRecoveryEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileEvidenceFromReconnectProofReports, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileHistoryReportFromStore, buildVoiceRealCallEvidenceRuntimeReadinessCheck, buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryJobHistoryCheck, buildVoiceRealCallProfileRecoveryActions, buildVoiceReconnectProfileEvidenceSummary, createVoiceRealCallEvidenceRuntime, createVoiceRealCallEvidenceRuntimeWorker, createVoiceRealCallEvidenceRuntimeWorkerLoop, createVoiceRealCallEvidenceRuntimeRoutes, createVoiceInMemoryRealCallProfileRecoveryJobStore, createVoiceRealCallProfileTraceCollector, createVoiceSQLiteRealCallProfileEvidenceStore, createVoiceSQLiteRealCallProfileRecoveryJobStore, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, createVoiceRealCallProfileRecoveryActionRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromStore, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallEvidenceRuntimeHTML, renderVoiceRealCallEvidenceRuntimeMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, runVoiceRealCallProfileRecoveryLoop, resolveVoiceRealCallProfileProviderRoute, } from "./proofTrends";
35
35
  export { createVoiceEvidenceAssertion, createVoiceProofAssertion, summarizeVoiceProofAssertions, } from "./proofAssertions";
36
36
  export { buildVoiceSessionSnapshot, buildVoiceSessionSnapshotStatus, createVoiceSessionSnapshotRoutes, parseVoiceSessionSnapshot, } from "./sessionSnapshot";
37
37
  export { buildVoiceCallDebuggerReport, createVoiceCallDebuggerRoutes, renderVoiceCallDebuggerHTML, resolveLatestVoiceCallDebuggerSessionId, } from "./callDebugger";
@@ -46,7 +46,7 @@ export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTrace
46
46
  export type { VoiceProviderDecisionStatus, VoiceProviderDecisionSurfaceReport, VoiceProviderDecisionTrace, VoiceProviderDecisionTraceInput, VoiceProviderDecisionTraceIssue, VoiceProviderDecisionTraceReport, VoiceProviderDecisionTraceReportOptions, VoiceProviderDecisionTraceRoutesOptions, } from "./providerDecisionTraces";
47
47
  export { appendVoiceIOProviderRouterTraceEvent, appendVoiceProviderRouterTraceEvent, buildVoiceIOProviderRouterTraceEvent, buildVoiceProviderRouterTraceEvent, } from "./providerRouterTraces";
48
48
  export type { VoiceIOProviderRouterTraceAppendOptions, VoiceIOProviderRouterTraceEventOptions, VoiceProviderRouterTraceAppendOptions, VoiceProviderRouterTraceEventOptions, } from "./providerRouterTraces";
49
- export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendReconnectSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileEvidenceCreateInput, VoiceRealCallProfileEvidenceListOptions, VoiceRealCallProfileEvidenceRecord, VoiceRealCallProfileEvidenceStore, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileReadinessCheckOptions, VoiceRealCallProfileRecoveryActionOptions, VoiceRealCallProfileRecoveryAction, VoiceRealCallProfileRecoveryActionHandler, VoiceRealCallProfileRecoveryActionHandlerInput, VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryJobHistoryCheckOptions, VoiceRealCallProfileRecoveryActionResult, VoiceRealCallProfileRecoveryActionRoutesOptions, VoiceRealCallProfileRecoveryJob, VoiceRealCallProfileRecoveryJobCreateInput, VoiceRealCallProfileRecoveryJobListOptions, VoiceRealCallProfileRecoveryJobStatus, VoiceRealCallProfileRecoveryJobStore, VoiceRealCallProfileRecoveryJobUpdate, VoiceRealCallProfileRecoveryLoopAction, VoiceRealCallProfileRecoveryLoopJob, VoiceRealCallProfileRecoveryLoopJobResult, VoiceRealCallProfileRecoveryLoopOptions, VoiceRealCallProfileRecoveryLoopReport, VoiceRealCallProfileRecoveryLoopStartFailure, VoiceRealCallProfileRecoveryEvidenceOptions, VoiceRealCallProfileRecoveryEvidenceProvider, VoiceRealCallProfileRecoveryEvidenceProviderRole, VoiceRealCallProfileRecoveryEvidenceResult, VoiceSQLiteRealCallProfileRecoveryJobStoreOptions, VoiceRealCallProfileTraceCollector, VoiceRealCallProfileTraceCollectorEvidenceOptions, VoiceRealCallProfileTraceCollectorOptions, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions, VoiceReconnectRealCallProfileEvidenceOptions, VoiceReconnectProfileEvidenceSummary, VoiceReconnectProfileEvidenceSummaryStatus, VoiceRealCallEvidenceRuntime, VoiceRealCallEvidenceRuntimeCollectOptions, VoiceRealCallEvidenceRuntimeOptions, VoiceRealCallEvidenceRuntimeReadinessCheckOptions, VoiceRealCallEvidenceRuntimeReport, VoiceRealCallEvidenceRuntimeRoutesOptions, VoiceRealCallEvidenceRuntimeSourceOptions, VoiceRealCallEvidenceRuntimeWorker, VoiceRealCallEvidenceRuntimeWorkerHealthReport, VoiceRealCallEvidenceRuntimeWorkerLoop, VoiceRealCallEvidenceRuntimeWorkerLoopOptions, VoiceRealCallEvidenceRuntimeWorkerOptions, VoiceRealCallEvidenceRuntimeWorkerStatus, VoiceSQLiteRealCallProfileEvidenceStoreOptions, } from "./proofTrends";
49
+ export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendReconnectSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileEvidenceCreateInput, VoiceRealCallProfileEvidenceListOptions, VoiceRealCallProfileEvidenceRecord, VoiceRealCallProfileEvidenceStore, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileReadinessCheckOptions, VoiceRealCallProfileRecoveryActionOptions, VoiceRealCallProfileRecoveryAction, VoiceRealCallProfileRecoveryActionHandler, VoiceRealCallProfileRecoveryActionHandlerInput, VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryJobHistoryCheckOptions, VoiceRealCallProfileRecoveryActionResult, VoiceRealCallProfileRecoveryActionRoutesOptions, VoiceRealCallProfileRecoveryJob, VoiceRealCallProfileRecoveryJobCreateInput, VoiceRealCallProfileRecoveryJobListOptions, VoiceRealCallProfileRecoveryJobStatus, VoiceRealCallProfileRecoveryJobStore, VoiceRealCallProfileRecoveryJobUpdate, VoiceRealCallProfileRecoveryLoopAction, VoiceRealCallProfileRecoveryLoopJob, VoiceRealCallProfileRecoveryLoopJobResult, VoiceRealCallProfileRecoveryLoopOptions, VoiceRealCallProfileRecoveryLoopReport, VoiceRealCallProfileRecoveryLoopStartFailure, VoiceRealCallProfileRecoveryEvidenceOptions, VoiceRealCallProfileRecoveryEvidenceProvider, VoiceRealCallProfileRecoveryEvidenceProviderRole, VoiceRealCallProfileRecoveryEvidenceResult, VoiceSQLiteRealCallProfileRecoveryJobStoreOptions, VoiceRealCallProfileTraceCollector, VoiceRealCallProfileTraceCollectorEvidenceOptions, VoiceRealCallProfileTraceCollectorOptions, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions, VoiceReconnectRealCallProfileEvidenceOptions, VoiceReconnectProfileEvidenceSummary, VoiceReconnectProfileEvidenceSummaryStatus, VoiceRealCallEvidenceRuntime, VoiceRealCallEvidenceRuntimeCollectOptions, VoiceRealCallEvidenceRuntimeOptions, VoiceRealCallEvidenceRuntimeReadinessCheckOptions, VoiceRealCallEvidenceRuntimeReport, VoiceRealCallEvidenceRuntimeRoutesOptions, VoiceRealCallEvidenceRuntimeSourceOptions, VoiceRealCallEvidenceRuntimeWorker, VoiceRealCallEvidenceRuntimeWorkerHealthReport, VoiceRealCallEvidenceRuntimeWorkerLoop, VoiceRealCallEvidenceRuntimeWorkerLoopOptions, VoiceRealCallEvidenceRuntimeWorkerOptions, VoiceRealCallEvidenceRuntimeWorkerReadinessCheckOptions, VoiceRealCallEvidenceRuntimeWorkerStatus, VoiceSQLiteRealCallProfileEvidenceStoreOptions, } from "./proofTrends";
50
50
  export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, buildVoiceSloReadinessThresholdReport, createVoiceSloReadinessThresholdOptions, createVoiceSloReadinessThresholdRoutes, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown, renderVoiceSloReadinessThresholdHTML, renderVoiceSloReadinessThresholdMarkdown, } from "./sloCalibration";
51
51
  export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloReadinessThresholdReport, VoiceSloReadinessThresholdReportOptions, VoiceSloReadinessThresholdOptions, VoiceSloReadinessThresholdRoutesOptions, VoiceSloThresholdProfile, } from "./sloCalibration";
52
52
  export { assertVoiceLiveOpsControlEvidence, assertVoiceLiveOpsEvidence, buildVoiceLiveOpsControlState, createVoiceLiveOpsController, createVoiceLiveOpsRoutes, createVoiceMemoryLiveOpsControlStore, evaluateVoiceLiveOpsControlEvidence, evaluateVoiceLiveOpsEvidence, getVoiceLiveOpsControlStatus, VOICE_LIVE_OPS_ACTIONS, } from "./liveOps";
@@ -93,6 +93,8 @@ export { createVoiceReadinessProfile, recommendVoiceReadinessProfile, } from "./
93
93
  export { assertVoiceProviderContractMatrixEvidence, assertVoiceProviderStackEvidence, buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderContractMatrixEvidence, evaluateVoiceProviderStackEvidence, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack, } from "./providerStackRecommendations";
94
94
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML, } from "./opsConsoleRoutes";
95
95
  export { assertVoiceOperationsRecordGuardrails, assertVoiceOperationsRecordProviderRecovery, buildVoiceFailureReplay, buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, evaluateVoiceOperationsRecordGuardrails, evaluateVoiceOperationsRecordProviderRecovery, renderVoiceFailureReplayMarkdown, renderVoiceOperationsRecordGuardrailMarkdown, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown, } from "./operationsRecord";
96
+ export { buildVoiceSessionObservabilityReport, createVoiceSessionObservabilityRoutes, renderVoiceSessionObservabilityHTML, renderVoiceSessionObservabilityMarkdown, } from "./sessionObservability";
97
+ export type { VoiceSessionObservabilityLink, VoiceSessionObservabilityReport, VoiceSessionObservabilityReportOptions, VoiceSessionObservabilityRoutesOptions, VoiceSessionObservabilityStage, VoiceSessionObservabilityStatus, VoiceSessionObservabilityTurn, } from "./sessionObservability";
96
98
  export { assertVoiceObservabilityExportDeliveryEvidence, assertVoiceObservabilityExportRecord, assertVoiceObservabilityExportReplayEvidence, buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExportDeliveryHistory, buildVoiceObservabilityExportReplayReport, buildVoiceObservabilityExport, assertVoiceObservabilityExportSchema, createVoiceObservabilityExportSchema, createVoiceFileObservabilityExportDeliveryReceiptStore, createVoiceMemoryObservabilityExportDeliveryReceiptStore, createVoiceObservabilityExportRoutes, createVoiceObservabilityExportReplayRoutes, deliverVoiceObservabilityExport, evaluateVoiceObservabilityExportDeliveryEvidence, evaluateVoiceObservabilityExportReplayEvidence, loadVoiceObservabilityExportReplaySource, replayVoiceObservabilityExport, renderVoiceObservabilityExportReplayHTML, renderVoiceObservabilityExportMarkdown, validateVoiceObservabilityExportRecord, voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVersion, } from "./observabilityExport";
97
99
  export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown, } from "./opsRecovery";
98
100
  export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact, } from "./incidentBundle";
package/dist/index.js CHANGED
@@ -17098,12 +17098,17 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
17098
17098
  const tick = () => worker.collect();
17099
17099
  return {
17100
17100
  collect: tick,
17101
- health: () => ({
17102
- ...worker.health(),
17103
- isRunning: isRunning(),
17104
- lastStartedAt,
17105
- lastStoppedAt
17106
- }),
17101
+ health: () => {
17102
+ const health = worker.health();
17103
+ const running = isRunning();
17104
+ return {
17105
+ ...health,
17106
+ isRunning: running,
17107
+ lastStartedAt,
17108
+ lastStoppedAt,
17109
+ status: running && health.status === "idle" ? "running" : health.status
17110
+ };
17111
+ },
17107
17112
  isRunning,
17108
17113
  start: () => {
17109
17114
  if (timer) {
@@ -17126,6 +17131,77 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
17126
17131
  tick
17127
17132
  };
17128
17133
  };
17134
+ var buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck = (health, options = {}) => {
17135
+ const requireRunning = options.requireRunning ?? true;
17136
+ const issues = [];
17137
+ const warnings = [];
17138
+ const now = options.now ?? (() => new Date);
17139
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-evidence-runtime/worker";
17140
+ const href = options.href ?? "/voice/real-call-evidence-runtime";
17141
+ if (health.error) {
17142
+ issues.push(`Real-call evidence auto-collector error: ${health.error}.`);
17143
+ }
17144
+ if (health.status === "fail") {
17145
+ issues.push("Real-call evidence auto-collector is failing.");
17146
+ }
17147
+ if (requireRunning && !health.isRunning) {
17148
+ const message = "Real-call evidence auto-collector is not running; evidence is only collected manually.";
17149
+ if (options.failOnNotRunning) {
17150
+ issues.push(message);
17151
+ } else {
17152
+ warnings.push(message);
17153
+ }
17154
+ }
17155
+ if (health.collectCount === 0) {
17156
+ warnings.push("Real-call evidence auto-collector has not collected yet.");
17157
+ }
17158
+ if (options.maxLastCollectedAgeMs && health.lastCollectedAt) {
17159
+ const ageMs = now().getTime() - new Date(health.lastCollectedAt).getTime();
17160
+ if (Number.isFinite(ageMs) && ageMs > options.maxLastCollectedAgeMs) {
17161
+ const message = `Last real-call evidence auto-collection is ${String(ageMs)}ms old.`;
17162
+ if (options.failOnStale) {
17163
+ issues.push(message);
17164
+ } else {
17165
+ warnings.push(message);
17166
+ }
17167
+ }
17168
+ }
17169
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
17170
+ return {
17171
+ actions: [
17172
+ {
17173
+ description: "Run one collection cycle immediately and update worker health.",
17174
+ href: options.collectHref ?? "/api/voice/real-call-evidence-runtime/collect",
17175
+ label: "Collect real-call evidence",
17176
+ method: "POST"
17177
+ },
17178
+ {
17179
+ description: "Open rolling real-call evidence and inspect worker health.",
17180
+ href,
17181
+ label: "Open real-call evidence runtime"
17182
+ }
17183
+ ],
17184
+ detail: status === "pass" ? `Auto-collector is running with ${String(health.collectCount)} collection(s).` : [...issues, ...warnings].join(" "),
17185
+ gateExplanation: {
17186
+ evidenceHref: sourceHref,
17187
+ observed: health.isRunning ? "running" : "manual",
17188
+ remediation: "Enable the real-call evidence worker loop in production, keep it healthy, and run real traffic so rolling evidence stays fresh.",
17189
+ sourceHref: href,
17190
+ threshold: requireRunning ? "running" : "available",
17191
+ thresholdLabel: "Real-call evidence collection mode",
17192
+ unit: "status"
17193
+ },
17194
+ href,
17195
+ label: options.label ?? "Real-call evidence auto-collector",
17196
+ proofSource: {
17197
+ href: sourceHref,
17198
+ source: health.source,
17199
+ sourceLabel: "Real-call evidence worker health"
17200
+ },
17201
+ status,
17202
+ value: `${health.isRunning ? "running" : "manual"} / ${String(health.collectCount)} collections / ${health.status}`
17203
+ };
17204
+ };
17129
17205
  var realCallProfileTraceSignalTypes = new Set([
17130
17206
  "client.barge_in",
17131
17207
  "client.browser_media",
@@ -38999,8 +39075,248 @@ var createVoiceOpsConsoleRoutes = (options) => {
38999
39075
  routes.get(`${path}/json`, async () => getReport());
39000
39076
  return routes;
39001
39077
  };
39002
- // src/incidentBundle.ts
39078
+ // src/sessionObservability.ts
39003
39079
  import { Elysia as Elysia62 } from "elysia";
39080
+ var escapeHtml59 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
39081
+ var formatMs6 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
39082
+ var resolveHref = (href, sessionId) => {
39083
+ if (href === false) {
39084
+ return;
39085
+ }
39086
+ if (typeof href === "function") {
39087
+ return href(sessionId);
39088
+ }
39089
+ if (typeof href === "string") {
39090
+ return href.includes(":sessionId") ? href.replaceAll(":sessionId", encodeURIComponent(sessionId)) : `${href.replace(/\/$/, "")}/${encodeURIComponent(sessionId)}`;
39091
+ }
39092
+ return;
39093
+ };
39094
+ var buildLinks = (options) => {
39095
+ const links = [];
39096
+ const add = (rel, label, href) => {
39097
+ if (href) {
39098
+ links.push({ href, label, rel });
39099
+ }
39100
+ };
39101
+ add("operations-record", "Open operations record", resolveHref(options.operationsRecordHref, options.sessionId));
39102
+ add("trace-timeline", "Open trace timeline", resolveHref(options.traceTimelineHref, options.sessionId));
39103
+ add("call-debugger", "Open call debugger", resolveHref(options.callDebuggerHref, options.sessionId));
39104
+ add("incident-markdown", "Download incident Markdown", resolveHref(options.incidentMarkdownHref, options.sessionId));
39105
+ return [...links, ...options.customLinks ?? []];
39106
+ };
39107
+ var buildTurnWaterfalls = (record) => {
39108
+ const byTurn = new Map;
39109
+ const getTurn = (turnId) => {
39110
+ const existing = byTurn.get(turnId);
39111
+ if (existing) {
39112
+ return existing;
39113
+ }
39114
+ const turn = {
39115
+ assistantReplies: 0,
39116
+ errors: 0,
39117
+ providerDecisions: 0,
39118
+ stages: [],
39119
+ toolCalls: 0,
39120
+ transcripts: 0
39121
+ };
39122
+ byTurn.set(turnId, turn);
39123
+ return turn;
39124
+ };
39125
+ for (const event of record.timeline) {
39126
+ if (!event.turnId) {
39127
+ continue;
39128
+ }
39129
+ const turn = getTurn(event.turnId);
39130
+ turn.stages.push({
39131
+ at: event.at,
39132
+ elapsedMs: event.elapsedMs,
39133
+ label: event.label,
39134
+ offsetMs: event.offsetMs,
39135
+ provider: event.provider,
39136
+ status: event.status,
39137
+ type: event.type
39138
+ });
39139
+ if (event.type === "turn.transcript") {
39140
+ turn.transcripts += 1;
39141
+ }
39142
+ if (event.type === "turn.assistant") {
39143
+ turn.assistantReplies += 1;
39144
+ }
39145
+ if (event.type === "agent.tool") {
39146
+ turn.toolCalls += 1;
39147
+ }
39148
+ if (event.type === "provider.decision") {
39149
+ turn.providerDecisions += 1;
39150
+ }
39151
+ if (event.type === "session.error" || event.status === "error") {
39152
+ turn.errors += 1;
39153
+ }
39154
+ }
39155
+ for (const transcript of record.transcript) {
39156
+ const turn = getTurn(transcript.id);
39157
+ turn.assistantReplies = Math.max(turn.assistantReplies, transcript.assistantReplies.length);
39158
+ turn.errors += transcript.errors.length;
39159
+ turn.transcripts = Math.max(turn.transcripts, transcript.transcripts.length);
39160
+ }
39161
+ return [...byTurn.entries()].map(([turnId, turn]) => {
39162
+ const startedAt = turn.stages[0]?.at;
39163
+ const endedAt = turn.stages.at(-1)?.at;
39164
+ return {
39165
+ assistantReplies: turn.assistantReplies,
39166
+ durationMs: startedAt !== undefined && endedAt !== undefined ? Math.max(0, endedAt - startedAt) : undefined,
39167
+ endedAt,
39168
+ errors: turn.errors,
39169
+ providerDecisions: turn.providerDecisions,
39170
+ stages: turn.stages,
39171
+ startedAt,
39172
+ toolCalls: turn.toolCalls,
39173
+ transcripts: turn.transcripts,
39174
+ turnId
39175
+ };
39176
+ }).sort((left, right) => (left.startedAt ?? 0) - (right.startedAt ?? 0));
39177
+ };
39178
+ var buildVoiceSessionObservabilityReport = async (options) => {
39179
+ const record = await buildVoiceOperationsRecord({
39180
+ audit: options.audit,
39181
+ evaluation: options.evaluation,
39182
+ events: options.events,
39183
+ integrationEvents: options.integrationEvents,
39184
+ redact: options.redact,
39185
+ reviews: options.reviews,
39186
+ sessionId: options.sessionId,
39187
+ store: options.store,
39188
+ tasks: options.tasks
39189
+ });
39190
+ const failureReplay = buildVoiceFailureReplay(record, {
39191
+ operationsRecordHref: resolveHref(options.operationsRecordHref, options.sessionId)
39192
+ });
39193
+ const incidentMarkdown = renderVoiceOperationsRecordIncidentMarkdown(record);
39194
+ const statuses = [
39195
+ record.status,
39196
+ failureReplay.status === "failed" ? "failed" : failureReplay.status === "degraded" ? "warning" : "healthy"
39197
+ ];
39198
+ const status = statuses.includes("failed") ? "failed" : statuses.includes("warning") ? "warning" : "healthy";
39199
+ return {
39200
+ checkedAt: Date.now(),
39201
+ failureReplay,
39202
+ incidentMarkdown,
39203
+ links: buildLinks(options),
39204
+ record,
39205
+ sessionId: options.sessionId,
39206
+ status,
39207
+ summary: {
39208
+ durationMs: record.summary.callDurationMs,
39209
+ errors: record.summary.errorCount,
39210
+ events: record.summary.eventCount,
39211
+ fallbacks: record.providerDecisionSummary.fallbacks,
39212
+ guardrailBlocks: record.guardrails.blocked,
39213
+ handoffs: record.handoffs.length,
39214
+ providerRecoveryStatus: record.providerDecisionSummary.recoveryStatus,
39215
+ providers: record.providerDecisionSummary.providers,
39216
+ telephonyMediaEvents: record.telephonyMedia.total,
39217
+ toolCalls: record.tools.length,
39218
+ turns: record.summary.turnCount
39219
+ },
39220
+ turns: buildTurnWaterfalls(record)
39221
+ };
39222
+ };
39223
+ var renderLinks = (links) => links.length === 0 ? "" : `<div class="actions">${links.map((link) => `<a href="${escapeHtml59(link.href)}">${escapeHtml59(link.label)}</a>`).join("")}</div>`;
39224
+ var renderTurns = (turns) => turns.length === 0 ? '<p class="muted">No turn-level events recorded yet.</p>' : turns.map((turn) => `<article class="turn"><header><strong>${escapeHtml59(turn.turnId)}</strong><span>${formatMs6(turn.durationMs)}</span></header><dl><div><dt>Transcripts</dt><dd>${String(turn.transcripts)}</dd></div><div><dt>Assistant</dt><dd>${String(turn.assistantReplies)}</dd></div><div><dt>Tools</dt><dd>${String(turn.toolCalls)}</dd></div><div><dt>Providers</dt><dd>${String(turn.providerDecisions)}</dd></div><div><dt>Errors</dt><dd>${String(turn.errors)}</dd></div></dl><table><thead><tr><th>Offset</th><th>Type</th><th>Stage</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${turn.stages.map((stage) => `<tr><td>+${String(stage.offsetMs)}ms</td><td>${escapeHtml59(stage.type)}</td><td>${escapeHtml59(stage.label)}</td><td>${escapeHtml59(stage.provider ?? "")}</td><td>${escapeHtml59(stage.status ?? "")}</td><td>${formatMs6(stage.elapsedMs)}</td></tr>`).join("")}</tbody></table></article>`).join("");
39225
+ var renderVoiceSessionObservabilityMarkdown = (report) => `# Voice session observability: ${report.sessionId}
39226
+
39227
+ Status: ${report.status}
39228
+
39229
+ - Events: ${report.summary.events}
39230
+ - Turns: ${report.summary.turns}
39231
+ - Errors: ${report.summary.errors}
39232
+ - Duration: ${formatMs6(report.summary.durationMs)}
39233
+ - Providers: ${report.summary.providers.join(", ") || "none"}
39234
+ - Provider recovery: ${report.summary.providerRecoveryStatus}
39235
+ - Fallbacks: ${report.summary.fallbacks}
39236
+ - Tool calls: ${report.summary.toolCalls}
39237
+ - Handoffs: ${report.summary.handoffs}
39238
+ - Guardrail blocks: ${report.summary.guardrailBlocks}
39239
+ - Telephony media events: ${report.summary.telephonyMediaEvents}
39240
+
39241
+ ## Links
39242
+
39243
+ ${report.links.length ? report.links.map((link) => `- [${link.label}](${link.href})`).join(`
39244
+ `) : "- none"}
39245
+
39246
+ ## Turn Waterfalls
39247
+
39248
+ ${report.turns.length ? report.turns.map((turn) => `### ${turn.turnId}
39249
+
39250
+ - Duration: ${formatMs6(turn.durationMs)}
39251
+ - Transcripts: ${turn.transcripts}
39252
+ - Assistant replies: ${turn.assistantReplies}
39253
+ - Tool calls: ${turn.toolCalls}
39254
+ - Provider decisions: ${turn.providerDecisions}
39255
+ - Errors: ${turn.errors}
39256
+
39257
+ ${turn.stages.map((stage) => `- +${stage.offsetMs}ms ${stage.type}: ${stage.label}${stage.provider ? ` (${stage.provider})` : ""}${stage.status ? ` [${stage.status}]` : ""}`).join(`
39258
+ `)}`).join(`
39259
+
39260
+ `) : "No turn-level events recorded."}
39261
+
39262
+ ## Incident Handoff
39263
+
39264
+ ${report.incidentMarkdown}`;
39265
+ var renderVoiceSessionObservabilityHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml59(options.title ?? "Voice Session Observability")}</title><style>body{background:#0d1412;color:#f7f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #425046;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.actions{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0}.actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:22px 0}.card,.turn,.incident{background:#17201c;border:1px solid #2e3c35;border-radius:20px;padding:16px}.card span,.muted,dt{color:#a8b4ad}.card strong{display:block;font-size:2rem}section{margin-top:30px}.turn{margin:16px 0}.turn header{align-items:center;display:flex;justify-content:space-between;gap:14px}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));margin:14px 0}dd{font-weight:900;margin:3px 0 0}table{border-collapse:collapse;margin-top:14px;width:100%}td,th{border-top:1px solid #2e3c35;padding:10px;text-align:left}pre{background:#08100d;border:1px solid #2e3c35;border-radius:16px;color:#d9f99d;overflow:auto;padding:14px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}</style></head><body><main><header><p class="eyebrow">Session observability</p><h1>${escapeHtml59(report.sessionId)}</h1><p class="status ${escapeHtml59(report.status)}">${escapeHtml59(report.status)}</p>${renderLinks(report.links)}<p class="muted">One support/debug report across trace timeline, operations record, provider recovery, turn waterfalls, guardrails, tools, handoffs, failure replay, and incident handoff.</p></header><section class="grid"><article class="card"><span>Events</span><strong>${String(report.summary.events)}</strong></article><article class="card"><span>Turns</span><strong>${String(report.summary.turns)}</strong></article><article class="card"><span>Errors</span><strong>${String(report.summary.errors)}</strong></article><article class="card"><span>Duration</span><strong>${formatMs6(report.summary.durationMs)}</strong></article><article class="card"><span>Fallbacks</span><strong>${String(report.summary.fallbacks)}</strong></article><article class="card"><span>Tools</span><strong>${String(report.summary.toolCalls)}</strong></article><article class="card"><span>Handoffs</span><strong>${String(report.summary.handoffs)}</strong></article><article class="card"><span>Guardrails blocked</span><strong>${String(report.summary.guardrailBlocks)}</strong></article><article class="card"><span>Telephony media</span><strong>${String(report.summary.telephonyMediaEvents)}</strong></article></section><section><h2>Turn Waterfalls</h2>${renderTurns(report.turns)}</section><section class="incident"><h2>Incident Handoff</h2><pre><code>${escapeHtml59(report.incidentMarkdown)}</code></pre></section></main></body></html>`;
39266
+ var routeSessionId = (params) => typeof params.sessionId === "string" ? params.sessionId : "";
39267
+ var createVoiceSessionObservabilityRoutes = (options) => {
39268
+ const path = options.path ?? "/api/voice/session-observability/:sessionId";
39269
+ const htmlPath = options.htmlPath ?? "/voice/session-observability/:sessionId";
39270
+ const incidentPath = options.incidentPath ?? "/api/voice/session-observability/:sessionId/incident.md";
39271
+ const title = options.title ?? "AbsoluteJS Voice Session Observability";
39272
+ const routes = new Elysia62({
39273
+ name: options.name ?? "absolutejs-voice-session-observability"
39274
+ });
39275
+ const build = (sessionId) => buildVoiceSessionObservabilityReport({
39276
+ audit: options.audit,
39277
+ callDebuggerHref: options.callDebuggerHref,
39278
+ customLinks: options.customLinks,
39279
+ evaluation: options.evaluation,
39280
+ events: options.events,
39281
+ incidentMarkdownHref: options.incidentMarkdownHref ?? (incidentPath === false ? false : incidentPath),
39282
+ integrationEvents: options.integrationEvents,
39283
+ operationsRecordHref: options.operationsRecordHref,
39284
+ redact: options.redact,
39285
+ reviews: options.reviews,
39286
+ sessionId,
39287
+ store: options.store,
39288
+ tasks: options.tasks,
39289
+ traceTimelineHref: options.traceTimelineHref
39290
+ });
39291
+ routes.get(path, async ({ params }) => Response.json(await build(routeSessionId(params))));
39292
+ if (htmlPath !== false) {
39293
+ routes.get(htmlPath, async ({ params }) => {
39294
+ const report = await build(routeSessionId(params));
39295
+ const body = await (options.render ?? ((input) => renderVoiceSessionObservabilityHTML(input, { title })))(report);
39296
+ return new Response(body, {
39297
+ headers: {
39298
+ "content-type": "text/html; charset=utf-8",
39299
+ ...options.headers
39300
+ }
39301
+ });
39302
+ });
39303
+ }
39304
+ if (incidentPath !== false) {
39305
+ routes.get(incidentPath, async ({ params }) => {
39306
+ const report = await build(routeSessionId(params));
39307
+ const body = await (options.renderIncidentMarkdown ?? renderVoiceSessionObservabilityMarkdown)(report);
39308
+ return new Response(body, {
39309
+ headers: {
39310
+ "content-type": "text/markdown; charset=utf-8",
39311
+ ...options.headers
39312
+ }
39313
+ });
39314
+ });
39315
+ }
39316
+ return routes;
39317
+ };
39318
+ // src/incidentBundle.ts
39319
+ import { Elysia as Elysia63 } from "elysia";
39004
39320
  var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
39005
39321
  if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
39006
39322
  return false;
@@ -39217,7 +39533,7 @@ var buildVoiceIncidentBundle = async (options) => {
39217
39533
  var createVoiceIncidentBundleRoutes = (options) => {
39218
39534
  const path = options.path ?? "/api/voice-incidents/:sessionId";
39219
39535
  const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
39220
- const routes = new Elysia62({
39536
+ const routes = new Elysia63({
39221
39537
  name: options.name ?? "absolutejs-voice-incident-bundle"
39222
39538
  });
39223
39539
  const getSessionId = (params) => params.sessionId ?? "";
@@ -39418,19 +39734,19 @@ var summarizeVoiceOpsStatus = async (options) => {
39418
39734
  };
39419
39735
  };
39420
39736
  // src/opsStatusRoutes.ts
39421
- import { Elysia as Elysia63 } from "elysia";
39422
- var escapeHtml59 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
39737
+ import { Elysia as Elysia64 } from "elysia";
39738
+ var escapeHtml60 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
39423
39739
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
39424
39740
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
39425
39741
  const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
39426
39742
  const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
39427
- return `<article class="surface ${escapeHtml59(surface.status)}"><span>${escapeHtml59(surface.status.toUpperCase())}</span><h2>${escapeHtml59(key)}</h2><strong>${escapeHtml59(value)}</strong></article>`;
39743
+ return `<article class="surface ${escapeHtml60(surface.status)}"><span>${escapeHtml60(surface.status.toUpperCase())}</span><h2>${escapeHtml60(key)}</h2><strong>${escapeHtml60(value)}</strong></article>`;
39428
39744
  }).join("");
39429
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml59(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml59(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml59(report.status)}">Overall: ${escapeHtml59(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
39745
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml60(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml60(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml60(report.status)}">Overall: ${escapeHtml60(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
39430
39746
  };
39431
39747
  var createVoiceOpsStatusRoutes = (options) => {
39432
39748
  const path = options.path ?? "/api/voice/ops-status";
39433
- const routes = new Elysia63({
39749
+ const routes = new Elysia64({
39434
39750
  name: options.name ?? "absolutejs-voice-ops-status"
39435
39751
  });
39436
39752
  routes.get(path, async () => summarizeVoiceOpsStatus(options));
@@ -39863,8 +40179,8 @@ var createVoiceTTSProviderRouter = (options) => {
39863
40179
  };
39864
40180
  };
39865
40181
  // src/traceDeliveryRoutes.ts
39866
- import { Elysia as Elysia64 } from "elysia";
39867
- var escapeHtml60 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
40182
+ import { Elysia as Elysia65 } from "elysia";
40183
+ var escapeHtml61 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
39868
40184
  var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
39869
40185
  var getNumber12 = (value) => {
39870
40186
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -39945,14 +40261,14 @@ var renderSinkResults2 = (delivery) => {
39945
40261
  if (entries.length === 0) {
39946
40262
  return "<p>No sink delivery attempts recorded yet.</p>";
39947
40263
  }
39948
- return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml60(sinkId)}</strong>: ${escapeHtml60(result.status)}${result.deliveredTo ? ` to ${escapeHtml60(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml60(result.error)})` : ""}</li>`).join("")}</ul>`;
40264
+ return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml61(sinkId)}</strong>: ${escapeHtml61(result.status)}${result.deliveredTo ? ` to ${escapeHtml61(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml61(result.error)})` : ""}</li>`).join("")}</ul>`;
39949
40265
  };
39950
- var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml60(event.type)} <small>${escapeHtml60(event.id)}</small>${event.sessionId ? ` session=${escapeHtml60(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
40266
+ var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml61(event.type)} <small>${escapeHtml61(event.id)}</small>${event.sessionId ? ` session=${escapeHtml61(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
39951
40267
  var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
39952
40268
  const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
39953
- const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml60(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
39954
- const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml60(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml60(delivery.deliveryStatus)}</span><h2>${escapeHtml60(delivery.id)}</h2><p>${escapeHtml60(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml60(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml60(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
39955
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml60(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml60(title)}</h1><p>Checked ${escapeHtml60(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
40269
+ const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml61(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
40270
+ const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml61(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml61(delivery.deliveryStatus)}</span><h2>${escapeHtml61(delivery.id)}</h2><p>${escapeHtml61(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml61(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml61(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
40271
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml61(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml61(title)}</h1><p>Checked ${escapeHtml61(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
39956
40272
  };
39957
40273
  var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
39958
40274
  var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
@@ -39972,7 +40288,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
39972
40288
  const path = options.path ?? "/api/voice-trace-deliveries";
39973
40289
  const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
39974
40290
  const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
39975
- const routes = new Elysia64({
40291
+ const routes = new Elysia65({
39976
40292
  name: options.name ?? "absolutejs-voice-trace-deliveries"
39977
40293
  }).get(path, createVoiceTraceDeliveryJSONHandler(options));
39978
40294
  if (htmlPath !== false) {
@@ -40069,7 +40385,7 @@ var createVoiceMemoryStore = () => {
40069
40385
  return { get, getOrCreate, list, remove, set };
40070
40386
  };
40071
40387
  // src/opsWebhook.ts
40072
- import { Elysia as Elysia65 } from "elysia";
40388
+ import { Elysia as Elysia66 } from "elysia";
40073
40389
  var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
40074
40390
  var signVoiceOpsWebhookBody = async (input) => {
40075
40391
  const encoder2 = new TextEncoder;
@@ -40199,7 +40515,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
40199
40515
  };
40200
40516
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
40201
40517
  const path = options.path ?? "/api/voice-ops/webhook";
40202
- return new Elysia65().post(path, async ({ body, request, set }) => {
40518
+ return new Elysia66().post(path, async ({ body, request, set }) => {
40203
40519
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
40204
40520
  if (options.signingSecret) {
40205
40521
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -40654,7 +40970,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
40654
40970
  };
40655
40971
  };
40656
40972
  // src/postCallAnalysis.ts
40657
- import { Elysia as Elysia66 } from "elysia";
40973
+ import { Elysia as Elysia67 } from "elysia";
40658
40974
  var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
40659
40975
  var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
40660
40976
  var getPathValue3 = (source, path) => {
@@ -40833,7 +41149,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
40833
41149
  };
40834
41150
  var createVoicePostCallAnalysisRoutes = (options = {}) => {
40835
41151
  const path = options.path ?? "/api/voice/post-call-analysis";
40836
- const routes = new Elysia66({
41152
+ const routes = new Elysia67({
40837
41153
  name: options.name ?? "absolutejs-voice-post-call-analysis"
40838
41154
  });
40839
41155
  routes.get(path, async ({ query }) => {
@@ -40858,7 +41174,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
40858
41174
  return routes;
40859
41175
  };
40860
41176
  // src/guardrails.ts
40861
- import { Elysia as Elysia67 } from "elysia";
41177
+ import { Elysia as Elysia68 } from "elysia";
40862
41178
  var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
40863
41179
  var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
40864
41180
  var matchesRule = async (rule, input) => {
@@ -41160,7 +41476,7 @@ var resolveGuardrailReport = async (options, input) => {
41160
41476
  };
41161
41477
  var createVoiceGuardrailRoutes = (options = {}) => {
41162
41478
  const path = options.path ?? "/api/voice/guardrails";
41163
- const routes = new Elysia67({
41479
+ const routes = new Elysia68({
41164
41480
  name: options.name ?? "absolutejs-voice-guardrails"
41165
41481
  });
41166
41482
  routes.all(path, async ({ request }) => {
@@ -41939,7 +42255,7 @@ var shapeTelephonyAssistantText = (text, options = {}) => {
41939
42255
  return ensureTerminalPunctuation(normalizeWhitespace(limitedChars));
41940
42256
  };
41941
42257
  // src/proofPack.ts
41942
- import { Elysia as Elysia68 } from "elysia";
42258
+ import { Elysia as Elysia69 } from "elysia";
41943
42259
  import { mkdir as mkdir5 } from "fs/promises";
41944
42260
  import { dirname as dirname3, join as join4 } from "path";
41945
42261
  var toGeneratedAt = (value) => value === undefined ? new Date().toISOString() : typeof value === "number" ? new Date(value).toISOString() : value;
@@ -42505,7 +42821,7 @@ var createVoiceProofPackArtifacts = (input) => [
42505
42821
  var createVoiceProofPackRoutes = (options) => {
42506
42822
  const jsonPath = options.jsonPath ?? "/api/voice/proof-pack";
42507
42823
  const markdownPath = options.markdownPath ?? "/voice/proof-pack.md";
42508
- const app = new Elysia68({ name: options.name ?? "voice-proof-pack" });
42824
+ const app = new Elysia69({ name: options.name ?? "voice-proof-pack" });
42509
42825
  if (jsonPath !== false) {
42510
42826
  app.get(jsonPath, async () => new Response(JSON.stringify(await resolveProofPack(options.source), null, 2), {
42511
42827
  headers: {
@@ -42640,6 +42956,8 @@ export {
42640
42956
  renderVoiceSloCalibrationMarkdown,
42641
42957
  renderVoiceSimulationSuiteHTML,
42642
42958
  renderVoiceSessionsHTML,
42959
+ renderVoiceSessionObservabilityMarkdown,
42960
+ renderVoiceSessionObservabilityHTML,
42643
42961
  renderVoiceScenarioFixtureEvalHTML,
42644
42962
  renderVoiceScenarioEvalHTML,
42645
42963
  renderVoiceResilienceHTML,
@@ -42880,6 +43198,7 @@ export {
42880
43198
  createVoiceSessionReplayJSONHandler,
42881
43199
  createVoiceSessionReplayHTMLHandler,
42882
43200
  createVoiceSessionRecord,
43201
+ createVoiceSessionObservabilityRoutes,
42883
43202
  createVoiceSessionListRoutes,
42884
43203
  createVoiceSession,
42885
43204
  createVoiceScopedTraceEventStore,
@@ -43156,6 +43475,7 @@ export {
43156
43475
  buildVoiceSloCalibrationReport,
43157
43476
  buildVoiceSessionSnapshotStatus,
43158
43477
  buildVoiceSessionSnapshot,
43478
+ buildVoiceSessionObservabilityReport,
43159
43479
  buildVoiceReconnectProofReport,
43160
43480
  buildVoiceReconnectProfileEvidenceSummary,
43161
43481
  buildVoiceRealtimeProviderContractMatrix,
@@ -43169,6 +43489,7 @@ export {
43169
43489
  buildVoiceRealCallProfileEvidenceFromTraceEvents,
43170
43490
  buildVoiceRealCallProfileEvidenceFromReconnectProofReports,
43171
43491
  buildVoiceRealCallProfileDefaults,
43492
+ buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck,
43172
43493
  buildVoiceRealCallEvidenceRuntimeReadinessCheck,
43173
43494
  buildVoiceReadinessRecoveryActions,
43174
43495
  buildVoiceProviderSloReport,
@@ -333,6 +333,17 @@ export type VoiceRealCallEvidenceRuntimeReadinessCheckOptions = {
333
333
  minStoredEvidence?: number;
334
334
  sourceHref?: string;
335
335
  };
336
+ export type VoiceRealCallEvidenceRuntimeWorkerReadinessCheckOptions = {
337
+ collectHref?: string;
338
+ failOnNotRunning?: boolean;
339
+ failOnStale?: boolean;
340
+ href?: string;
341
+ label?: string;
342
+ maxLastCollectedAgeMs?: number;
343
+ now?: () => Date;
344
+ requireRunning?: boolean;
345
+ sourceHref?: string;
346
+ };
336
347
  export type VoiceProofTrendRealCallProfileReportOptions = VoiceProofTrendProfileSummaryOptions & {
337
348
  baseUrl?: string;
338
349
  evidence: readonly VoiceProofTrendRealCallProfileEvidence[];
@@ -757,6 +768,7 @@ export declare const createVoiceRealCallEvidenceRuntime: (options: VoiceRealCall
757
768
  export declare const buildVoiceRealCallEvidenceRuntimeReadinessCheck: (report: VoiceRealCallEvidenceRuntimeReport, options?: VoiceRealCallEvidenceRuntimeReadinessCheckOptions) => VoiceProductionReadinessCheck;
758
769
  export declare const createVoiceRealCallEvidenceRuntimeWorker: (options: VoiceRealCallEvidenceRuntimeWorkerOptions) => VoiceRealCallEvidenceRuntimeWorker;
759
770
  export declare const createVoiceRealCallEvidenceRuntimeWorkerLoop: (options: VoiceRealCallEvidenceRuntimeWorkerLoopOptions) => VoiceRealCallEvidenceRuntimeWorkerLoop;
771
+ export declare const buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck: (health: VoiceRealCallEvidenceRuntimeWorkerHealthReport, options?: VoiceRealCallEvidenceRuntimeWorkerReadinessCheckOptions) => VoiceProductionReadinessCheck;
760
772
  export declare const createVoiceRealCallProfileTraceCollector: <TEvent extends StoredVoiceTraceEvent = StoredVoiceTraceEvent>(options: VoiceRealCallProfileTraceCollectorOptions<TEvent>) => VoiceRealCallProfileTraceCollector<TEvent>;
761
773
  export declare const buildVoiceProofTrendProfileSummaries: (input: VoiceProofTrendReport | readonly VoiceProofTrendReport[], options?: VoiceProofTrendProfileSummaryOptions) => VoiceProofTrendProfileSummary[];
762
774
  export declare const buildVoiceProofTrendReportFromRealCallProfiles: (options: VoiceProofTrendRealCallProfileReportOptions) => VoiceProofTrendReport;
@@ -4003,12 +4003,17 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
4003
4003
  const tick = () => worker.collect();
4004
4004
  return {
4005
4005
  collect: tick,
4006
- health: () => ({
4007
- ...worker.health(),
4008
- isRunning: isRunning(),
4009
- lastStartedAt,
4010
- lastStoppedAt
4011
- }),
4006
+ health: () => {
4007
+ const health = worker.health();
4008
+ const running = isRunning();
4009
+ return {
4010
+ ...health,
4011
+ isRunning: running,
4012
+ lastStartedAt,
4013
+ lastStoppedAt,
4014
+ status: running && health.status === "idle" ? "running" : health.status
4015
+ };
4016
+ },
4012
4017
  isRunning,
4013
4018
  start: () => {
4014
4019
  if (timer) {
@@ -4031,6 +4036,77 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
4031
4036
  tick
4032
4037
  };
4033
4038
  };
4039
+ var buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck = (health, options = {}) => {
4040
+ const requireRunning = options.requireRunning ?? true;
4041
+ const issues = [];
4042
+ const warnings = [];
4043
+ const now = options.now ?? (() => new Date);
4044
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-evidence-runtime/worker";
4045
+ const href = options.href ?? "/voice/real-call-evidence-runtime";
4046
+ if (health.error) {
4047
+ issues.push(`Real-call evidence auto-collector error: ${health.error}.`);
4048
+ }
4049
+ if (health.status === "fail") {
4050
+ issues.push("Real-call evidence auto-collector is failing.");
4051
+ }
4052
+ if (requireRunning && !health.isRunning) {
4053
+ const message = "Real-call evidence auto-collector is not running; evidence is only collected manually.";
4054
+ if (options.failOnNotRunning) {
4055
+ issues.push(message);
4056
+ } else {
4057
+ warnings.push(message);
4058
+ }
4059
+ }
4060
+ if (health.collectCount === 0) {
4061
+ warnings.push("Real-call evidence auto-collector has not collected yet.");
4062
+ }
4063
+ if (options.maxLastCollectedAgeMs && health.lastCollectedAt) {
4064
+ const ageMs = now().getTime() - new Date(health.lastCollectedAt).getTime();
4065
+ if (Number.isFinite(ageMs) && ageMs > options.maxLastCollectedAgeMs) {
4066
+ const message = `Last real-call evidence auto-collection is ${String(ageMs)}ms old.`;
4067
+ if (options.failOnStale) {
4068
+ issues.push(message);
4069
+ } else {
4070
+ warnings.push(message);
4071
+ }
4072
+ }
4073
+ }
4074
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
4075
+ return {
4076
+ actions: [
4077
+ {
4078
+ description: "Run one collection cycle immediately and update worker health.",
4079
+ href: options.collectHref ?? "/api/voice/real-call-evidence-runtime/collect",
4080
+ label: "Collect real-call evidence",
4081
+ method: "POST"
4082
+ },
4083
+ {
4084
+ description: "Open rolling real-call evidence and inspect worker health.",
4085
+ href,
4086
+ label: "Open real-call evidence runtime"
4087
+ }
4088
+ ],
4089
+ detail: status === "pass" ? `Auto-collector is running with ${String(health.collectCount)} collection(s).` : [...issues, ...warnings].join(" "),
4090
+ gateExplanation: {
4091
+ evidenceHref: sourceHref,
4092
+ observed: health.isRunning ? "running" : "manual",
4093
+ remediation: "Enable the real-call evidence worker loop in production, keep it healthy, and run real traffic so rolling evidence stays fresh.",
4094
+ sourceHref: href,
4095
+ threshold: requireRunning ? "running" : "available",
4096
+ thresholdLabel: "Real-call evidence collection mode",
4097
+ unit: "status"
4098
+ },
4099
+ href,
4100
+ label: options.label ?? "Real-call evidence auto-collector",
4101
+ proofSource: {
4102
+ href: sourceHref,
4103
+ source: health.source,
4104
+ sourceLabel: "Real-call evidence worker health"
4105
+ },
4106
+ status,
4107
+ value: `${health.isRunning ? "running" : "manual"} / ${String(health.collectCount)} collections / ${health.status}`
4108
+ };
4109
+ };
4034
4110
  var realCallProfileTraceSignalTypes = new Set([
4035
4111
  "client.barge_in",
4036
4112
  "client.browser_media",
@@ -0,0 +1,104 @@
1
+ import { Elysia } from "elysia";
2
+ import { type VoiceFailureReplayReport, type VoiceOperationsRecord, type VoiceOperationsRecordOptions } from "./operationsRecord";
3
+ import type { StoredVoiceTraceEvent } from "./trace";
4
+ export type VoiceSessionObservabilityStatus = "failed" | "healthy" | "warning";
5
+ export type VoiceSessionObservabilityLink = {
6
+ href: string;
7
+ label: string;
8
+ rel: "call-debugger" | "incident-markdown" | "operations-record" | "trace-timeline" | "custom";
9
+ };
10
+ export type VoiceSessionObservabilityStage = {
11
+ at: number;
12
+ elapsedMs?: number;
13
+ label: string;
14
+ offsetMs: number;
15
+ provider?: string;
16
+ status?: string;
17
+ type: StoredVoiceTraceEvent["type"];
18
+ };
19
+ export type VoiceSessionObservabilityTurn = {
20
+ assistantReplies: number;
21
+ durationMs?: number;
22
+ endedAt?: number;
23
+ errors: number;
24
+ providerDecisions: number;
25
+ stages: VoiceSessionObservabilityStage[];
26
+ startedAt?: number;
27
+ toolCalls: number;
28
+ transcripts: number;
29
+ turnId: string;
30
+ };
31
+ export type VoiceSessionObservabilityReport = {
32
+ checkedAt: number;
33
+ failureReplay: VoiceFailureReplayReport;
34
+ incidentMarkdown: string;
35
+ links: VoiceSessionObservabilityLink[];
36
+ record: VoiceOperationsRecord;
37
+ sessionId: string;
38
+ status: VoiceSessionObservabilityStatus;
39
+ summary: {
40
+ durationMs?: number;
41
+ errors: number;
42
+ events: number;
43
+ fallbacks: number;
44
+ guardrailBlocks: number;
45
+ handoffs: number;
46
+ providerRecoveryStatus: VoiceOperationsRecord["providerDecisionSummary"]["recoveryStatus"];
47
+ providers: string[];
48
+ telephonyMediaEvents: number;
49
+ toolCalls: number;
50
+ turns: number;
51
+ };
52
+ turns: VoiceSessionObservabilityTurn[];
53
+ };
54
+ export type VoiceSessionObservabilityReportOptions = Omit<VoiceOperationsRecordOptions, "sessionId"> & {
55
+ callDebuggerHref?: false | string | ((sessionId: string) => string);
56
+ customLinks?: readonly VoiceSessionObservabilityLink[];
57
+ incidentMarkdownHref?: false | string | ((sessionId: string) => string);
58
+ operationsRecordHref?: false | string | ((sessionId: string) => string);
59
+ sessionId: string;
60
+ traceTimelineHref?: false | string | ((sessionId: string) => string);
61
+ };
62
+ export type VoiceSessionObservabilityRoutesOptions = Omit<VoiceSessionObservabilityReportOptions, "sessionId"> & {
63
+ headers?: HeadersInit;
64
+ htmlPath?: false | string;
65
+ incidentPath?: false | string;
66
+ name?: string;
67
+ path?: string;
68
+ render?: (report: VoiceSessionObservabilityReport) => Promise<string> | string;
69
+ renderIncidentMarkdown?: (report: VoiceSessionObservabilityReport) => Promise<string> | string;
70
+ title?: string;
71
+ };
72
+ export declare const buildVoiceSessionObservabilityReport: (options: VoiceSessionObservabilityReportOptions) => Promise<VoiceSessionObservabilityReport>;
73
+ export declare const renderVoiceSessionObservabilityMarkdown: (report: VoiceSessionObservabilityReport) => string;
74
+ export declare const renderVoiceSessionObservabilityHTML: (report: VoiceSessionObservabilityReport, options?: {
75
+ title?: string;
76
+ }) => string;
77
+ export declare const createVoiceSessionObservabilityRoutes: (options: VoiceSessionObservabilityRoutesOptions) => Elysia<"", {
78
+ decorator: {};
79
+ store: {};
80
+ derive: {};
81
+ resolve: {};
82
+ }, {
83
+ typebox: {};
84
+ error: {};
85
+ }, {
86
+ schema: {};
87
+ standaloneSchema: {};
88
+ macro: {};
89
+ macroFn: {};
90
+ parser: {};
91
+ response: {};
92
+ }, {}, {
93
+ derive: {};
94
+ resolve: {};
95
+ schema: {};
96
+ standaloneSchema: {};
97
+ response: {};
98
+ }, {
99
+ derive: {};
100
+ resolve: {};
101
+ schema: {};
102
+ standaloneSchema: {};
103
+ response: {};
104
+ }>;
package/dist/vue/index.js CHANGED
@@ -3924,12 +3924,17 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
3924
3924
  const tick = () => worker.collect();
3925
3925
  return {
3926
3926
  collect: tick,
3927
- health: () => ({
3928
- ...worker.health(),
3929
- isRunning: isRunning(),
3930
- lastStartedAt,
3931
- lastStoppedAt
3932
- }),
3927
+ health: () => {
3928
+ const health = worker.health();
3929
+ const running = isRunning();
3930
+ return {
3931
+ ...health,
3932
+ isRunning: running,
3933
+ lastStartedAt,
3934
+ lastStoppedAt,
3935
+ status: running && health.status === "idle" ? "running" : health.status
3936
+ };
3937
+ },
3933
3938
  isRunning,
3934
3939
  start: () => {
3935
3940
  if (timer) {
@@ -3952,6 +3957,77 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
3952
3957
  tick
3953
3958
  };
3954
3959
  };
3960
+ var buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck = (health, options = {}) => {
3961
+ const requireRunning = options.requireRunning ?? true;
3962
+ const issues = [];
3963
+ const warnings = [];
3964
+ const now = options.now ?? (() => new Date);
3965
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-evidence-runtime/worker";
3966
+ const href = options.href ?? "/voice/real-call-evidence-runtime";
3967
+ if (health.error) {
3968
+ issues.push(`Real-call evidence auto-collector error: ${health.error}.`);
3969
+ }
3970
+ if (health.status === "fail") {
3971
+ issues.push("Real-call evidence auto-collector is failing.");
3972
+ }
3973
+ if (requireRunning && !health.isRunning) {
3974
+ const message = "Real-call evidence auto-collector is not running; evidence is only collected manually.";
3975
+ if (options.failOnNotRunning) {
3976
+ issues.push(message);
3977
+ } else {
3978
+ warnings.push(message);
3979
+ }
3980
+ }
3981
+ if (health.collectCount === 0) {
3982
+ warnings.push("Real-call evidence auto-collector has not collected yet.");
3983
+ }
3984
+ if (options.maxLastCollectedAgeMs && health.lastCollectedAt) {
3985
+ const ageMs = now().getTime() - new Date(health.lastCollectedAt).getTime();
3986
+ if (Number.isFinite(ageMs) && ageMs > options.maxLastCollectedAgeMs) {
3987
+ const message = `Last real-call evidence auto-collection is ${String(ageMs)}ms old.`;
3988
+ if (options.failOnStale) {
3989
+ issues.push(message);
3990
+ } else {
3991
+ warnings.push(message);
3992
+ }
3993
+ }
3994
+ }
3995
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
3996
+ return {
3997
+ actions: [
3998
+ {
3999
+ description: "Run one collection cycle immediately and update worker health.",
4000
+ href: options.collectHref ?? "/api/voice/real-call-evidence-runtime/collect",
4001
+ label: "Collect real-call evidence",
4002
+ method: "POST"
4003
+ },
4004
+ {
4005
+ description: "Open rolling real-call evidence and inspect worker health.",
4006
+ href,
4007
+ label: "Open real-call evidence runtime"
4008
+ }
4009
+ ],
4010
+ detail: status === "pass" ? `Auto-collector is running with ${String(health.collectCount)} collection(s).` : [...issues, ...warnings].join(" "),
4011
+ gateExplanation: {
4012
+ evidenceHref: sourceHref,
4013
+ observed: health.isRunning ? "running" : "manual",
4014
+ remediation: "Enable the real-call evidence worker loop in production, keep it healthy, and run real traffic so rolling evidence stays fresh.",
4015
+ sourceHref: href,
4016
+ threshold: requireRunning ? "running" : "available",
4017
+ thresholdLabel: "Real-call evidence collection mode",
4018
+ unit: "status"
4019
+ },
4020
+ href,
4021
+ label: options.label ?? "Real-call evidence auto-collector",
4022
+ proofSource: {
4023
+ href: sourceHref,
4024
+ source: health.source,
4025
+ sourceLabel: "Real-call evidence worker health"
4026
+ },
4027
+ status,
4028
+ value: `${health.isRunning ? "running" : "manual"} / ${String(health.collectCount)} collections / ${health.status}`
4029
+ };
4030
+ };
3955
4031
  var realCallProfileTraceSignalTypes = new Set([
3956
4032
  "client.barge_in",
3957
4033
  "client.browser_media",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.457",
3
+ "version": "0.0.22-beta.459",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",