@absolutejs/voice 0.0.22-beta.330 → 0.0.22-beta.331
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/index.d.ts +2 -2
- package/dist/index.js +149 -2
- package/dist/operationsRecord.d.ts +71 -0
- package/dist/testing/index.js +147 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ export { acknowledgeVoiceMonitorIssue, buildVoiceMonitorRunReport, createVoiceMe
|
|
|
73
73
|
export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './readinessProfiles';
|
|
74
74
|
export { assertVoiceProviderContractMatrixEvidence, assertVoiceProviderStackEvidence, buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderContractMatrixEvidence, evaluateVoiceProviderStackEvidence, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
|
|
75
75
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
76
|
-
export { assertVoiceOperationsRecordGuardrails, assertVoiceOperationsRecordProviderRecovery, buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, evaluateVoiceOperationsRecordGuardrails, evaluateVoiceOperationsRecordProviderRecovery, renderVoiceOperationsRecordGuardrailMarkdown, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown } from './operationsRecord';
|
|
76
|
+
export { assertVoiceOperationsRecordGuardrails, assertVoiceOperationsRecordProviderRecovery, buildVoiceFailureReplay, buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, evaluateVoiceOperationsRecordGuardrails, evaluateVoiceOperationsRecordProviderRecovery, renderVoiceFailureReplayMarkdown, renderVoiceOperationsRecordGuardrailMarkdown, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown } from './operationsRecord';
|
|
77
77
|
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';
|
|
78
78
|
export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown } from './opsRecovery';
|
|
79
79
|
export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
|
|
@@ -142,7 +142,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptio
|
|
|
142
142
|
export type { VoiceMonitorDefinition, VoiceMonitorEvaluation, VoiceMonitorEvaluationInput, VoiceMonitorIssue, VoiceMonitorIssueStatus, VoiceMonitorIssueStore, VoiceMonitorNotifier, VoiceMonitorNotifierDeliveryInput, VoiceMonitorNotifierDeliveryOptions, VoiceMonitorNotifierDeliveryReceipt, VoiceMonitorNotifierDeliveryReceiptStore, VoiceMonitorNotifierDeliveryReport, VoiceMonitorNotifierDeliveryResult, VoiceMonitorRoutesOptions, VoiceMonitorRun, VoiceMonitorRunOptions, VoiceMonitorRunReport, VoiceMonitorRunner, VoiceMonitorRunnerOptions, VoiceMonitorRunnerRoutesOptions, VoiceMonitorRunnerTickResult, VoiceMonitorSeverity, VoiceMonitorStatus, VoiceMonitorWebhookNotifierOptions } from './voiceMonitoring';
|
|
143
143
|
export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
|
|
144
144
|
export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixAssertionInput, VoiceProviderContractMatrixAssertionReport, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackAssertionInput, VoiceProviderStackAssertionReport, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
|
|
145
|
-
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordGuardrailAssertionInput, VoiceOperationsRecordGuardrailAssertionReport, VoiceOperationsRecordGuardrailDecision, VoiceOperationsRecordGuardrailFinding, VoiceOperationsRecordGuardrailSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordProviderDecisionRecoveryStatus, VoiceOperationsRecordProviderDecisionSummary, VoiceOperationsRecordProviderRecoveryAssertionInput, VoiceOperationsRecordProviderRecoveryAssertionReport, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTelephonyMediaEvent, VoiceOperationsRecordTelephonyMediaSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
|
|
145
|
+
export type { VoiceFailureReplayMediaStep, VoiceFailureReplayOptions, VoiceFailureReplayProviderStep, VoiceFailureReplayReport, VoiceFailureReplayStatus, VoiceFailureReplayTurn, VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordGuardrailAssertionInput, VoiceOperationsRecordGuardrailAssertionReport, VoiceOperationsRecordGuardrailDecision, VoiceOperationsRecordGuardrailFinding, VoiceOperationsRecordGuardrailSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordProviderDecisionRecoveryStatus, VoiceOperationsRecordProviderDecisionSummary, VoiceOperationsRecordProviderRecoveryAssertionInput, VoiceOperationsRecordProviderRecoveryAssertionReport, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTelephonyMediaEvent, VoiceOperationsRecordTelephonyMediaSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
|
|
146
146
|
export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliveryAssertionInput, VoiceObservabilityExportDeliveryAssertionReport, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryHistory, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReceipt, VoiceObservabilityExportDeliveryReceiptStore, VoiceObservabilityExportDeliveryReport, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportIngestedRecordKind, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportRecordValidationOptions, VoiceObservabilityExportReplayIssue, VoiceObservabilityExportReplayIssueCode, VoiceObservabilityExportReplayAssertionInput, VoiceObservabilityExportReplayAssertionReport, VoiceObservabilityExportReplayRecords, VoiceObservabilityExportReplayReport, VoiceObservabilityExportReplayRoutesOptions, VoiceObservabilityExportReplaySource, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportSchema, VoiceObservabilityExportStatus, VoiceObservabilityExportValidationIssue, VoiceObservabilityExportValidationResult } from './observabilityExport';
|
|
147
147
|
export type { VoiceOpsRecoveryFailedSession, VoiceOpsRecoveryInterventionSummary, VoiceOpsRecoveryIssue, VoiceOpsRecoveryIssueCode, VoiceOpsRecoveryLinks, VoiceOpsRecoveryProviderSummary, VoiceOpsRecoveryReport, VoiceOpsRecoveryReportOptions, VoiceOpsRecoveryRoutesOptions, VoiceOpsRecoveryStatus } from './opsRecovery';
|
|
148
148
|
export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
|
package/dist/index.js
CHANGED
|
@@ -27838,6 +27838,7 @@ var pushMissingValuesIssue = (input) => {
|
|
|
27838
27838
|
}
|
|
27839
27839
|
};
|
|
27840
27840
|
var resolveRoutePath = (path, sessionId) => path.replace(":sessionId", encodeURIComponent(sessionId));
|
|
27841
|
+
var resolveOperationsRecordHref = (href, record) => typeof href === "function" ? href({ record, sessionId: record.sessionId }) : href;
|
|
27841
27842
|
var toHandoff = (event) => ({
|
|
27842
27843
|
at: event.at,
|
|
27843
27844
|
fromAgentId: getString17(event.payload.fromAgentId),
|
|
@@ -28252,6 +28253,150 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
28252
28253
|
}
|
|
28253
28254
|
return report;
|
|
28254
28255
|
};
|
|
28256
|
+
var getAssistantRepliesForTurn = (record, turnId) => turnId ? record.transcript.find((turn) => turn.id === turnId)?.assistantReplies ?? [] : [];
|
|
28257
|
+
var mediaIssueForStep = (step) => {
|
|
28258
|
+
const event = step.event.toLowerCase();
|
|
28259
|
+
if (event === "error") {
|
|
28260
|
+
return "Carrier media stream emitted an error.";
|
|
28261
|
+
}
|
|
28262
|
+
if (event === "media" && step.audioBytes <= 0) {
|
|
28263
|
+
return "Carrier media packet had no audio bytes.";
|
|
28264
|
+
}
|
|
28265
|
+
return;
|
|
28266
|
+
};
|
|
28267
|
+
var buildVoiceFailureReplay = (record, options = {}) => {
|
|
28268
|
+
const providerSteps = record.providerDecisions.filter((decision) => ["degraded", "error", "fallback", "selected", "success"].includes(decision.status ?? "")).map((decision) => ({
|
|
28269
|
+
at: decision.at,
|
|
28270
|
+
elapsedMs: decision.elapsedMs,
|
|
28271
|
+
error: decision.error,
|
|
28272
|
+
fallbackProvider: decision.fallbackProvider,
|
|
28273
|
+
kind: decision.kind,
|
|
28274
|
+
provider: decision.provider,
|
|
28275
|
+
reason: decision.reason,
|
|
28276
|
+
selectedProvider: decision.selectedProvider,
|
|
28277
|
+
status: decision.status,
|
|
28278
|
+
surface: decision.surface,
|
|
28279
|
+
turnId: decision.turnId,
|
|
28280
|
+
userHeard: getAssistantRepliesForTurn(record, decision.turnId)
|
|
28281
|
+
}));
|
|
28282
|
+
const mediaSteps = record.telephonyMedia.events.map((event) => {
|
|
28283
|
+
const step = {
|
|
28284
|
+
at: event.at,
|
|
28285
|
+
audioBytes: event.audioBytes,
|
|
28286
|
+
carrier: event.carrier,
|
|
28287
|
+
direction: event.direction,
|
|
28288
|
+
event: event.event,
|
|
28289
|
+
streamId: event.streamId
|
|
28290
|
+
};
|
|
28291
|
+
return {
|
|
28292
|
+
...step,
|
|
28293
|
+
issue: mediaIssueForStep(step)
|
|
28294
|
+
};
|
|
28295
|
+
});
|
|
28296
|
+
const providerIssues = providerSteps.filter((step) => step.status === "error" || step.status === "fallback" || step.status === "degraded").map((step) => {
|
|
28297
|
+
const provider = step.provider ?? step.selectedProvider ?? "provider";
|
|
28298
|
+
const recovery = step.status === "fallback" ? `recovered through ${step.fallbackProvider ?? step.selectedProvider ?? "fallback"}` : step.status === "degraded" ? `degraded to ${step.fallbackProvider ?? step.selectedProvider ?? "fallback"}` : "failed before recovery";
|
|
28299
|
+
return `${provider} ${recovery}${step.reason ? `: ${step.reason}` : ""}`;
|
|
28300
|
+
});
|
|
28301
|
+
const mediaIssues = [
|
|
28302
|
+
...mediaSteps.map((step) => step.issue).filter((issue) => typeof issue === "string"),
|
|
28303
|
+
record.telephonyMedia.total > 0 && record.telephonyMedia.inbound === 0 ? "Carrier stream has no inbound media evidence." : undefined,
|
|
28304
|
+
record.telephonyMedia.total > 0 && record.telephonyMedia.outbound === 0 ? "Carrier stream has no outbound assistant media/control evidence." : undefined
|
|
28305
|
+
].filter((issue) => typeof issue === "string");
|
|
28306
|
+
const userHeard = [
|
|
28307
|
+
...new Set(record.transcript.flatMap((turn) => turn.assistantReplies))
|
|
28308
|
+
];
|
|
28309
|
+
const status = record.providerDecisionSummary.errors > 0 || record.telephonyMedia.errors > 0 ? "failed" : record.providerDecisionSummary.degraded > 0 ? "degraded" : record.providerDecisionSummary.fallbacks > 0 || mediaIssues.length > 0 ? "recovered" : "healthy";
|
|
28310
|
+
const turns = record.transcript.map((turn) => ({
|
|
28311
|
+
...turn,
|
|
28312
|
+
media: mediaSteps.filter((step) => record.traceEvents.some((event) => event.turnId === turn.id && event.type === "client.telephony_media" && event.at === step.at)),
|
|
28313
|
+
providers: providerSteps.filter((step) => step.turnId === turn.id)
|
|
28314
|
+
}));
|
|
28315
|
+
const issues = [...providerIssues, ...mediaIssues];
|
|
28316
|
+
const reportBase = {
|
|
28317
|
+
media: {
|
|
28318
|
+
audioBytes: record.telephonyMedia.audioBytes,
|
|
28319
|
+
clears: record.telephonyMedia.clears,
|
|
28320
|
+
errors: record.telephonyMedia.errors,
|
|
28321
|
+
issues: mediaIssues,
|
|
28322
|
+
steps: mediaSteps,
|
|
28323
|
+
total: record.telephonyMedia.total
|
|
28324
|
+
},
|
|
28325
|
+
ok: status === "healthy" || status === "recovered",
|
|
28326
|
+
operationsRecordHref: resolveOperationsRecordHref(options.operationsRecordHref, record),
|
|
28327
|
+
providers: {
|
|
28328
|
+
degraded: record.providerDecisionSummary.degraded,
|
|
28329
|
+
errors: record.providerDecisionSummary.errors,
|
|
28330
|
+
fallbacks: record.providerDecisionSummary.fallbacks,
|
|
28331
|
+
recoveryStatus: record.providerDecisionSummary.recoveryStatus,
|
|
28332
|
+
selected: record.providerDecisionSummary.selected,
|
|
28333
|
+
steps: providerSteps,
|
|
28334
|
+
total: record.providerDecisionSummary.total
|
|
28335
|
+
},
|
|
28336
|
+
sessionId: record.sessionId,
|
|
28337
|
+
status,
|
|
28338
|
+
summary: {
|
|
28339
|
+
callDurationMs: record.summary.callDurationMs,
|
|
28340
|
+
issues,
|
|
28341
|
+
userHeard
|
|
28342
|
+
},
|
|
28343
|
+
turns
|
|
28344
|
+
};
|
|
28345
|
+
return {
|
|
28346
|
+
...reportBase,
|
|
28347
|
+
incidentMarkdown: renderVoiceFailureReplayMarkdown(reportBase)
|
|
28348
|
+
};
|
|
28349
|
+
};
|
|
28350
|
+
var renderVoiceFailureReplayMarkdown = (report) => {
|
|
28351
|
+
const heard = report.summary.userHeard.length ? report.summary.userHeard.map((text) => `- ${text}`).join(`
|
|
28352
|
+
`) : "- none recorded";
|
|
28353
|
+
const providerSteps = report.providers.steps.length ? report.providers.steps.slice(0, 8).map((step) => {
|
|
28354
|
+
const provider = step.provider ?? step.selectedProvider ?? "provider";
|
|
28355
|
+
const parts = [
|
|
28356
|
+
step.status ? `status=${step.status}` : undefined,
|
|
28357
|
+
step.selectedProvider ? `selected=${step.selectedProvider}` : undefined,
|
|
28358
|
+
step.fallbackProvider ? `fallback=${step.fallbackProvider}` : undefined,
|
|
28359
|
+
step.elapsedMs !== undefined ? `elapsed=${step.elapsedMs}ms` : undefined,
|
|
28360
|
+
step.reason
|
|
28361
|
+
].filter((part) => typeof part === "string");
|
|
28362
|
+
return `- ${provider}: ${parts.join("; ")}`;
|
|
28363
|
+
}).join(`
|
|
28364
|
+
`) : "- none recorded";
|
|
28365
|
+
const mediaSteps = report.media.steps.length ? report.media.steps.slice(0, 8).map((step) => {
|
|
28366
|
+
const parts = [
|
|
28367
|
+
step.carrier,
|
|
28368
|
+
step.event,
|
|
28369
|
+
step.direction,
|
|
28370
|
+
step.streamId ? `stream=${step.streamId}` : undefined,
|
|
28371
|
+
`audioBytes=${String(step.audioBytes)}`,
|
|
28372
|
+
step.issue
|
|
28373
|
+
].filter((part) => typeof part === "string");
|
|
28374
|
+
return `- ${parts.join("; ")}`;
|
|
28375
|
+
}).join(`
|
|
28376
|
+
`) : "- none recorded";
|
|
28377
|
+
const issues = report.summary.issues.length ? report.summary.issues.map((issue) => `- ${issue}`).join(`
|
|
28378
|
+
`) : "- none";
|
|
28379
|
+
return [
|
|
28380
|
+
`# Voice Failure Replay: ${report.sessionId}`,
|
|
28381
|
+
"",
|
|
28382
|
+
`Status: ${report.status}`,
|
|
28383
|
+
`Operations record: ${report.operationsRecordHref ?? "not linked"}`,
|
|
28384
|
+
`Duration: ${formatMs5(report.summary.callDurationMs)}`,
|
|
28385
|
+
"",
|
|
28386
|
+
"## What Failed Or Recovered",
|
|
28387
|
+
issues,
|
|
28388
|
+
"",
|
|
28389
|
+
"## Provider Path",
|
|
28390
|
+
providerSteps,
|
|
28391
|
+
"",
|
|
28392
|
+
"## Media Path",
|
|
28393
|
+
mediaSteps,
|
|
28394
|
+
"",
|
|
28395
|
+
"## What The User Heard",
|
|
28396
|
+
heard
|
|
28397
|
+
].join(`
|
|
28398
|
+
`);
|
|
28399
|
+
};
|
|
28255
28400
|
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28256
28401
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
28257
28402
|
var outcomeLabels = (outcome) => [
|
|
@@ -35656,7 +35801,7 @@ var createFakeTTSAdapter = (chunkCount, chunkDelayMs) => ({
|
|
|
35656
35801
|
var defaultOperationsRecordHref = ({
|
|
35657
35802
|
sessionId
|
|
35658
35803
|
}) => `/voice-operations/${encodeURIComponent(sessionId)}`;
|
|
35659
|
-
var
|
|
35804
|
+
var resolveOperationsRecordHref2 = (href, input) => typeof href === "function" ? href(input) : href === undefined ? defaultOperationsRecordHref(input) : href;
|
|
35660
35805
|
var runVoiceTelephonyMediaOperationsSmoke = async (options = {}) => {
|
|
35661
35806
|
const timeoutMs = options.timeoutMs ?? 5000;
|
|
35662
35807
|
const sessionId = options.sessionId ?? `telephony-media-ops-${Date.now()}`;
|
|
@@ -35744,7 +35889,7 @@ var runVoiceTelephonyMediaOperationsSmoke = async (options = {}) => {
|
|
|
35744
35889
|
issues,
|
|
35745
35890
|
ok: issues.length === 0,
|
|
35746
35891
|
operationsRecord,
|
|
35747
|
-
operationsRecordHref:
|
|
35892
|
+
operationsRecordHref: resolveOperationsRecordHref2(options.operationsRecordHref, { sessionId, streamSid }),
|
|
35748
35893
|
sentEvents: sentEvents.map((message) => message.event).filter((event) => typeof event === "string"),
|
|
35749
35894
|
sessionId,
|
|
35750
35895
|
streamSid,
|
|
@@ -36068,6 +36213,7 @@ export {
|
|
|
36068
36213
|
renderVoiceLatencySLOMarkdown,
|
|
36069
36214
|
renderVoiceHandoffHealthHTML,
|
|
36070
36215
|
renderVoiceGuardrailMarkdown,
|
|
36216
|
+
renderVoiceFailureReplayMarkdown,
|
|
36071
36217
|
renderVoiceEvalHTML,
|
|
36072
36218
|
renderVoiceEvalBaselineHTML,
|
|
36073
36219
|
renderVoiceDemoReadyHTML,
|
|
@@ -36507,6 +36653,7 @@ export {
|
|
|
36507
36653
|
buildVoiceLatencySLOGate,
|
|
36508
36654
|
buildVoiceIncidentBundle,
|
|
36509
36655
|
buildVoiceGuardrailReport,
|
|
36656
|
+
buildVoiceFailureReplay,
|
|
36510
36657
|
buildVoiceDiagnosticsMarkdown,
|
|
36511
36658
|
buildVoiceDemoReadyReport,
|
|
36512
36659
|
buildVoiceDeliverySinkReport,
|
|
@@ -217,6 +217,75 @@ export type VoiceOperationsRecord = {
|
|
|
217
217
|
traceEvents: StoredVoiceTraceEvent[];
|
|
218
218
|
transcript: VoiceOperationsRecordTranscriptTurn[];
|
|
219
219
|
};
|
|
220
|
+
export type VoiceFailureReplayStatus = 'degraded' | 'failed' | 'healthy' | 'recovered';
|
|
221
|
+
export type VoiceFailureReplayProviderStep = {
|
|
222
|
+
at: number;
|
|
223
|
+
elapsedMs?: number;
|
|
224
|
+
error?: string;
|
|
225
|
+
fallbackProvider?: string;
|
|
226
|
+
kind?: string;
|
|
227
|
+
provider?: string;
|
|
228
|
+
reason?: string;
|
|
229
|
+
selectedProvider?: string;
|
|
230
|
+
status?: string;
|
|
231
|
+
surface?: string;
|
|
232
|
+
turnId?: string;
|
|
233
|
+
userHeard: string[];
|
|
234
|
+
};
|
|
235
|
+
export type VoiceFailureReplayMediaStep = {
|
|
236
|
+
at: number;
|
|
237
|
+
audioBytes: number;
|
|
238
|
+
carrier?: string;
|
|
239
|
+
direction?: string;
|
|
240
|
+
event: string;
|
|
241
|
+
issue?: string;
|
|
242
|
+
streamId?: string;
|
|
243
|
+
};
|
|
244
|
+
export type VoiceFailureReplayTurn = {
|
|
245
|
+
assistantReplies: string[];
|
|
246
|
+
committedText?: string;
|
|
247
|
+
errors: string[];
|
|
248
|
+
id: string;
|
|
249
|
+
media: VoiceFailureReplayMediaStep[];
|
|
250
|
+
providers: VoiceFailureReplayProviderStep[];
|
|
251
|
+
transcripts: string[];
|
|
252
|
+
};
|
|
253
|
+
export type VoiceFailureReplayReport = {
|
|
254
|
+
incidentMarkdown: string;
|
|
255
|
+
media: {
|
|
256
|
+
audioBytes: number;
|
|
257
|
+
clears: number;
|
|
258
|
+
errors: number;
|
|
259
|
+
issues: string[];
|
|
260
|
+
steps: VoiceFailureReplayMediaStep[];
|
|
261
|
+
total: number;
|
|
262
|
+
};
|
|
263
|
+
ok: boolean;
|
|
264
|
+
operationsRecordHref?: string;
|
|
265
|
+
providers: {
|
|
266
|
+
degraded: number;
|
|
267
|
+
errors: number;
|
|
268
|
+
fallbacks: number;
|
|
269
|
+
recoveryStatus: VoiceOperationsRecordProviderDecisionRecoveryStatus;
|
|
270
|
+
selected: number;
|
|
271
|
+
steps: VoiceFailureReplayProviderStep[];
|
|
272
|
+
total: number;
|
|
273
|
+
};
|
|
274
|
+
sessionId: string;
|
|
275
|
+
status: VoiceFailureReplayStatus;
|
|
276
|
+
summary: {
|
|
277
|
+
callDurationMs?: number;
|
|
278
|
+
issues: string[];
|
|
279
|
+
userHeard: string[];
|
|
280
|
+
};
|
|
281
|
+
turns: VoiceFailureReplayTurn[];
|
|
282
|
+
};
|
|
283
|
+
export type VoiceFailureReplayOptions = {
|
|
284
|
+
operationsRecordHref?: string | ((input: {
|
|
285
|
+
record: VoiceOperationsRecord;
|
|
286
|
+
sessionId: string;
|
|
287
|
+
}) => string);
|
|
288
|
+
};
|
|
220
289
|
export type VoiceOperationsRecordOptions = {
|
|
221
290
|
audit?: VoiceAuditEventStore;
|
|
222
291
|
evaluation?: VoiceTraceEvaluationOptions;
|
|
@@ -244,6 +313,8 @@ export declare const evaluateVoiceOperationsRecordGuardrails: (record: VoiceOper
|
|
|
244
313
|
export declare const assertVoiceOperationsRecordGuardrails: (record: VoiceOperationsRecord, input?: VoiceOperationsRecordGuardrailAssertionInput) => VoiceOperationsRecordGuardrailAssertionReport;
|
|
245
314
|
export declare const evaluateVoiceOperationsRecordProviderRecovery: (record: VoiceOperationsRecord, input?: VoiceOperationsRecordProviderRecoveryAssertionInput) => VoiceOperationsRecordProviderRecoveryAssertionReport;
|
|
246
315
|
export declare const assertVoiceOperationsRecordProviderRecovery: (record: VoiceOperationsRecord, input?: VoiceOperationsRecordProviderRecoveryAssertionInput) => VoiceOperationsRecordProviderRecoveryAssertionReport;
|
|
316
|
+
export declare const buildVoiceFailureReplay: (record: VoiceOperationsRecord, options?: VoiceFailureReplayOptions) => VoiceFailureReplayReport;
|
|
317
|
+
export declare const renderVoiceFailureReplayMarkdown: (report: Omit<VoiceFailureReplayReport, "incidentMarkdown"> | VoiceFailureReplayReport) => string;
|
|
247
318
|
export declare const renderVoiceOperationsRecordIncidentMarkdown: (record: VoiceOperationsRecord) => string;
|
|
248
319
|
export declare const renderVoiceOperationsRecordGuardrailMarkdown: (record: VoiceOperationsRecord) => string;
|
|
249
320
|
export declare const renderVoiceOperationsRecordHTML: (record: VoiceOperationsRecord, options?: {
|
package/dist/testing/index.js
CHANGED
|
@@ -10780,6 +10780,7 @@ var pushMissingValuesIssue = (input) => {
|
|
|
10780
10780
|
}
|
|
10781
10781
|
};
|
|
10782
10782
|
var resolveRoutePath = (path, sessionId) => path.replace(":sessionId", encodeURIComponent(sessionId));
|
|
10783
|
+
var resolveOperationsRecordHref = (href, record) => typeof href === "function" ? href({ record, sessionId: record.sessionId }) : href;
|
|
10783
10784
|
var toHandoff = (event) => ({
|
|
10784
10785
|
at: event.at,
|
|
10785
10786
|
fromAgentId: getString4(event.payload.fromAgentId),
|
|
@@ -11194,6 +11195,150 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
11194
11195
|
}
|
|
11195
11196
|
return report;
|
|
11196
11197
|
};
|
|
11198
|
+
var getAssistantRepliesForTurn = (record, turnId) => turnId ? record.transcript.find((turn) => turn.id === turnId)?.assistantReplies ?? [] : [];
|
|
11199
|
+
var mediaIssueForStep = (step) => {
|
|
11200
|
+
const event = step.event.toLowerCase();
|
|
11201
|
+
if (event === "error") {
|
|
11202
|
+
return "Carrier media stream emitted an error.";
|
|
11203
|
+
}
|
|
11204
|
+
if (event === "media" && step.audioBytes <= 0) {
|
|
11205
|
+
return "Carrier media packet had no audio bytes.";
|
|
11206
|
+
}
|
|
11207
|
+
return;
|
|
11208
|
+
};
|
|
11209
|
+
var buildVoiceFailureReplay = (record, options = {}) => {
|
|
11210
|
+
const providerSteps = record.providerDecisions.filter((decision) => ["degraded", "error", "fallback", "selected", "success"].includes(decision.status ?? "")).map((decision) => ({
|
|
11211
|
+
at: decision.at,
|
|
11212
|
+
elapsedMs: decision.elapsedMs,
|
|
11213
|
+
error: decision.error,
|
|
11214
|
+
fallbackProvider: decision.fallbackProvider,
|
|
11215
|
+
kind: decision.kind,
|
|
11216
|
+
provider: decision.provider,
|
|
11217
|
+
reason: decision.reason,
|
|
11218
|
+
selectedProvider: decision.selectedProvider,
|
|
11219
|
+
status: decision.status,
|
|
11220
|
+
surface: decision.surface,
|
|
11221
|
+
turnId: decision.turnId,
|
|
11222
|
+
userHeard: getAssistantRepliesForTurn(record, decision.turnId)
|
|
11223
|
+
}));
|
|
11224
|
+
const mediaSteps = record.telephonyMedia.events.map((event) => {
|
|
11225
|
+
const step = {
|
|
11226
|
+
at: event.at,
|
|
11227
|
+
audioBytes: event.audioBytes,
|
|
11228
|
+
carrier: event.carrier,
|
|
11229
|
+
direction: event.direction,
|
|
11230
|
+
event: event.event,
|
|
11231
|
+
streamId: event.streamId
|
|
11232
|
+
};
|
|
11233
|
+
return {
|
|
11234
|
+
...step,
|
|
11235
|
+
issue: mediaIssueForStep(step)
|
|
11236
|
+
};
|
|
11237
|
+
});
|
|
11238
|
+
const providerIssues = providerSteps.filter((step) => step.status === "error" || step.status === "fallback" || step.status === "degraded").map((step) => {
|
|
11239
|
+
const provider = step.provider ?? step.selectedProvider ?? "provider";
|
|
11240
|
+
const recovery = step.status === "fallback" ? `recovered through ${step.fallbackProvider ?? step.selectedProvider ?? "fallback"}` : step.status === "degraded" ? `degraded to ${step.fallbackProvider ?? step.selectedProvider ?? "fallback"}` : "failed before recovery";
|
|
11241
|
+
return `${provider} ${recovery}${step.reason ? `: ${step.reason}` : ""}`;
|
|
11242
|
+
});
|
|
11243
|
+
const mediaIssues = [
|
|
11244
|
+
...mediaSteps.map((step) => step.issue).filter((issue) => typeof issue === "string"),
|
|
11245
|
+
record.telephonyMedia.total > 0 && record.telephonyMedia.inbound === 0 ? "Carrier stream has no inbound media evidence." : undefined,
|
|
11246
|
+
record.telephonyMedia.total > 0 && record.telephonyMedia.outbound === 0 ? "Carrier stream has no outbound assistant media/control evidence." : undefined
|
|
11247
|
+
].filter((issue) => typeof issue === "string");
|
|
11248
|
+
const userHeard = [
|
|
11249
|
+
...new Set(record.transcript.flatMap((turn) => turn.assistantReplies))
|
|
11250
|
+
];
|
|
11251
|
+
const status = record.providerDecisionSummary.errors > 0 || record.telephonyMedia.errors > 0 ? "failed" : record.providerDecisionSummary.degraded > 0 ? "degraded" : record.providerDecisionSummary.fallbacks > 0 || mediaIssues.length > 0 ? "recovered" : "healthy";
|
|
11252
|
+
const turns = record.transcript.map((turn) => ({
|
|
11253
|
+
...turn,
|
|
11254
|
+
media: mediaSteps.filter((step) => record.traceEvents.some((event) => event.turnId === turn.id && event.type === "client.telephony_media" && event.at === step.at)),
|
|
11255
|
+
providers: providerSteps.filter((step) => step.turnId === turn.id)
|
|
11256
|
+
}));
|
|
11257
|
+
const issues = [...providerIssues, ...mediaIssues];
|
|
11258
|
+
const reportBase = {
|
|
11259
|
+
media: {
|
|
11260
|
+
audioBytes: record.telephonyMedia.audioBytes,
|
|
11261
|
+
clears: record.telephonyMedia.clears,
|
|
11262
|
+
errors: record.telephonyMedia.errors,
|
|
11263
|
+
issues: mediaIssues,
|
|
11264
|
+
steps: mediaSteps,
|
|
11265
|
+
total: record.telephonyMedia.total
|
|
11266
|
+
},
|
|
11267
|
+
ok: status === "healthy" || status === "recovered",
|
|
11268
|
+
operationsRecordHref: resolveOperationsRecordHref(options.operationsRecordHref, record),
|
|
11269
|
+
providers: {
|
|
11270
|
+
degraded: record.providerDecisionSummary.degraded,
|
|
11271
|
+
errors: record.providerDecisionSummary.errors,
|
|
11272
|
+
fallbacks: record.providerDecisionSummary.fallbacks,
|
|
11273
|
+
recoveryStatus: record.providerDecisionSummary.recoveryStatus,
|
|
11274
|
+
selected: record.providerDecisionSummary.selected,
|
|
11275
|
+
steps: providerSteps,
|
|
11276
|
+
total: record.providerDecisionSummary.total
|
|
11277
|
+
},
|
|
11278
|
+
sessionId: record.sessionId,
|
|
11279
|
+
status,
|
|
11280
|
+
summary: {
|
|
11281
|
+
callDurationMs: record.summary.callDurationMs,
|
|
11282
|
+
issues,
|
|
11283
|
+
userHeard
|
|
11284
|
+
},
|
|
11285
|
+
turns
|
|
11286
|
+
};
|
|
11287
|
+
return {
|
|
11288
|
+
...reportBase,
|
|
11289
|
+
incidentMarkdown: renderVoiceFailureReplayMarkdown(reportBase)
|
|
11290
|
+
};
|
|
11291
|
+
};
|
|
11292
|
+
var renderVoiceFailureReplayMarkdown = (report) => {
|
|
11293
|
+
const heard = report.summary.userHeard.length ? report.summary.userHeard.map((text) => `- ${text}`).join(`
|
|
11294
|
+
`) : "- none recorded";
|
|
11295
|
+
const providerSteps = report.providers.steps.length ? report.providers.steps.slice(0, 8).map((step) => {
|
|
11296
|
+
const provider = step.provider ?? step.selectedProvider ?? "provider";
|
|
11297
|
+
const parts = [
|
|
11298
|
+
step.status ? `status=${step.status}` : undefined,
|
|
11299
|
+
step.selectedProvider ? `selected=${step.selectedProvider}` : undefined,
|
|
11300
|
+
step.fallbackProvider ? `fallback=${step.fallbackProvider}` : undefined,
|
|
11301
|
+
step.elapsedMs !== undefined ? `elapsed=${step.elapsedMs}ms` : undefined,
|
|
11302
|
+
step.reason
|
|
11303
|
+
].filter((part) => typeof part === "string");
|
|
11304
|
+
return `- ${provider}: ${parts.join("; ")}`;
|
|
11305
|
+
}).join(`
|
|
11306
|
+
`) : "- none recorded";
|
|
11307
|
+
const mediaSteps = report.media.steps.length ? report.media.steps.slice(0, 8).map((step) => {
|
|
11308
|
+
const parts = [
|
|
11309
|
+
step.carrier,
|
|
11310
|
+
step.event,
|
|
11311
|
+
step.direction,
|
|
11312
|
+
step.streamId ? `stream=${step.streamId}` : undefined,
|
|
11313
|
+
`audioBytes=${String(step.audioBytes)}`,
|
|
11314
|
+
step.issue
|
|
11315
|
+
].filter((part) => typeof part === "string");
|
|
11316
|
+
return `- ${parts.join("; ")}`;
|
|
11317
|
+
}).join(`
|
|
11318
|
+
`) : "- none recorded";
|
|
11319
|
+
const issues = report.summary.issues.length ? report.summary.issues.map((issue) => `- ${issue}`).join(`
|
|
11320
|
+
`) : "- none";
|
|
11321
|
+
return [
|
|
11322
|
+
`# Voice Failure Replay: ${report.sessionId}`,
|
|
11323
|
+
"",
|
|
11324
|
+
`Status: ${report.status}`,
|
|
11325
|
+
`Operations record: ${report.operationsRecordHref ?? "not linked"}`,
|
|
11326
|
+
`Duration: ${formatMs2(report.summary.callDurationMs)}`,
|
|
11327
|
+
"",
|
|
11328
|
+
"## What Failed Or Recovered",
|
|
11329
|
+
issues,
|
|
11330
|
+
"",
|
|
11331
|
+
"## Provider Path",
|
|
11332
|
+
providerSteps,
|
|
11333
|
+
"",
|
|
11334
|
+
"## Media Path",
|
|
11335
|
+
mediaSteps,
|
|
11336
|
+
"",
|
|
11337
|
+
"## What The User Heard",
|
|
11338
|
+
heard
|
|
11339
|
+
].join(`
|
|
11340
|
+
`);
|
|
11341
|
+
};
|
|
11197
11342
|
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11198
11343
|
var formatMs2 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
11199
11344
|
var outcomeLabels = (outcome) => [
|
|
@@ -13130,7 +13275,7 @@ var createFakeTTSAdapter = (chunkCount, chunkDelayMs) => ({
|
|
|
13130
13275
|
var defaultOperationsRecordHref = ({
|
|
13131
13276
|
sessionId
|
|
13132
13277
|
}) => `/voice-operations/${encodeURIComponent(sessionId)}`;
|
|
13133
|
-
var
|
|
13278
|
+
var resolveOperationsRecordHref2 = (href, input) => typeof href === "function" ? href(input) : href === undefined ? defaultOperationsRecordHref(input) : href;
|
|
13134
13279
|
var runVoiceTelephonyMediaOperationsSmoke = async (options = {}) => {
|
|
13135
13280
|
const timeoutMs = options.timeoutMs ?? 5000;
|
|
13136
13281
|
const sessionId = options.sessionId ?? `telephony-media-ops-${Date.now()}`;
|
|
@@ -13218,7 +13363,7 @@ var runVoiceTelephonyMediaOperationsSmoke = async (options = {}) => {
|
|
|
13218
13363
|
issues,
|
|
13219
13364
|
ok: issues.length === 0,
|
|
13220
13365
|
operationsRecord,
|
|
13221
|
-
operationsRecordHref:
|
|
13366
|
+
operationsRecordHref: resolveOperationsRecordHref2(options.operationsRecordHref, { sessionId, streamSid }),
|
|
13222
13367
|
sentEvents: sentEvents.map((message) => message.event).filter((event) => typeof event === "string"),
|
|
13223
13368
|
sessionId,
|
|
13224
13369
|
streamSid,
|