@absolutejs/voice 0.0.22-beta.247 → 0.0.22-beta.248
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/README.md +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +70 -1
- package/dist/operationsRecord.d.ts +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2792,7 +2792,7 @@ app.use(
|
|
|
2792
2792
|
);
|
|
2793
2793
|
```
|
|
2794
2794
|
|
|
2795
|
-
`createVoiceOperationsRecordRoutes(...)` links the call/session timeline, transcript, replay, provider decisions, tools, handoffs, audit, reviews, ops tasks, integration events, and sink delivery attempts into one debuggable object. Use `/voice-operations/:sessionId` as the first place to investigate failed calls, provider failures, handoff failures, slow turns, and campaign attempts. The same mount also exposes incident handoff Markdown at `/voice-operations/:sessionId/incident.md` and `/api/voice-operations/:sessionId/incident.md` for support tooling.
|
|
2795
|
+
`createVoiceOperationsRecordRoutes(...)` links the call/session timeline, transcript, replay, provider decisions, tools, handoffs, guardrail decisions, audit, reviews, ops tasks, integration events, and sink delivery attempts into one debuggable object. Use `/voice-operations/:sessionId` as the first place to investigate failed calls, blocked assistant output, blocked tool payloads, provider failures, handoff failures, slow turns, and campaign attempts. The same mount also exposes incident handoff Markdown at `/voice-operations/:sessionId/incident.md` and `/api/voice-operations/:sessionId/incident.md` for support tooling, including an `assistant.guardrail` blocked-stage summary when guardrail trace events exist.
|
|
2796
2796
|
|
|
2797
2797
|
Most proof surfaces can link to the same record by passing an operations-record URL template such as `/voice-operations/:sessionId`. Use that template anywhere a report emits session-level failures: production readiness, ops recovery, trace timelines, session lists, reviews, campaign attempts, eval reports, simulation-suite actions, tool-contract cases, and outcome-contract matched sessions. The goal is that no operator has to guess which trace, review, task, or delivery queue belongs to the failing call.
|
|
2798
2798
|
|
package/dist/index.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export { buildVoiceProductionReadinessGate, buildVoiceProductionReadinessReport,
|
|
|
56
56
|
export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './readinessProfiles';
|
|
57
57
|
export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
|
|
58
58
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
59
|
-
export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown } from './operationsRecord';
|
|
59
|
+
export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordGuardrailMarkdown, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown } from './operationsRecord';
|
|
60
60
|
export { assertVoiceObservabilityExportRecord, buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExportDeliveryHistory, buildVoiceObservabilityExportReplayReport, buildVoiceObservabilityExport, assertVoiceObservabilityExportSchema, createVoiceObservabilityExportSchema, createVoiceFileObservabilityExportDeliveryReceiptStore, createVoiceMemoryObservabilityExportDeliveryReceiptStore, createVoiceObservabilityExportRoutes, createVoiceObservabilityExportReplayRoutes, deliverVoiceObservabilityExport, loadVoiceObservabilityExportReplaySource, replayVoiceObservabilityExport, renderVoiceObservabilityExportReplayHTML, renderVoiceObservabilityExportMarkdown, validateVoiceObservabilityExportRecord, voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVersion } from './observabilityExport';
|
|
61
61
|
export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown } from './opsRecovery';
|
|
62
62
|
export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
|
|
@@ -123,7 +123,7 @@ export type { VoiceOpsStatus, VoiceOpsStatusLink, VoiceOpsStatusOptions, VoiceOp
|
|
|
123
123
|
export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptions, VoiceProductionReadinessAuditRequirement, VoiceProductionReadinessAuditSummary, VoiceProductionReadinessCheck, VoiceProductionReadinessGateIssue, VoiceProductionReadinessGateOptions, VoiceProductionReadinessGateProfile, VoiceProductionReadinessGateProfileSurface, VoiceProductionReadinessGateReport, VoiceProductionReadinessOpsActionHistoryOptions, VoiceProductionReadinessOpsActionHistorySummary, VoiceProductionReadinessOperationsRecordLink, VoiceProductionReadinessOperationsRecordLinks, VoiceProductionReadinessProfileExplanation, VoiceProductionReadinessProfileSurface, VoiceProductionReadinessProofSource, VoiceProductionReadinessReport, VoiceProductionReadinessRoutesOptions, VoiceProductionReadinessTraceDeliverySummary, VoiceProductionReadinessAuditDeliveryOptions, VoiceProductionReadinessAuditDeliverySummary, VoiceProductionReadinessTraceDeliveryOptions, VoiceProductionReadinessStatus } from './productionReadiness';
|
|
124
124
|
export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
|
|
125
125
|
export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
|
|
126
|
-
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
|
|
126
|
+
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordGuardrailDecision, VoiceOperationsRecordGuardrailFinding, VoiceOperationsRecordGuardrailSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
|
|
127
127
|
export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryHistory, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReceipt, VoiceObservabilityExportDeliveryReceiptStore, VoiceObservabilityExportDeliveryReport, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportIngestedRecordKind, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportRecordValidationOptions, VoiceObservabilityExportReplayIssue, VoiceObservabilityExportReplayIssueCode, VoiceObservabilityExportReplayRecords, VoiceObservabilityExportReplayReport, VoiceObservabilityExportReplayRoutesOptions, VoiceObservabilityExportReplaySource, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportSchema, VoiceObservabilityExportStatus, VoiceObservabilityExportValidationIssue, VoiceObservabilityExportValidationResult } from './observabilityExport';
|
|
128
128
|
export type { VoiceOpsRecoveryFailedSession, VoiceOpsRecoveryInterventionSummary, VoiceOpsRecoveryIssue, VoiceOpsRecoveryIssueCode, VoiceOpsRecoveryLinks, VoiceOpsRecoveryProviderSummary, VoiceOpsRecoveryReport, VoiceOpsRecoveryReportOptions, VoiceOpsRecoveryRoutesOptions, VoiceOpsRecoveryStatus } from './opsRecovery';
|
|
129
129
|
export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
|
package/dist/index.js
CHANGED
|
@@ -22872,6 +22872,7 @@ var createVoiceTraceTimelineRoutes = (options) => {
|
|
|
22872
22872
|
// src/operationsRecord.ts
|
|
22873
22873
|
var getString16 = (value) => typeof value === "string" ? value : undefined;
|
|
22874
22874
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
22875
|
+
var getBoolean3 = (value) => typeof value === "boolean" ? value : undefined;
|
|
22875
22876
|
var countOutcome = (events, outcome) => events.filter((event) => event.outcome === outcome).length;
|
|
22876
22877
|
var matchesSessionScopedId = (id, sessionId) => id === sessionId || id.startsWith(`${sessionId}:`);
|
|
22877
22878
|
var hasPayloadValue = (payload, key, values) => {
|
|
@@ -22899,6 +22900,44 @@ var toTool = (event) => ({
|
|
|
22899
22900
|
toolName: getString16(event.payload.toolName),
|
|
22900
22901
|
turnId: event.turnId
|
|
22901
22902
|
});
|
|
22903
|
+
var toGuardrailFinding = (value) => {
|
|
22904
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
22905
|
+
return;
|
|
22906
|
+
}
|
|
22907
|
+
const record = value;
|
|
22908
|
+
return {
|
|
22909
|
+
action: getString16(record.action),
|
|
22910
|
+
label: getString16(record.label),
|
|
22911
|
+
ruleId: getString16(record.ruleId)
|
|
22912
|
+
};
|
|
22913
|
+
};
|
|
22914
|
+
var toGuardrailDecision = (event) => ({
|
|
22915
|
+
allowed: getBoolean3(event.payload.allowed),
|
|
22916
|
+
at: event.at,
|
|
22917
|
+
findings: Array.isArray(event.payload.findings) ? event.payload.findings.map(toGuardrailFinding).filter((finding) => finding !== undefined) : [],
|
|
22918
|
+
metadata: event.metadata && typeof event.metadata === "object" && !Array.isArray(event.metadata) ? event.metadata : undefined,
|
|
22919
|
+
proof: getString16(event.metadata?.proof),
|
|
22920
|
+
stage: getString16(event.payload.stage),
|
|
22921
|
+
status: getString16(event.payload.status),
|
|
22922
|
+
toolName: getString16(event.payload.toolName),
|
|
22923
|
+
turnId: event.turnId
|
|
22924
|
+
});
|
|
22925
|
+
var summarizeGuardrails = (events) => {
|
|
22926
|
+
const decisions = events.filter((event) => event.type === "assistant.guardrail").map(toGuardrailDecision);
|
|
22927
|
+
const isBlocked = (decision) => decision.allowed === false || decision.status === "fail";
|
|
22928
|
+
const isWarned = (decision) => decision.status === "warn" || decision.findings.some((finding) => finding.action === "warn");
|
|
22929
|
+
const stages = [
|
|
22930
|
+
...new Set(decisions.map((decision) => decision.stage).filter((stage) => typeof stage === "string"))
|
|
22931
|
+
].sort();
|
|
22932
|
+
return {
|
|
22933
|
+
blocked: decisions.filter(isBlocked).length,
|
|
22934
|
+
decisions,
|
|
22935
|
+
passed: decisions.filter((decision) => !isBlocked(decision) && !isWarned(decision)).length,
|
|
22936
|
+
stages,
|
|
22937
|
+
total: decisions.length,
|
|
22938
|
+
warned: decisions.filter(isWarned).length
|
|
22939
|
+
};
|
|
22940
|
+
};
|
|
22902
22941
|
var toProviderDecision = (event) => {
|
|
22903
22942
|
const provider = getString16(event.payload.provider) ?? getString16(event.payload.selectedProvider) ?? getString16(event.payload.fallbackProvider) ?? getString16(event.payload.variantId);
|
|
22904
22943
|
const status = getString16(event.payload.providerStatus) ?? getString16(event.payload.status) ?? getString16(event.payload.reason);
|
|
@@ -22971,6 +23010,7 @@ var buildVoiceOperationsRecord = async (options) => {
|
|
|
22971
23010
|
total: auditEvents.length
|
|
22972
23011
|
} : undefined,
|
|
22973
23012
|
checkedAt: Date.now(),
|
|
23013
|
+
guardrails: summarizeGuardrails(traceEvents),
|
|
22974
23014
|
handoffs: traceEvents.filter((event) => event.type === "agent.handoff").map(toHandoff),
|
|
22975
23015
|
integrationEvents: integrationEvents ? {
|
|
22976
23016
|
delivered: countIntegrationDeliveryStatus(integrationEvents, "delivered"),
|
|
@@ -23031,6 +23071,9 @@ var renderVoiceOperationsRecordIncidentMarkdown = (record) => {
|
|
|
23031
23071
|
`- Providers: ${record.providers.map((provider) => provider.provider).join(", ") || "none recorded"}`,
|
|
23032
23072
|
`- Open tasks: ${openTasks.join("; ") || "none"}`,
|
|
23033
23073
|
`- Top errors: ${topErrors.join("; ") || "none"}`,
|
|
23074
|
+
`- Guardrails: ${String(record.guardrails.blocked)} blocked / ${String(record.guardrails.warned)} warned / ${String(record.guardrails.total)} decisions`,
|
|
23075
|
+
"",
|
|
23076
|
+
renderVoiceOperationsRecordGuardrailMarkdown(record),
|
|
23034
23077
|
"",
|
|
23035
23078
|
"## Next checks",
|
|
23036
23079
|
"- Review provider decisions and fallback status.",
|
|
@@ -23039,6 +23082,25 @@ var renderVoiceOperationsRecordIncidentMarkdown = (record) => {
|
|
|
23039
23082
|
].join(`
|
|
23040
23083
|
`);
|
|
23041
23084
|
};
|
|
23085
|
+
var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
23086
|
+
if (record.guardrails.total === 0) {
|
|
23087
|
+
return [
|
|
23088
|
+
"## Guardrail evidence",
|
|
23089
|
+
"",
|
|
23090
|
+
"- No assistant.guardrail events were recorded for this session."
|
|
23091
|
+
].join(`
|
|
23092
|
+
`);
|
|
23093
|
+
}
|
|
23094
|
+
return [
|
|
23095
|
+
"## Guardrail evidence",
|
|
23096
|
+
"",
|
|
23097
|
+
...record.guardrails.decisions.map((decision) => {
|
|
23098
|
+
const findings = decision.findings.map((finding) => [finding.action, finding.ruleId, finding.label].filter((value) => typeof value === "string").join(":")).filter(Boolean).join(", ");
|
|
23099
|
+
return `- assistant.guardrail ${decision.stage ?? "unknown"}: ${decision.status ?? "unknown"}; allowed=${String(decision.allowed ?? "unknown")}; proof=${decision.proof ?? "runtime"}; findings=${findings || "none"}`;
|
|
23100
|
+
})
|
|
23101
|
+
].join(`
|
|
23102
|
+
`);
|
|
23103
|
+
};
|
|
23042
23104
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
23043
23105
|
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml39(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs4(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
23044
23106
|
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml39(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml39(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml39(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml39(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
@@ -23048,6 +23110,10 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
23048
23110
|
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml39(review.title)}</strong> <span>${escapeHtml39(review.summary.outcome ?? "")}</span><p>${escapeHtml39(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
23049
23111
|
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml39(task.title)}</strong> <span>${escapeHtml39(task.status)}</span><p>${escapeHtml39(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
23050
23112
|
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml39(event.type)}</strong> <span>${escapeHtml39(event.deliveryStatus ?? "local")}</span><p>${escapeHtml39(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
23113
|
+
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
23114
|
+
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
23115
|
+
return `<li><strong>assistant.guardrail ${escapeHtml39(decision.stage ?? "unknown")}</strong> <span>${escapeHtml39(decision.status ?? "")}</span><p>Allowed: ${escapeHtml39(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml39(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml39(decision.turnId)}` : ""}</p><p>${escapeHtml39(findings)}</p></li>`;
|
|
23116
|
+
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
23051
23117
|
const snippet = escapeHtml39(`app.use(
|
|
23052
23118
|
createVoiceOperationsRecordRoutes({
|
|
23053
23119
|
audit: auditStore,
|
|
@@ -23064,7 +23130,7 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
23064
23130
|
);`);
|
|
23065
23131
|
const incidentMarkdown = escapeHtml39(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
23066
23132
|
const incidentLink = options.incidentHref ? `<a href="${escapeHtml39(options.incidentHref)}">Download incident.md</a>` : "";
|
|
23067
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;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 #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml39(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml39(record.status)}">${escapeHtml39(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs4(record.summary.callDurationMs)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
|
|
23133
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;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 #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml39(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml39(record.status)}">${escapeHtml39(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs4(record.summary.callDurationMs)}</strong></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
|
|
23068
23134
|
};
|
|
23069
23135
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
23070
23136
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -26686,6 +26752,8 @@ var renderIncidentMarkdown = (input) => {
|
|
|
26686
26752
|
"",
|
|
26687
26753
|
...input.record.tools.length ? input.record.tools.map((tool) => `- ${tool.toolName ?? "tool"} ${tool.status ?? ""} ${tool.elapsedMs === undefined ? "" : `${tool.elapsedMs}ms`} ${tool.error ?? ""}`.trim()) : ["- none"],
|
|
26688
26754
|
"",
|
|
26755
|
+
renderVoiceOperationsRecordGuardrailMarkdown(input.record),
|
|
26756
|
+
"",
|
|
26689
26757
|
"## Trace Evidence",
|
|
26690
26758
|
"",
|
|
26691
26759
|
input.traceMarkdown,
|
|
@@ -29771,6 +29839,7 @@ export {
|
|
|
29771
29839
|
renderVoiceOpsActionHistoryHTML,
|
|
29772
29840
|
renderVoiceOperationsRecordIncidentMarkdown,
|
|
29773
29841
|
renderVoiceOperationsRecordHTML,
|
|
29842
|
+
renderVoiceOperationsRecordGuardrailMarkdown,
|
|
29774
29843
|
renderVoiceObservabilityExportReplayHTML,
|
|
29775
29844
|
renderVoiceObservabilityExportMarkdown,
|
|
29776
29845
|
renderVoiceLiveLatencyHTML,
|
|
@@ -81,9 +81,34 @@ export type VoiceOperationsRecordIntegrationEventSummary = {
|
|
|
81
81
|
skipped: number;
|
|
82
82
|
total: number;
|
|
83
83
|
};
|
|
84
|
+
export type VoiceOperationsRecordGuardrailFinding = {
|
|
85
|
+
action?: string;
|
|
86
|
+
label?: string;
|
|
87
|
+
ruleId?: string;
|
|
88
|
+
};
|
|
89
|
+
export type VoiceOperationsRecordGuardrailDecision = {
|
|
90
|
+
allowed?: boolean;
|
|
91
|
+
at: number;
|
|
92
|
+
findings: VoiceOperationsRecordGuardrailFinding[];
|
|
93
|
+
metadata?: Record<string, unknown>;
|
|
94
|
+
proof?: string;
|
|
95
|
+
stage?: string;
|
|
96
|
+
status?: string;
|
|
97
|
+
toolName?: string;
|
|
98
|
+
turnId?: string;
|
|
99
|
+
};
|
|
100
|
+
export type VoiceOperationsRecordGuardrailSummary = {
|
|
101
|
+
blocked: number;
|
|
102
|
+
decisions: VoiceOperationsRecordGuardrailDecision[];
|
|
103
|
+
passed: number;
|
|
104
|
+
stages: string[];
|
|
105
|
+
total: number;
|
|
106
|
+
warned: number;
|
|
107
|
+
};
|
|
84
108
|
export type VoiceOperationsRecord = {
|
|
85
109
|
audit?: VoiceOperationsRecordAuditSummary;
|
|
86
110
|
checkedAt: number;
|
|
111
|
+
guardrails: VoiceOperationsRecordGuardrailSummary;
|
|
87
112
|
handoffs: VoiceOperationsRecordAgentHandoff[];
|
|
88
113
|
integrationEvents?: VoiceOperationsRecordIntegrationEventSummary;
|
|
89
114
|
outcome: VoiceOperationsRecordOutcome;
|
|
@@ -124,6 +149,7 @@ export type VoiceOperationsRecordRoutesOptions = Omit<VoiceOperationsRecordOptio
|
|
|
124
149
|
};
|
|
125
150
|
export declare const buildVoiceOperationsRecord: (options: VoiceOperationsRecordOptions) => Promise<VoiceOperationsRecord>;
|
|
126
151
|
export declare const renderVoiceOperationsRecordIncidentMarkdown: (record: VoiceOperationsRecord) => string;
|
|
152
|
+
export declare const renderVoiceOperationsRecordGuardrailMarkdown: (record: VoiceOperationsRecord) => string;
|
|
127
153
|
export declare const renderVoiceOperationsRecordHTML: (record: VoiceOperationsRecord, options?: {
|
|
128
154
|
incidentHref?: string;
|
|
129
155
|
title?: string;
|