@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.
- package/dist/client/index.js +82 -6
- package/dist/index.d.ts +4 -2
- package/dist/index.js +350 -29
- package/dist/proofTrends.d.ts +12 -0
- package/dist/react/index.js +82 -6
- package/dist/sessionObservability.d.ts +104 -0
- package/dist/vue/index.js +82 -6
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -6908,12 +6908,17 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
|
|
|
6908
6908
|
const tick = () => worker.collect();
|
|
6909
6909
|
return {
|
|
6910
6910
|
collect: tick,
|
|
6911
|
-
health: () =>
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
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
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
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/
|
|
39078
|
+
// src/sessionObservability.ts
|
|
39003
39079
|
import { Elysia as Elysia62 } from "elysia";
|
|
39080
|
+
var escapeHtml59 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
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
|
|
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
|
|
39422
|
-
var
|
|
39737
|
+
import { Elysia as Elysia64 } from "elysia";
|
|
39738
|
+
var escapeHtml60 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
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 ${
|
|
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>${
|
|
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
|
|
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
|
|
39867
|
-
var
|
|
40182
|
+
import { Elysia as Elysia65 } from "elysia";
|
|
40183
|
+
var escapeHtml61 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
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>${
|
|
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>${
|
|
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="${
|
|
39954
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
39955
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
package/dist/proofTrends.d.ts
CHANGED
|
@@ -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;
|
package/dist/react/index.js
CHANGED
|
@@ -4003,12 +4003,17 @@ var createVoiceRealCallEvidenceRuntimeWorkerLoop = (options) => {
|
|
|
4003
4003
|
const tick = () => worker.collect();
|
|
4004
4004
|
return {
|
|
4005
4005
|
collect: tick,
|
|
4006
|
-
health: () =>
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
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
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
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",
|