@absolutejs/voice 0.0.22-beta.528 → 0.0.22-beta.529
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/angular/index.js +3 -1
- package/dist/client/htmxBootstrap.js +3 -1
- package/dist/client/index.js +290 -304
- package/dist/embed/index.js +3 -1
- package/dist/embed/voice-widget.js +7 -7
- package/dist/index.d.ts +4 -6
- package/dist/index.js +513 -892
- package/dist/internal/html.d.ts +6 -0
- package/dist/internal/status.d.ts +9 -0
- package/dist/react/index.js +287 -300
- package/dist/svelte/index.js +181 -198
- package/dist/testing/index.js +57 -62
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/index.js +231 -239
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -251,6 +251,9 @@ var conditionAudioChunk = (audio, config) => {
|
|
|
251
251
|
import { Elysia as Elysia70 } from "elysia";
|
|
252
252
|
import { resolve } from "path";
|
|
253
253
|
|
|
254
|
+
// src/internal/html.ts
|
|
255
|
+
var escapeHtml = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
256
|
+
|
|
254
257
|
// src/htmx.ts
|
|
255
258
|
var DEFAULT_HTMX_TARGETS = {
|
|
256
259
|
assistant: "voice-htmx-assistant",
|
|
@@ -259,7 +262,6 @@ var DEFAULT_HTMX_TARGETS = {
|
|
|
259
262
|
status: "voice-htmx-status",
|
|
260
263
|
turns: "voice-htmx-turns"
|
|
261
264
|
};
|
|
262
|
-
var escapeHtml = (text) => text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
263
265
|
var stringifyResult = (result) => {
|
|
264
266
|
if (result === undefined) {
|
|
265
267
|
return "";
|
|
@@ -2724,10 +2726,9 @@ var renderVoiceCallReviewMarkdown = (artifact) => {
|
|
|
2724
2726
|
].filter((value) => typeof value === "string").join(`
|
|
2725
2727
|
`);
|
|
2726
2728
|
};
|
|
2727
|
-
var escapeHtml2 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2728
2729
|
var renderVoiceCallReviewHTML = (artifact) => {
|
|
2729
|
-
const notes = artifact.notes.map((note) => `<li>${
|
|
2730
|
-
const latency = artifact.latencyBreakdown.map((entry) => `<li><strong>${
|
|
2730
|
+
const notes = artifact.notes.map((note) => `<li>${escapeHtml(note)}</li>`).join("");
|
|
2731
|
+
const latency = artifact.latencyBreakdown.map((entry) => `<li><strong>${escapeHtml(entry.label)}:</strong> ${roundMetric(entry.valueMs)}ms</li>`).join("");
|
|
2731
2732
|
const transport = summarizeTimelineTraffic(artifact.timeline).map((summary) => {
|
|
2732
2733
|
const parts = [`${summary.count}`, "events"];
|
|
2733
2734
|
if (summary.bytes > 0) {
|
|
@@ -2736,15 +2737,15 @@ var renderVoiceCallReviewHTML = (artifact) => {
|
|
|
2736
2737
|
if ((summary.audioMs ?? 0) > 0) {
|
|
2737
2738
|
parts.push(`${roundMetric(summary.audioMs)}ms audio`);
|
|
2738
2739
|
}
|
|
2739
|
-
return `<li><strong>${
|
|
2740
|
+
return `<li><strong>${escapeHtml(summary.label)}:</strong> ${escapeHtml(parts.join(", "))}</li>`;
|
|
2740
2741
|
}).join("");
|
|
2741
|
-
const timeline = compactTimeline(artifact.timeline.filter((entry) => !isLowSignalTimelineEvent(entry))).map((line) => `<li>${
|
|
2742
|
+
const timeline = compactTimeline(artifact.timeline.filter((entry) => !isLowSignalTimelineEvent(entry))).map((line) => `<li>${escapeHtml(line.replace(/^- /u, ""))}</li>`).join("");
|
|
2742
2743
|
return `<!doctype html>
|
|
2743
2744
|
<html lang="en">
|
|
2744
2745
|
<head>
|
|
2745
2746
|
<meta charset="utf-8" />
|
|
2746
2747
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
2747
|
-
<title>${
|
|
2748
|
+
<title>${escapeHtml(artifact.title)}</title>
|
|
2748
2749
|
<style>
|
|
2749
2750
|
:root { color-scheme: dark; }
|
|
2750
2751
|
body { font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; background: #0b0d10; color: #f4f4f5; }
|
|
@@ -2763,7 +2764,7 @@ var renderVoiceCallReviewHTML = (artifact) => {
|
|
|
2763
2764
|
<body>
|
|
2764
2765
|
<main>
|
|
2765
2766
|
<section>
|
|
2766
|
-
<h1>${
|
|
2767
|
+
<h1>${escapeHtml(artifact.title)}</h1>
|
|
2767
2768
|
<div class="grid">
|
|
2768
2769
|
<div class="metric"><div class="label">Pass</div><div class="value">${artifact.summary.pass ? "yes" : "no"}</div></div>
|
|
2769
2770
|
<div class="metric"><div class="label">First Turn</div><div class="value">${artifact.summary.firstTurnLatencyMs ?? "n/a"}ms</div></div>
|
|
@@ -2774,8 +2775,8 @@ var renderVoiceCallReviewHTML = (artifact) => {
|
|
|
2774
2775
|
<section>
|
|
2775
2776
|
<h2>Transcript</h2>
|
|
2776
2777
|
<ul>
|
|
2777
|
-
<li><strong>Expected:</strong> ${
|
|
2778
|
-
<li><strong>Actual:</strong> ${
|
|
2778
|
+
<li><strong>Expected:</strong> ${escapeHtml(artifact.transcript.expected ?? "n/a")}</li>
|
|
2779
|
+
<li><strong>Actual:</strong> ${escapeHtml(artifact.transcript.actual || "n/a")}</li>
|
|
2779
2780
|
</ul>
|
|
2780
2781
|
</section>
|
|
2781
2782
|
<section>
|
|
@@ -2796,7 +2797,7 @@ var renderVoiceCallReviewHTML = (artifact) => {
|
|
|
2796
2797
|
</section>
|
|
2797
2798
|
<section>
|
|
2798
2799
|
<h2>Config</h2>
|
|
2799
|
-
<pre>${
|
|
2800
|
+
<pre>${escapeHtml(JSON.stringify(artifact.config ?? {}, null, 2))}</pre>
|
|
2800
2801
|
</section>
|
|
2801
2802
|
</main>
|
|
2802
2803
|
</body>
|
|
@@ -5954,8 +5955,7 @@ var createVoiceAuditLogger = (store) => ({
|
|
|
5954
5955
|
|
|
5955
5956
|
// src/profileSwitchRecommendation.ts
|
|
5956
5957
|
var readDefaults = (input) => ("defaults" in input) ? input.defaults : input;
|
|
5957
|
-
var
|
|
5958
|
-
var stringifyForHtml = (value) => escapeHtml3(JSON.stringify(value, null, 2) ?? "");
|
|
5958
|
+
var stringifyForHtml = (value) => escapeHtml(JSON.stringify(value, null, 2) ?? "");
|
|
5959
5959
|
var isNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
5960
5960
|
var exceeds = (observed, budget) => isNumber(observed) && isNumber(budget) && observed > budget;
|
|
5961
5961
|
var scoreProfile = (profile, observed) => {
|
|
@@ -6231,15 +6231,15 @@ var runVoiceProfileSwitchPolicyProof = async (options) => {
|
|
|
6231
6231
|
var renderVoiceProfileSwitchPolicyProofHTML = (report, options = {}) => {
|
|
6232
6232
|
const title = options.title ?? "Voice Profile Switch Policy Proof";
|
|
6233
6233
|
const rows = report.results.map((result) => `<tr>
|
|
6234
|
-
<td><strong>${
|
|
6235
|
-
<td>${
|
|
6236
|
-
<td>${
|
|
6237
|
-
<td>${
|
|
6238
|
-
<td>${
|
|
6234
|
+
<td><strong>${escapeHtml(result.label ?? result.id)}</strong><p>${escapeHtml(result.description ?? "")}</p></td>
|
|
6235
|
+
<td>${escapeHtml(result.expectedAction ?? "n/a")}</td>
|
|
6236
|
+
<td>${escapeHtml(result.decision.action)}</td>
|
|
6237
|
+
<td>${escapeHtml(result.decision.selectedProfileId ?? "none")}</td>
|
|
6238
|
+
<td>${escapeHtml(result.decision.blockedByPolicy ?? "none")}</td>
|
|
6239
6239
|
<td>${Math.round(result.decision.confidence * 100)}%</td>
|
|
6240
6240
|
<td><span class="status ${result.ok ? "pass" : "fail"}">${result.ok ? "PASS" : "FAIL"}</span></td>
|
|
6241
6241
|
</tr>`).join("");
|
|
6242
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
6242
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>:root{color-scheme:dark;background:#07110e;color:#e8fff5;font-family:ui-sans-serif,system-ui,sans-serif}body{margin:0;padding:32px;background:radial-gradient(circle at top left,rgba(45,212,191,.2),transparent 34%),#07110e}main{max-width:1120px;margin:0 auto}a{color:#67e8f9}.hero,.card{border:1px solid rgba(148,163,184,.24);border-radius:24px;background:rgba(15,23,42,.72);box-shadow:0 24px 90px rgba(0,0,0,.24);padding:24px;margin-bottom:18px}.metric-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}.metric{border:1px solid rgba(148,163,184,.2);border-radius:18px;padding:16px;background:rgba(8,47,73,.34)}.metric span{display:block;color:#9ca3af;font-size:.78rem;text-transform:uppercase;letter-spacing:.08em}.metric strong{display:block;margin-top:8px;font-size:1.6rem}table{width:100%;border-collapse:collapse;overflow:hidden;border-radius:18px}th,td{padding:14px;text-align:left;border-bottom:1px solid rgba(148,163,184,.18);vertical-align:top}th{color:#a7f3d0;text-transform:uppercase;font-size:.75rem;letter-spacing:.08em}td p{margin:.4rem 0 0;color:#a7b5ae}pre{white-space:pre-wrap;overflow:auto;border-radius:18px;background:#020617;padding:18px;color:#d1fae5}.status{display:inline-flex;border-radius:999px;padding:5px 10px;font-weight:800;font-size:.75rem}.pass{background:rgba(34,197,94,.18);color:#bbf7d0}.fail{background:rgba(239,68,68,.18);color:#fecaca}</style></head><body><main><section class="hero"><p><a href="#raw-report">Raw report</a></p><h1>${escapeHtml(title)}</h1><p>This page proves profile switching is production-bounded: teams can disable it, run recommend-only, auto-apply with confidence, restrict allowed targets, block unsafe targets, and cap automatic switches per session.</p><div class="metric-grid"><div class="metric"><span>Status</span><strong>${report.ok ? "PASS" : "FAIL"}</strong></div><div class="metric"><span>Cases</span><strong>${report.summary.passed}/${report.summary.total}</strong></div><div class="metric"><span>Generated</span><strong>${escapeHtml(report.generatedAt)}</strong></div></div></section><section class="card"><h2>Policy Cases</h2><table><thead><tr><th>Case</th><th>Expected</th><th>Actual</th><th>Selected</th><th>Blocked by</th><th>Confidence</th><th>Status</th></tr></thead><tbody>${rows}</tbody></table></section><section class="card" id="raw-report"><h2>Raw Report</h2><pre>${stringifyForHtml(report)}</pre></section></main></body></html>`;
|
|
6243
6243
|
};
|
|
6244
6244
|
var createVoiceProfileSwitchPolicyProofRoutes = (options) => {
|
|
6245
6245
|
const path = options.path ?? "/api/voice/profile-switch-policy-proof";
|
|
@@ -6384,15 +6384,15 @@ var buildVoiceProfileSwitchLiveDecisionReport = async (options) => {
|
|
|
6384
6384
|
var renderVoiceProfileSwitchLiveDecisionHTML = (report, options = {}) => {
|
|
6385
6385
|
const title = options.title ?? "Voice Profile Switch Live Decisions";
|
|
6386
6386
|
const rows = report.sessions.flatMap((session) => session.decisions.map((decision) => `<tr>
|
|
6387
|
-
<td><strong>${
|
|
6388
|
-
<td>${
|
|
6389
|
-
<td>${
|
|
6390
|
-
<td>${
|
|
6391
|
-
<td>${
|
|
6387
|
+
<td><strong>${escapeHtml(decision.sessionId)}</strong><p>${escapeHtml(new Date(decision.at).toISOString())}</p></td>
|
|
6388
|
+
<td>${escapeHtml(decision.source)}</td>
|
|
6389
|
+
<td>${escapeHtml(decision.action ?? "unknown")}</td>
|
|
6390
|
+
<td>${escapeHtml(decision.selectedProfileId ?? "none")}</td>
|
|
6391
|
+
<td>${escapeHtml(decision.blockedByPolicy ?? "none")}</td>
|
|
6392
6392
|
<td>${typeof decision.confidence === "number" ? `${Math.round(decision.confidence * 100)}%` : "n/a"}</td>
|
|
6393
|
-
<td>${
|
|
6393
|
+
<td>${escapeHtml(decision.reason ?? decision.outcome ?? "recorded")}</td>
|
|
6394
6394
|
</tr>`)).join("");
|
|
6395
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
6395
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>:root{color-scheme:dark;background:#11100b;color:#fff7ed;font-family:ui-sans-serif,system-ui,sans-serif}body{margin:0;padding:32px;background:radial-gradient(circle at top right,rgba(251,146,60,.18),transparent 34%),#11100b}main{max-width:1180px;margin:0 auto}.hero,.card{border:1px solid rgba(251,191,36,.24);border-radius:24px;background:rgba(28,25,23,.78);box-shadow:0 24px 90px rgba(0,0,0,.24);padding:24px;margin-bottom:18px}.metric-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px}.metric{border:1px solid rgba(251,191,36,.22);border-radius:18px;padding:16px;background:rgba(120,53,15,.26)}.metric span{display:block;color:#fed7aa;font-size:.75rem;text-transform:uppercase;letter-spacing:.08em}.metric strong{display:block;margin-top:8px;font-size:1.7rem}table{width:100%;border-collapse:collapse}th,td{padding:13px;text-align:left;border-bottom:1px solid rgba(251,191,36,.18);vertical-align:top}th{color:#fde68a;text-transform:uppercase;font-size:.74rem;letter-spacing:.08em}td p{margin:.35rem 0 0;color:#fdba74}pre{white-space:pre-wrap;overflow:auto;border-radius:18px;background:#020617;padding:18px;color:#ffedd5}.empty{color:#fdba74}</style></head><body><main><section class="hero"><h1>${escapeHtml(title)}</h1><p>This page summarizes real profile switch guard evidence from audit and trace stores. Use it beside policy proof to show bounded policy plus actual session decisions.</p><div class="metric-grid"><div class="metric"><span>Sessions</span><strong>${String(report.summary.sessions)}</strong></div><div class="metric"><span>Decisions</span><strong>${String(report.summary.decisions)}</strong></div><div class="metric"><span>Switches</span><strong>${String(report.summary.switches)}</strong></div><div class="metric"><span>Blocked</span><strong>${String(report.summary.blocked)}</strong></div><div class="metric"><span>Auto applied</span><strong>${String(report.summary.autoApplied)}</strong></div></div></section><section class="card"><h2>Live Guard Decisions</h2>${rows ? `<table><thead><tr><th>Session</th><th>Source</th><th>Action</th><th>Selected</th><th>Blocked by</th><th>Confidence</th><th>Reason</th></tr></thead><tbody>${rows}</tbody></table>` : '<p class="empty">No profile switch guard decisions recorded yet. Start a voice session with profileSwitchGuard enabled.</p>'}</section><section class="card"><h2>Raw Report</h2><pre>${stringifyForHtml(report)}</pre></section></main></body></html>`;
|
|
6396
6396
|
};
|
|
6397
6397
|
var createVoiceProfileSwitchLiveDecisionRoutes = (options) => {
|
|
6398
6398
|
const path = options.path ?? "/api/voice/profile-switch-live-decisions";
|
|
@@ -6514,9 +6514,9 @@ var buildVoiceProfileSwitchReadinessReport = async (options) => {
|
|
|
6514
6514
|
};
|
|
6515
6515
|
var renderVoiceProfileSwitchReadinessHTML = (report, options = {}) => {
|
|
6516
6516
|
const title = options.title ?? "Voice Profile Switch Readiness";
|
|
6517
|
-
const issues = report.issues.map((issue) => `<li class="${
|
|
6518
|
-
const sessions = report.live.sessions.map((session) => `<tr><td>${
|
|
6519
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
6517
|
+
const issues = report.issues.map((issue) => `<li class="${escapeHtml(issue.status)}"><strong>${escapeHtml(issue.code)}</strong><p>${escapeHtml(issue.message)}</p></li>`).join("");
|
|
6518
|
+
const sessions = report.live.sessions.map((session) => `<tr><td>${escapeHtml(session.sessionId)}</td><td>${escapeHtml(session.actions.join(", ") || "none")}</td><td>${String(session.decisions.length)}</td><td>${String(session.autoApplied)}</td><td>${escapeHtml(session.blockedByPolicy.join(", ") || "none")}</td></tr>`).join("");
|
|
6519
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>:root{color-scheme:dark;background:#0b1020;color:#eff6ff;font-family:ui-sans-serif,system-ui,sans-serif}body{margin:0;padding:32px;background:radial-gradient(circle at top left,rgba(59,130,246,.2),transparent 34%),#0b1020}main{max-width:1140px;margin:0 auto}.hero,.card{background:rgba(15,23,42,.82);border:1px solid rgba(147,197,253,.24);border-radius:24px;margin-bottom:18px;padding:24px}.status{border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{background:rgba(34,197,94,.18);color:#bbf7d0}.warn{background:rgba(245,158,11,.18);color:#fde68a}.fail{background:rgba(239,68,68,.18);color:#fecaca}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-top:16px}.metric{background:#0f172a;border:1px solid rgba(147,197,253,.2);border-radius:18px;padding:16px}.metric span{color:#93c5fd;display:block;font-size:.75rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.metric strong{display:block;font-size:1.8rem;margin-top:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{border-radius:16px;padding:14px}li p{margin:.35rem 0 0}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid rgba(147,197,253,.18);padding:12px;text-align:left}pre{background:#020617;border-radius:18px;color:#dbeafe;overflow:auto;padding:18px}</style></head><body><main><section class="hero"><h1>${escapeHtml(title)}</h1><p>Deploy-facing readiness for profile switching: policy proof, audit evidence, trace evidence, and live session behavior.</p><p class="status ${escapeHtml(report.status)}">${escapeHtml(report.status.toUpperCase())}</p><div class="grid"><div class="metric"><span>Sessions</span><strong>${String(report.summary.sessions)}</strong></div><div class="metric"><span>Decisions</span><strong>${String(report.summary.decisions)}</strong></div><div class="metric"><span>Policy cases</span><strong>${String(report.summary.policyCases ?? 0)}</strong></div><div class="metric"><span>Audit</span><strong>${String(report.summary.auditEvents)}</strong></div><div class="metric"><span>Trace</span><strong>${String(report.summary.traceEvents)}</strong></div></div></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass status">No readiness issues.</p>'}</section><section class="card"><h2>Live Sessions</h2>${sessions ? `<table><thead><tr><th>Session</th><th>Actions</th><th>Decisions</th><th>Auto applied</th><th>Blocked by</th></tr></thead><tbody>${sessions}</tbody></table>` : "<p>No live guard sessions found.</p>"}</section><section class="card"><h2>Raw Report</h2><pre>${stringifyForHtml(report)}</pre></section></main></body></html>`;
|
|
6520
6520
|
};
|
|
6521
6521
|
var createVoiceProfileSwitchReadinessRoutes = (options) => {
|
|
6522
6522
|
const path = options.path ?? "/api/voice/profile-switch-readiness";
|
|
@@ -6596,10 +6596,7 @@ var buildDefaultCitationMessage = (citations, args, maxChunkChars) => {
|
|
|
6596
6596
|
const text = truncate(citation.chunkText, maxChunkChars);
|
|
6597
6597
|
return `${String(index + 1)}. ${label} (score ${formatScore(citation.score)}): ${text}`;
|
|
6598
6598
|
});
|
|
6599
|
-
return [
|
|
6600
|
-
`Knowledge base results for "${args.query}":`,
|
|
6601
|
-
...lines
|
|
6602
|
-
].join(`
|
|
6599
|
+
return [`Knowledge base results for "${args.query}":`, ...lines].join(`
|
|
6603
6600
|
`);
|
|
6604
6601
|
};
|
|
6605
6602
|
var filterAllowedFilterKeys = (filter, allowedKeys) => {
|
|
@@ -8260,16 +8257,15 @@ var summarizeVoiceProviderHealth = async (input) => {
|
|
|
8260
8257
|
}
|
|
8261
8258
|
return summaries;
|
|
8262
8259
|
};
|
|
8263
|
-
var escapeHtml4 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
8264
8260
|
var renderVoiceProviderHealthHTML = (providers) => providers.length === 0 ? '<p class="voice-provider-empty">No provider status yet.</p>' : [
|
|
8265
8261
|
'<div class="voice-provider-health">',
|
|
8266
8262
|
...providers.map((provider) => {
|
|
8267
8263
|
const suppressionSeconds = typeof provider.suppressionRemainingMs === "number" ? Math.ceil(provider.suppressionRemainingMs / 1000) : undefined;
|
|
8268
8264
|
return [
|
|
8269
|
-
`<article class="voice-provider-card ${
|
|
8265
|
+
`<article class="voice-provider-card ${escapeHtml(provider.status)}">`,
|
|
8270
8266
|
'<div class="voice-provider-card-header">',
|
|
8271
|
-
`<strong>${
|
|
8272
|
-
`<span>${
|
|
8267
|
+
`<strong>${escapeHtml(provider.provider)}</strong>`,
|
|
8268
|
+
`<span>${escapeHtml(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>`,
|
|
8273
8269
|
"</div>",
|
|
8274
8270
|
"<dl>",
|
|
8275
8271
|
`<div><dt>Runs</dt><dd>${String(provider.runCount)}</dd></div>`,
|
|
@@ -8279,7 +8275,7 @@ var renderVoiceProviderHealthHTML = (providers) => providers.length === 0 ? '<p
|
|
|
8279
8275
|
`<div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div>`,
|
|
8280
8276
|
"</dl>",
|
|
8281
8277
|
suppressionSeconds ? `<p>Temporarily suppressed for ${String(suppressionSeconds)}s.</p>` : "",
|
|
8282
|
-
provider.lastError ? `<p>${
|
|
8278
|
+
provider.lastError ? `<p>${escapeHtml(provider.lastError)}</p>` : "",
|
|
8283
8279
|
"</article>"
|
|
8284
8280
|
].join("");
|
|
8285
8281
|
}),
|
|
@@ -8310,7 +8306,6 @@ var createVoiceProviderHealthRoutes = (options) => {
|
|
|
8310
8306
|
};
|
|
8311
8307
|
|
|
8312
8308
|
// src/assistantHealth.ts
|
|
8313
|
-
var escapeHtml5 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
8314
8309
|
var renderCountMap = (values) => {
|
|
8315
8310
|
const entries = Object.entries(values).sort((left, right) => right[1] - left[1]);
|
|
8316
8311
|
if (entries.length === 0) {
|
|
@@ -8318,7 +8313,7 @@ var renderCountMap = (values) => {
|
|
|
8318
8313
|
}
|
|
8319
8314
|
return [
|
|
8320
8315
|
'<div class="voice-assistant-health-metrics">',
|
|
8321
|
-
...entries.map(([label, value]) => `<div><span>${
|
|
8316
|
+
...entries.map(([label, value]) => `<div><span>${escapeHtml(label)}</span><strong>${String(value)}</strong></div>`),
|
|
8322
8317
|
"</div>"
|
|
8323
8318
|
].join("");
|
|
8324
8319
|
};
|
|
@@ -8379,11 +8374,11 @@ var renderVoiceAssistantHealthHTML = (summary) => {
|
|
|
8379
8374
|
'<div class="voice-assistant-health-failures">',
|
|
8380
8375
|
...failures.map((failure) => [
|
|
8381
8376
|
"<article>",
|
|
8382
|
-
`<strong>${
|
|
8383
|
-
`<span>${
|
|
8384
|
-
failure.error ? `<p>${
|
|
8385
|
-
`<small>${
|
|
8386
|
-
failure.replayHref ? `<p><a href="${
|
|
8377
|
+
`<strong>${escapeHtml(failure.provider ?? failure.assistantId ?? failure.type)}</strong>`,
|
|
8378
|
+
`<span>${escapeHtml(failure.status ?? (failure.rateLimited ? "rate-limited" : "error"))}</span>`,
|
|
8379
|
+
failure.error ? `<p>${escapeHtml(failure.error)}</p>` : "",
|
|
8380
|
+
`<small>${escapeHtml(failure.sessionId)}${failure.turnId ? ` / ${escapeHtml(failure.turnId)}` : ""}</small>`,
|
|
8381
|
+
failure.replayHref ? `<p><a href="${escapeHtml(failure.replayHref)}">Open replay</a></p>` : "",
|
|
8387
8382
|
"</article>"
|
|
8388
8383
|
].join("")),
|
|
8389
8384
|
"</div>"
|
|
@@ -8893,7 +8888,6 @@ var exportVoiceTrace = async (input) => {
|
|
|
8893
8888
|
};
|
|
8894
8889
|
};
|
|
8895
8890
|
var toNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
8896
|
-
var escapeHtml6 = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
8897
8891
|
var formatTraceValue = (value) => {
|
|
8898
8892
|
if (value === undefined || value === null) {
|
|
8899
8893
|
return "";
|
|
@@ -9177,10 +9171,10 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9177
9171
|
const offset = summary.startedAt === undefined ? event.at : Math.max(0, event.at - summary.startedAt);
|
|
9178
9172
|
return [
|
|
9179
9173
|
"<tr>",
|
|
9180
|
-
`<td>${
|
|
9181
|
-
`<td>${
|
|
9182
|
-
`<td>${
|
|
9183
|
-
`<td><code>${
|
|
9174
|
+
`<td>${escapeHtml(String(offset))}</td>`,
|
|
9175
|
+
`<td>${escapeHtml(event.type)}</td>`,
|
|
9176
|
+
`<td>${escapeHtml(event.turnId ?? "")}</td>`,
|
|
9177
|
+
`<td><code>${escapeHtml(JSON.stringify(event.payload))}</code></td>`,
|
|
9184
9178
|
"</tr>"
|
|
9185
9179
|
].join("");
|
|
9186
9180
|
}).join(`
|
|
@@ -9191,7 +9185,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9191
9185
|
"<head>",
|
|
9192
9186
|
'<meta charset="utf-8" />',
|
|
9193
9187
|
'<meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
9194
|
-
`<title>${
|
|
9188
|
+
`<title>${escapeHtml(options.title ?? "Voice Trace")}</title>`,
|
|
9195
9189
|
"<style>",
|
|
9196
9190
|
"body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}",
|
|
9197
9191
|
"main{max-width:1100px;margin:auto}",
|
|
@@ -9205,7 +9199,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9205
9199
|
"</style>",
|
|
9206
9200
|
"</head>",
|
|
9207
9201
|
"<body><main>",
|
|
9208
|
-
`<h1>${
|
|
9202
|
+
`<h1>${escapeHtml(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
|
|
9209
9203
|
`<p class="${evaluation.pass ? "pass" : "fail"}">QA: ${evaluation.pass ? "pass" : "fail"}</p>`,
|
|
9210
9204
|
'<section class="summary">',
|
|
9211
9205
|
`<div class="card"><strong>Events</strong><br>${summary.eventCount}</div>`,
|
|
@@ -9219,7 +9213,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9219
9213
|
eventRows,
|
|
9220
9214
|
"</tbody></table>",
|
|
9221
9215
|
"<h2>Markdown Export</h2>",
|
|
9222
|
-
`<pre>${
|
|
9216
|
+
`<pre>${escapeHtml(markdown)}</pre>`,
|
|
9223
9217
|
"</main></body></html>"
|
|
9224
9218
|
].join(`
|
|
9225
9219
|
`);
|
|
@@ -9233,7 +9227,6 @@ var buildVoiceTraceReplay = (events, options = {}) => ({
|
|
|
9233
9227
|
|
|
9234
9228
|
// src/auditRoutes.ts
|
|
9235
9229
|
import { Elysia as Elysia4 } from "elysia";
|
|
9236
|
-
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
9237
9230
|
var getString3 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
9238
9231
|
var getNumber2 = (value) => {
|
|
9239
9232
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -9331,14 +9324,14 @@ var buildVoiceAuditTrailReport = async (options) => {
|
|
|
9331
9324
|
};
|
|
9332
9325
|
var renderVoiceAuditTrailHTML = (report, options = {}) => {
|
|
9333
9326
|
const title = options.title ?? "AbsoluteJS Voice Audit Trail";
|
|
9334
|
-
const chips = report.summary.byType.map(([type, count]) => `<span>${
|
|
9327
|
+
const chips = report.summary.byType.map(([type, count]) => `<span>${escapeHtml(type)} <strong>${count}</strong></span>`).join("");
|
|
9335
9328
|
const rows = report.events.map((event) => {
|
|
9336
9329
|
const actor = event.actor ? `${event.actor.kind}:${event.actor.id}` : "unknown";
|
|
9337
9330
|
const resource = event.resource ? `${event.resource.type}${event.resource.id ? `:${event.resource.id}` : ""}` : "";
|
|
9338
9331
|
const payload = event.payload ? JSON.stringify(event.payload, null, 2) : "";
|
|
9339
|
-
return `<article class="event ${
|
|
9332
|
+
return `<article class="event ${escapeHtml(event.outcome ?? "unknown")}"><div><span>${escapeHtml(event.type)}</span><h2>${escapeHtml(event.action)}</h2><p>${escapeHtml(new Date(event.at).toLocaleString())}</p><p>Actor: ${escapeHtml(actor)}${resource ? ` \xB7 Resource: ${escapeHtml(resource)}` : ""}</p>${event.sessionId ? `<p>Session: ${escapeHtml(event.sessionId)}</p>` : ""}</div><strong>${escapeHtml(event.outcome ?? "recorded")}</strong>${payload ? `<pre>${escapeHtml(payload)}</pre>` : ""}</article>`;
|
|
9340
9333
|
}).join("");
|
|
9341
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
9334
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#11140f;color:#f7f1df;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,.18),rgba(245,158,11,.12));border:1px solid #2c3327;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#facc15;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.chips{display:flex;flex-wrap:wrap;gap:10px}.chips span{border:1px solid #46513b;border-radius:999px;padding:8px 12px}.events{display:grid;gap:14px}.event{background:#181d15;border:1px solid #2c3327;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto;padding:18px}.event.error{border-color:rgba(239,68,68,.75)}.event.skipped{border-color:rgba(245,158,11,.7)}.event.success{border-color:rgba(34,197,94,.55)}.event span{color:#facc15;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.event h2{margin:.2rem 0}.event p{color:#c8ccb8;margin:.2rem 0}.event strong{text-transform:uppercase}pre{background:#0c0f0a;border-radius:14px;grid-column:1/-1;overflow:auto;padding:14px;white-space:pre-wrap}@media(max-width:760px){main{padding:20px}.event{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted evidence</p><h1>${escapeHtml(title)}</h1><p>${report.summary.total} event(s), ${report.summary.errors} error(s). Latest ${report.summary.latestAt ? escapeHtml(new Date(report.summary.latestAt).toLocaleString()) : "never"}.</p><div class="chips">${chips}</div></section><section class="events">${rows || "<p>No audit events match this filter.</p>"}</section></main></body></html>`;
|
|
9342
9335
|
};
|
|
9343
9336
|
var createVoiceAuditTrailRoutes = (options) => {
|
|
9344
9337
|
const path = options.path ?? "/api/voice-audit";
|
|
@@ -9430,7 +9423,6 @@ var createVoiceAuditTrailRoutes = (options) => {
|
|
|
9430
9423
|
};
|
|
9431
9424
|
|
|
9432
9425
|
// src/auditExport.ts
|
|
9433
|
-
var escapeHtml8 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
9434
9426
|
var normalizeRedactionKey2 = (key) => key.trim().toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
9435
9427
|
var resolveReplacement2 = (input) => typeof input.options.replacement === "function" ? input.options.replacement({
|
|
9436
9428
|
key: input.key,
|
|
@@ -9548,8 +9540,8 @@ var renderVoiceAuditHTML = (events, options = {}) => {
|
|
|
9548
9540
|
const markdown = renderVoiceAuditMarkdown(events, options);
|
|
9549
9541
|
const renderEvents = options.redact ? redactVoiceAuditEvents(events, options.redact) : events;
|
|
9550
9542
|
const summary = summarizeVoiceAuditTrail(renderEvents);
|
|
9551
|
-
const rows = renderEvents.map((event) => `<tr><td>${
|
|
9552
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
9543
|
+
const rows = renderEvents.map((event) => `<tr><td>${escapeHtml(new Date(event.at).toISOString())}</td><td>${escapeHtml(event.type)}</td><td>${escapeHtml(event.action)}</td><td>${escapeHtml(event.outcome ?? "")}</td><td><code>${escapeHtml(JSON.stringify(event.payload ?? {}))}</code></td></tr>`).join("");
|
|
9544
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;margin:1rem 0}.card{background:white;border:1px solid #ded9cc;border-radius:12px;padding:1rem}table{border-collapse:collapse;width:100%;background:white;border:1px solid #ded9cc}th,td{border-bottom:1px solid #eee8dc;padding:.65rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}pre{background:#181713;color:#f8f7f2;padding:1rem;border-radius:12px;overflow:auto}</style></head><body><main><h1>${escapeHtml(title)}</h1><section class="summary"><div class="card"><strong>Events</strong><br>${summary.total}</div><div class="card"><strong>Errors</strong><br>${summary.errors}</div><div class="card"><strong>Latest</strong><br>${summary.latestAt ? escapeHtml(new Date(summary.latestAt).toLocaleString()) : "never"}</div></section><table><thead><tr><th>At</th><th>Type</th><th>Action</th><th>Outcome</th><th>Payload</th></tr></thead><tbody>${rows}</tbody></table><h2>Markdown Export</h2><pre>${escapeHtml(markdown)}</pre></main></body></html>`;
|
|
9553
9545
|
};
|
|
9554
9546
|
var buildVoiceAuditExport = (events, options = {}) => {
|
|
9555
9547
|
const exportEvents = options.redact ? redactVoiceAuditEvents(events, options.redact) : events;
|
|
@@ -9999,7 +9991,6 @@ var createVoiceAuditSinkDeliveryWorkerLoop = (options) => {
|
|
|
9999
9991
|
};
|
|
10000
9992
|
|
|
10001
9993
|
// src/auditDeliveryRoutes.ts
|
|
10002
|
-
var escapeHtml9 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10003
9994
|
var getString4 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
10004
9995
|
var getNumber3 = (value) => {
|
|
10005
9996
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -10080,14 +10071,14 @@ var renderSinkResults = (delivery) => {
|
|
|
10080
10071
|
if (entries.length === 0) {
|
|
10081
10072
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
10082
10073
|
}
|
|
10083
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
10074
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml(sinkId)}</strong>: ${escapeHtml(result.status)}${result.deliveredTo ? ` to ${escapeHtml(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
10084
10075
|
};
|
|
10085
|
-
var renderEventList = (delivery) => delivery.events.length === 0 ? "<p>No audit events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
10076
|
+
var renderEventList = (delivery) => delivery.events.length === 0 ? "<p>No audit events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml(event.type)} ${escapeHtml(event.action)} <small>${escapeHtml(event.id)}</small></li>`).join("")}</ul>`;
|
|
10086
10077
|
var renderVoiceAuditDeliveryHTML = (report, options = {}) => {
|
|
10087
10078
|
const title = options.title ?? "AbsoluteJS Voice Audit Deliveries";
|
|
10088
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
10089
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
10090
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10079
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml(options.workerPath ?? "/api/voice-audit-deliveries/drain")}"><button type="submit">Drain audit deliveries</button></form>`;
|
|
10080
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml(delivery.deliveryStatus)}</span><h2>${escapeHtml(delivery.id)}</h2><p>${escapeHtml(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults(delivery)}<h3>Events</h3>${renderEventList(delivery)}</article>`).join("");
|
|
10081
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101418;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(14,165,233,.17),rgba(245,158,11,.13));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#38bdf8;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:#93c5fd;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:#38bdf8;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">Compliance export health</p><h1>${escapeHtml(title)}</h1><p>Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid(report)}<section class="deliveries">${rows || "<p>No audit deliveries match this filter.</p>"}</section></main></body></html>`;
|
|
10091
10082
|
};
|
|
10092
10083
|
var createVoiceAuditDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceAuditDeliveryReport(options, resolveVoiceAuditDeliveryFilter(query, options.filter));
|
|
10093
10084
|
var createVoiceAuditDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -10127,7 +10118,6 @@ var createVoiceAuditDeliveryRoutes = (options) => {
|
|
|
10127
10118
|
|
|
10128
10119
|
// src/bargeInRoutes.ts
|
|
10129
10120
|
import { Elysia as Elysia6 } from "elysia";
|
|
10130
|
-
var escapeHtml10 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10131
10121
|
var isBargeInPayload = (value) => !!value && typeof value === "object" && typeof value.at === "number" && typeof value.id === "string" && typeof value.reason === "string" && typeof value.status === "string";
|
|
10132
10122
|
var toBargeInEvent = (event) => event.type === "client.barge_in" && isBargeInPayload(event.payload) ? event.payload : undefined;
|
|
10133
10123
|
var summarizeVoiceBargeIn = (events, options = {}) => {
|
|
@@ -10183,8 +10173,8 @@ const bargeInMonitor = createVoiceBargeInMonitor({
|
|
|
10183
10173
|
path: '/api/voice-barge-in',
|
|
10184
10174
|
sessionId
|
|
10185
10175
|
});`;
|
|
10186
|
-
const sessions = report.sessions.length ? report.sessions.map((session) => `<tr><td>${
|
|
10187
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10176
|
+
const sessions = report.sessions.length ? report.sessions.map((session) => `<tr><td>${escapeHtml(session.sessionId)}</td><td>${String(session.total)}</td><td>${String(session.passed)}</td><td>${String(session.failed)}</td><td>${String(session.averageLatencyMs ?? 0)}ms</td></tr>`).join("") : '<tr><td colspan="5">No barge-in events yet.</td></tr>';
|
|
10177
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn{color:#fbbf24}.fail{color:#fca5a5}.empty{color:#cbd5e1}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.primitive{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}.primitive{margin:0 0 20px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2b3642;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}</style></head><body><main><p class="eyebrow">Interruption quality</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><section class="metrics"><article><span>Interruptions</span><strong>${String(report.total)}</strong></article><article><span>Avg latency</span><strong>${String(report.averageLatencyMs ?? 0)}ms</strong></article><article><span>Passed</span><strong>${String(report.passed)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceBargeInRoutes(...)</code> proves interruption quality</h2><p>Use the shared trace store for browser interrupts, readiness gates, trace timelines, and production evidence instead of trusting a black-box hosted dashboard.</p><pre><code>${escapeHtml(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Total</th><th>Passed</th><th>Failed</th><th>Avg latency</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
10188
10178
|
};
|
|
10189
10179
|
var createVoiceBargeInRoutes = (options) => {
|
|
10190
10180
|
const path = options.path ?? "/api/voice-barge-in";
|
|
@@ -10225,7 +10215,6 @@ var createVoiceBargeInRoutes = (options) => {
|
|
|
10225
10215
|
// src/browserCallProfiles.ts
|
|
10226
10216
|
import { Elysia as Elysia7 } from "elysia";
|
|
10227
10217
|
var DEFAULT_MAX_AGE_MS = 10 * 60 * 1000;
|
|
10228
|
-
var escapeHtml11 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10229
10218
|
var toTime = (value) => {
|
|
10230
10219
|
if (value === undefined) {
|
|
10231
10220
|
return;
|
|
@@ -10365,8 +10354,8 @@ var renderVoiceBrowserCallProfileMarkdown = (report, options = {}) => {
|
|
|
10365
10354
|
var renderVoiceBrowserCallProfileHTML = (report, options = {}) => {
|
|
10366
10355
|
const normalized = buildVoiceBrowserCallProfileReport(report);
|
|
10367
10356
|
const title = options.title ?? "Voice Browser Call Profiles";
|
|
10368
|
-
const rows = normalized.results.map((result) => `<tr><td>${
|
|
10369
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10357
|
+
const rows = normalized.results.map((result) => `<tr><td>${escapeHtml(result.framework)}</td><td class="${result.ok ? "pass" : "fail"}">${result.ok ? "pass" : "fail"}</td><td>${String(result.summary?.openSockets ?? 0)}</td><td>${String(result.summary?.sentBytes ?? 0)}</td><td>${String(result.summary?.receivedBytes ?? 0)}</td><td>${String(result.summary?.messageCount ?? 0)}</td><td>${escapeHtml(result.error ?? "")}</td></tr>`).join("");
|
|
10358
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#11140f;color:#f4f0df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.primitive,table{background:#191d15;border:1px solid #323a27;border-radius:22px;margin-bottom:16px}.hero,.primitive{padding:22px}.eyebrow{color:#bef264;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#bef264}.warn,.empty,.stale{color:#fde68a}.fail{color:#fecaca}.metrics{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-top:18px}.metric{background:#10130d;border:1px solid #303827;border-radius:16px;padding:14px}.metric span{color:#b8c3a3}.metric strong{display:block;font-size:1.7rem;margin-top:4px}.primitive code{color:#d9f99d}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #323a27;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Real browser microphone proof</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(normalized.status)}">Status: ${escapeHtml(normalized.status)}</p><p>Framework parity proof from real browser pages opening the voice WebSocket and sending microphone audio bytes.</p><section class="metrics"><div class="metric"><span>Frameworks</span><strong>${String(normalized.summary.totalFrameworks)}</strong></div><div class="metric"><span>Passing</span><strong>${String(normalized.summary.passedFrameworks.length)}</strong></div><div class="metric"><span>Open sockets</span><strong>${String(normalized.summary.openSockets)}</strong></div><div class="metric"><span>Sent bytes</span><strong>${String(normalized.summary.sentBytes)}</strong></div><div class="metric"><span>Received bytes</span><strong>${String(normalized.summary.receivedBytes)}</strong></div><div class="metric"><span>Messages</span><strong>${String(normalized.summary.totalMessages)}</strong></div></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><p><code>buildVoiceBrowserCallProfileReport(...)</code> normalizes browser-call evidence. <code>evaluateVoiceBrowserCallProfileEvidence(...)</code> gates required frameworks, WebSocket opens, sent bytes, and freshness. <code>createVoiceBrowserCallProfileRoutes(...)</code> serves JSON, HTML, and Markdown.</p></section><table><thead><tr><th>Framework</th><th>Status</th><th>WebSockets</th><th>Sent bytes</th><th>Received bytes</th><th>Messages</th><th>Error</th></tr></thead><tbody>${rows || '<tr><td colspan="7">No browser call profile evidence yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
10370
10359
|
};
|
|
10371
10360
|
var resolveSource = async (options) => {
|
|
10372
10361
|
const source = typeof options.source === "function" ? await options.source() : options.source;
|
|
@@ -10410,7 +10399,6 @@ var createVoiceBrowserCallProfileRoutes = (options = {}) => {
|
|
|
10410
10399
|
|
|
10411
10400
|
// src/browserMediaRoutes.ts
|
|
10412
10401
|
import { Elysia as Elysia8 } from "elysia";
|
|
10413
|
-
var escapeHtml12 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10414
10402
|
var isMediaWebRTCStatsReport = (value) => {
|
|
10415
10403
|
const report = value;
|
|
10416
10404
|
return !!report && typeof report === "object" && (report.status === "pass" || report.status === "warn" || report.status === "fail") && typeof report.activeCandidatePairs === "number" && typeof report.liveAudioTracks === "number" && typeof report.packetLossRatio === "number" && typeof report.bytesReceived === "number" && typeof report.bytesSent === "number" && Array.isArray(report.issues);
|
|
@@ -10480,9 +10468,9 @@ var renderVoiceBrowserMediaHTML = (report, options = {}) => {
|
|
|
10480
10468
|
const latestContinuity = report.latest?.continuity;
|
|
10481
10469
|
const rows = report.recent.slice(0, 20).map((sample) => {
|
|
10482
10470
|
const stalledStreams = (sample.continuity?.stalledInboundStreams ?? 0) + (sample.continuity?.stalledOutboundStreams ?? 0);
|
|
10483
|
-
return `<tr><td>${
|
|
10471
|
+
return `<tr><td>${escapeHtml(sample.sessionId)}</td><td>${escapeHtml(mergeIssues(sample.report, sample.continuity).status)}</td><td>${String(sample.report.activeCandidatePairs)}</td><td>${String(sample.report.liveAudioTracks)}</td><td>${String(sample.continuity?.inboundAudioStreams ?? "n/a")}</td><td>${String(sample.continuity?.outboundAudioStreams ?? "n/a")}</td><td>${String(stalledStreams)}</td><td>${String(sample.report.roundTripTimeMs ?? "n/a")}ms</td><td>${String(sample.report.jitterMs ?? "n/a")}ms</td><td>${String(sample.report.packetLossRatio)}</td><td>${escapeHtml(new Date(sample.at).toLocaleString())}</td></tr>`;
|
|
10484
10472
|
}).join("");
|
|
10485
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10473
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0f172a;color:#e2e8f0;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.primitive,table{background:#111827;border:1px solid #334155;border-radius:22px;margin-bottom:16px}.hero,.primitive{padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fecaca}.metrics{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-top:18px}.metric{background:#0b1220;border:1px solid #263244;border-radius:16px;padding:14px}.metric span{color:#94a3b8}.metric strong{display:block;font-size:1.7rem;margin-top:4px}.primitive code{color:#bfdbfe}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #334155;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Browser WebRTC media proof</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><p>Recent <code>client.browser_media</code> traces from browser <code>RTCPeerConnection.getStats()</code> reports, including aggregate transport stats and per-stream continuity.</p><section class="metrics"><div class="metric"><span>Reports</span><strong>${String(report.total)}</strong></div><div class="metric"><span>Candidate pairs</span><strong>${String(latest?.activeCandidatePairs ?? 0)}</strong></div><div class="metric"><span>Live audio tracks</span><strong>${String(latest?.liveAudioTracks ?? 0)}</strong></div><div class="metric"><span>Inbound streams</span><strong>${String(latestContinuity?.inboundAudioStreams ?? "n/a")}</strong></div><div class="metric"><span>Outbound streams</span><strong>${String(latestContinuity?.outboundAudioStreams ?? "n/a")}</strong></div><div class="metric"><span>Stalled streams</span><strong>${String((latestContinuity?.stalledInboundStreams ?? 0) + (latestContinuity?.stalledOutboundStreams ?? 0))}</strong></div><div class="metric"><span>RTT</span><strong>${String(latest?.roundTripTimeMs ?? "n/a")}ms</strong></div><div class="metric"><span>Jitter</span><strong>${String(latest?.jitterMs ?? "n/a")}ms</strong></div><div class="metric"><span>Loss</span><strong>${String(latest?.packetLossRatio ?? "n/a")}</strong></div></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><p><code>createVoiceBrowserMediaReporter({ peerConnection, continuity })</code> runs in the browser and posts reports here. <code>getLatestVoiceBrowserMediaReport(...)</code> can feed production readiness with aggregate and continuity issues merged.</p></section><table><thead><tr><th>Session</th><th>Status</th><th>Pairs</th><th>Tracks</th><th>Inbound</th><th>Outbound</th><th>Stalled</th><th>RTT</th><th>Jitter</th><th>Loss</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="11">No browser media reports yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
10486
10474
|
};
|
|
10487
10475
|
var createVoiceBrowserMediaRoutes = (options) => {
|
|
10488
10476
|
const path = options.path ?? "/api/voice/browser-media";
|
|
@@ -10535,7 +10523,6 @@ import {
|
|
|
10535
10523
|
// src/sessionReplay.ts
|
|
10536
10524
|
import { Elysia as Elysia9 } from "elysia";
|
|
10537
10525
|
var getString5 = (value) => typeof value === "string" ? value : undefined;
|
|
10538
|
-
var escapeHtml13 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10539
10526
|
var increment3 = (record, key) => {
|
|
10540
10527
|
record[key] = (record[key] ?? 0) + 1;
|
|
10541
10528
|
};
|
|
@@ -10732,10 +10719,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
10732
10719
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
10733
10720
|
'<div class="voice-sessions-list">',
|
|
10734
10721
|
...sessions.map((session) => [
|
|
10735
|
-
`<article class="voice-session-card ${
|
|
10722
|
+
`<article class="voice-session-card ${escapeHtml(session.status)}">`,
|
|
10736
10723
|
'<div class="voice-session-card-header">',
|
|
10737
|
-
`<strong>${
|
|
10738
|
-
`<span>${
|
|
10724
|
+
`<strong>${escapeHtml(session.sessionId)}</strong>`,
|
|
10725
|
+
`<span>${escapeHtml(session.status)}</span>`,
|
|
10739
10726
|
"</div>",
|
|
10740
10727
|
"<dl>",
|
|
10741
10728
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -10743,9 +10730,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
10743
10730
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
10744
10731
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
10745
10732
|
"</dl>",
|
|
10746
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
10747
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
10748
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
10733
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml(session.latestOutcome)}</p>` : "",
|
|
10734
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml).join(", ")}</p>` : "",
|
|
10735
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml(session.replayHref)}">Open replay</a></p>` : "",
|
|
10749
10736
|
"</article>"
|
|
10750
10737
|
].join("")),
|
|
10751
10738
|
"</div>"
|
|
@@ -10815,7 +10802,6 @@ var createVoiceSessionReplayRoutes = (options) => {
|
|
|
10815
10802
|
|
|
10816
10803
|
// src/traceTimeline.ts
|
|
10817
10804
|
import { Elysia as Elysia10 } from "elysia";
|
|
10818
|
-
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10819
10805
|
var getString6 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
10820
10806
|
var getNumber4 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
10821
10807
|
var firstString = (payload, keys) => {
|
|
@@ -11001,17 +10987,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
11001
10987
|
};
|
|
11002
10988
|
};
|
|
11003
10989
|
var formatMs = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
11004
|
-
var renderProviderCards = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${
|
|
10990
|
+
var renderProviderCards = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
|
|
11005
10991
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
11006
|
-
const events = session.events.map((event) => `<tr class="${
|
|
11007
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
11008
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
11009
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10992
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml(event.type)}</td><td>${escapeHtml(event.label)}</td><td>${escapeHtml(event.provider ?? "")}</td><td>${escapeHtml(event.status ?? "")}</td><td>${formatMs(event.elapsedMs)}</td></tr>`).join("");
|
|
10993
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml(issue.severity)}">${escapeHtml(issue.code)}: ${escapeHtml(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
10994
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
10995
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml(session.sessionId)}</h1><p class="status ${escapeHtml(session.status)}">${escapeHtml(session.status)}</p>${supportLinks}</header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
|
|
11010
10996
|
};
|
|
11011
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
10997
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">${escapeHtml(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml(session.sessionId)}</a>`}</td><td>${escapeHtml(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
11012
10998
|
var timelineCSS = "body{background:#0f1318;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}a{color:#fbbf24}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;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}.metrics,.providers{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.providers article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span,dt,.muted{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:12px 0 0}dd{font-weight:800;margin:4px 0 0}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}section{margin-top:28px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}";
|
|
11013
10999
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
11014
|
-
const snippet =
|
|
11000
|
+
const snippet = escapeHtml(`const traceStore = createVoiceTraceSinkStore({
|
|
11015
11001
|
store: runtimeStorage.traces,
|
|
11016
11002
|
sinks: [
|
|
11017
11003
|
createVoiceTraceHTTPSink({
|
|
@@ -11037,7 +11023,7 @@ app.use(
|
|
|
11037
11023
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
11038
11024
|
})
|
|
11039
11025
|
);`);
|
|
11040
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11026
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
|
|
11041
11027
|
};
|
|
11042
11028
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
11043
11029
|
const path = options.path ?? "/api/voice-traces";
|
|
@@ -11707,7 +11693,6 @@ var renderVoiceFailureReplayMarkdown = (report) => {
|
|
|
11707
11693
|
].join(`
|
|
11708
11694
|
`);
|
|
11709
11695
|
};
|
|
11710
|
-
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11711
11696
|
var formatMs2 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
11712
11697
|
var outcomeLabels = (outcome) => [
|
|
11713
11698
|
outcome.complete ? "complete" : undefined,
|
|
@@ -11833,18 +11818,18 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
11833
11818
|
`);
|
|
11834
11819
|
};
|
|
11835
11820
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
11836
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
11837
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
11838
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
11821
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs2(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
11822
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
11823
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml(decision.status ?? decision.type)}</span> ${formatMs2(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
11839
11824
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
11840
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
11841
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
11842
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
11843
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
11844
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
11825
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml(handoff.status ?? "")}</span><p>${escapeHtml(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
11826
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml(tool.toolName ?? "tool")}</strong> <span>${escapeHtml(tool.status ?? "")}</span> ${formatMs2(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
11827
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml(review.title)}</strong> <span>${escapeHtml(review.summary.outcome ?? "")}</span><p>${escapeHtml(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
11828
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml(task.title)}</strong> <span>${escapeHtml(task.status)}</span><p>${escapeHtml(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
11829
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml(event.type)}</strong> <span>${escapeHtml(event.deliveryStatus ?? "local")}</span><p>${escapeHtml(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
11845
11830
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
11846
11831
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
11847
|
-
return `<li><strong>assistant.guardrail ${
|
|
11832
|
+
return `<li><strong>assistant.guardrail ${escapeHtml(decision.stage ?? "unknown")}</strong> <span>${escapeHtml(decision.status ?? "")}</span><p>Allowed: ${escapeHtml(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml(decision.turnId)}` : ""}</p><p>${escapeHtml(findings)}</p></li>`;
|
|
11848
11833
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
11849
11834
|
const telephonyMedia = record.telephonyMedia.events.length ? record.telephonyMedia.events.slice(0, 50).map((event) => {
|
|
11850
11835
|
const details = [
|
|
@@ -11855,12 +11840,12 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
11855
11840
|
event.sequenceNumber ? `Seq: ${event.sequenceNumber}` : undefined,
|
|
11856
11841
|
`Audio bytes: ${String(event.audioBytes)}`
|
|
11857
11842
|
].filter((detail) => typeof detail === "string");
|
|
11858
|
-
return `<li><strong>${
|
|
11843
|
+
return `<li><strong>${escapeHtml(event.event)}</strong> <span>${escapeHtml(new Date(event.at).toLocaleString())}</span><p>${escapeHtml(details.join(" \xB7 "))}</p></li>`;
|
|
11859
11844
|
}).join("") : "<li>No telephony media trace events recorded.</li>";
|
|
11860
|
-
const mediaPipelineSection = record.mediaPipeline ? `<section id="media-pipeline"><h2>Media Pipeline</h2><p class="muted">Surface: ${
|
|
11861
|
-
const mediaPipelineCard = record.mediaPipeline ? `<div class="card"><span>Media pipeline</span><strong>${
|
|
11845
|
+
const mediaPipelineSection = record.mediaPipeline ? `<section id="media-pipeline"><h2>Media Pipeline</h2><p class="muted">Surface: ${escapeHtml(record.mediaPipeline.surface)} \xB7 Status: ${escapeHtml(record.mediaPipeline.status)} \xB7 Quality: ${escapeHtml(record.mediaPipeline.qualityStatus)} \xB7 Transport: ${escapeHtml(record.mediaPipeline.transportStatus ?? "n/a")} \xB7 Graph: ${escapeHtml(record.mediaPipeline.processorGraphStatus ?? "n/a")} \xB7 Frames: ${String(record.mediaPipeline.frames)} \xB7 Jitter: ${record.mediaPipeline.jitterMs === undefined ? "n/a" : `${String(record.mediaPipeline.jitterMs)}ms`}</p><ul>${record.mediaPipeline.issueCodes.length ? record.mediaPipeline.issueCodes.map((code) => `<li><strong>${escapeHtml(code)}</strong></li>`).join("") : "<li>No media pipeline issue codes.</li>"}</ul></section>` : "";
|
|
11846
|
+
const mediaPipelineCard = record.mediaPipeline ? `<div class="card"><span>Media pipeline</span><strong>${escapeHtml(record.mediaPipeline.status)}</strong><span>${String(record.mediaPipeline.issueCodes.length)} issue code(s)</span></div>` : "";
|
|
11862
11847
|
const mediaPipelineNavLink = record.mediaPipeline ? '<a href="#media-pipeline">Media pipeline</a>' : "";
|
|
11863
|
-
const snippet =
|
|
11848
|
+
const snippet = escapeHtml(`app.use(
|
|
11864
11849
|
createVoiceOperationsRecordRoutes({
|
|
11865
11850
|
audit: auditStore,
|
|
11866
11851
|
integrationEvents: opsEvents,
|
|
@@ -11874,9 +11859,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
11874
11859
|
tasks: opsTasks
|
|
11875
11860
|
})
|
|
11876
11861
|
);`);
|
|
11877
|
-
const incidentMarkdown =
|
|
11878
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
11879
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11862
|
+
const incidentMarkdown = escapeHtml(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
11863
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml(options.incidentHref)}">Download incident.md</a>` : "";
|
|
11864
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(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>${escapeHtml(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml(record.status)}">${escapeHtml(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#telephony-media">Telephony media</a>${mediaPipelineNavLink}<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>${formatMs2(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Telephony media</span><strong>${String(record.telephonyMedia.media)}</strong><span>${String(record.telephonyMedia.inbound)} inbound / ${String(record.telephonyMedia.outbound)} outbound / ${String(record.telephonyMedia.clears)} clears</span></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>${mediaPipelineCard}</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="telephony-media"><h2>Telephony Media</h2><p class="muted">Live <code>client.telephony_media</code> stream lifecycle evidence attached to this session. Carriers: ${escapeHtml(record.telephonyMedia.carriers.join(", ") || "none")}. Streams: ${escapeHtml(record.telephonyMedia.streamIds.join(", ") || "none")}. Inbound: ${String(record.telephonyMedia.inbound)}. Outbound: ${String(record.telephonyMedia.outbound)}. Marks: ${String(record.telephonyMedia.marks)}. Clears: ${String(record.telephonyMedia.clears)}.</p><ul>${telephonyMedia}</ul></section>${mediaPipelineSection}<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, media streams, 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>`;
|
|
11880
11865
|
};
|
|
11881
11866
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
11882
11867
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -12119,7 +12104,6 @@ var createVoiceSessionSnapshotRoutes = (options = {}) => {
|
|
|
12119
12104
|
};
|
|
12120
12105
|
|
|
12121
12106
|
// src/callDebugger.ts
|
|
12122
|
-
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12123
12107
|
var resolveSessionId = (params) => {
|
|
12124
12108
|
const sessionId = params.sessionId;
|
|
12125
12109
|
return typeof sessionId === "string" ? sessionId : "";
|
|
@@ -12211,20 +12195,20 @@ var buildVoiceCallDebuggerReport = async (options, input) => {
|
|
|
12211
12195
|
status
|
|
12212
12196
|
};
|
|
12213
12197
|
};
|
|
12214
|
-
var renderMetric = (label, value) => `<div class="card"><span>${
|
|
12198
|
+
var renderMetric = (label, value) => `<div class="card"><span>${escapeHtml(label)}</span><strong>${escapeHtml(String(value))}</strong></div>`;
|
|
12215
12199
|
var renderArtifact = (artifact) => {
|
|
12216
|
-
const body = `<strong>${
|
|
12217
|
-
return artifact.href ? `<a href="${
|
|
12200
|
+
const body = `<strong>${escapeHtml(artifact.label)}</strong><span>${escapeHtml(artifact.status ?? "n/a")}</span>`;
|
|
12201
|
+
return artifact.href ? `<a href="${escapeHtml(artifact.href)}">${body}</a>` : `<div>${body}</div>`;
|
|
12218
12202
|
};
|
|
12219
12203
|
var renderVoiceCallDebuggerHTML = (report, options = {}) => {
|
|
12220
12204
|
const title = options.title ?? "Voice Call Debugger";
|
|
12221
|
-
const transcript = report.operationsRecord.transcript.length ? report.operationsRecord.transcript.map((turn) => `<li><strong>${
|
|
12222
|
-
const providerDecisions = report.operationsRecord.providerDecisions.length ? report.operationsRecord.providerDecisions.slice(0, 12).map((decision) => `<li><strong>${
|
|
12223
|
-
const failureIssues = report.failureReplay.summary.issues.length ? report.failureReplay.summary.issues.map((issue) => `<li>${
|
|
12224
|
-
const heard = report.failureReplay.summary.userHeard.length ? report.failureReplay.summary.userHeard.map((text) => `<li>${
|
|
12205
|
+
const transcript = report.operationsRecord.transcript.length ? report.operationsRecord.transcript.map((turn) => `<li><strong>${escapeHtml(turn.id)}</strong><p>${escapeHtml(turn.committedText ?? turn.transcripts.at(-1) ?? "No transcript text.")}</p><p>${escapeHtml(turn.assistantReplies.at(-1) ?? "No assistant reply recorded.")}</p></li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
12206
|
+
const providerDecisions = report.operationsRecord.providerDecisions.length ? report.operationsRecord.providerDecisions.slice(0, 12).map((decision) => `<li><strong>${escapeHtml(decision.provider ?? decision.selectedProvider ?? "provider")}</strong><p>${escapeHtml(decision.status ?? "unknown")} ${decision.fallbackProvider ? `via ${escapeHtml(decision.fallbackProvider)}` : ""}</p><p>${escapeHtml(decision.reason ?? "No reason recorded.")}</p></li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
12207
|
+
const failureIssues = report.failureReplay.summary.issues.length ? report.failureReplay.summary.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("") : "<li>No failure or recovery issues recorded.</li>";
|
|
12208
|
+
const heard = report.failureReplay.summary.userHeard.length ? report.failureReplay.summary.userHeard.map((text) => `<li>${escapeHtml(text)}</li>`).join("") : "<li>No assistant output recorded.</li>";
|
|
12225
12209
|
const artifacts = report.snapshot.artifacts.length ? report.snapshot.artifacts.map(renderArtifact).join("") : "<div><strong>No linked artifacts</strong><span>empty</span></div>";
|
|
12226
12210
|
const incidentPath = `/voice-call-debugger/${encodeURIComponent(report.sessionId)}/incident.md`;
|
|
12227
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12211
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0d1216;color:#f8f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,7vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy,.pass{color:#86efac}.warning,.warn,.degraded{color:#fbbf24}.failed,.fail{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(175px,1fr));margin:20px 0}.card,section{background:#161f26;border:1px solid #2b3943;border-radius:20px;padding:16px}.card span,.muted{color:#a9b5bd}.card strong{display:block;font-size:1.8rem;margin-top:4px}section{margin-top:18px}.two{display:grid;gap:18px;grid-template-columns:1fr 1fr}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#0f171d;border:1px solid #2b3943;border-radius:14px;padding:12px}.actions,.artifacts{display:flex;flex-wrap:wrap;gap:10px}.actions a,.artifacts a,.artifacts div{background:#5eead4;border-radius:999px;color:#061014;font-weight:900;padding:10px 14px;text-decoration:none}.artifacts a,.artifacts div{align-items:center;background:#111a20;border:1px solid #2b3943;color:#f8f4e8;display:flex;gap:10px;justify-content:space-between}.artifacts span{color:#5eead4;text-transform:uppercase}pre{background:#090e12;border:1px solid #2b3943;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}@media(max-width:860px){main{padding:20px}.two{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">One-call support artifact</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">${escapeHtml(report.status)}</p><p class="muted">Session <code>${escapeHtml(report.sessionId)}</code>. Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}.</p><div class="actions"><a href="/api/voice-call-debugger/${encodeURIComponent(report.sessionId)}">JSON</a><a href="${escapeHtml(incidentPath)}">Incident markdown</a>${report.failureReplay.operationsRecordHref ? `<a href="${escapeHtml(report.failureReplay.operationsRecordHref)}">Operations record</a>` : ""}</div><section class="grid">${renderMetric("Snapshot", report.snapshot.status)}${renderMetric("Events", report.operationsRecord.summary.eventCount)}${renderMetric("Turns", report.operationsRecord.summary.turnCount)}${renderMetric("Errors", report.operationsRecord.summary.errorCount)}${renderMetric("Provider recovery", report.operationsRecord.providerDecisionSummary.recoveryStatus)}${renderMetric("Fallbacks", report.operationsRecord.providerDecisionSummary.fallbacks)}${renderMetric("Media warnings", report.snapshot.media.filter((media) => media.report.status !== "pass").length)}${renderMetric("Telephony media", report.operationsRecord.telephonyMedia.total)}</section><section><h2>Linked Debug Artifacts</h2><div class="artifacts">${artifacts}</div></section><section class="two"><div><h2>Provider Decisions</h2><ul>${providerDecisions}</ul></div><div><h2>Failure Replay</h2><ul>${failureIssues}</ul><h3>User Heard</h3><ul>${heard}</ul></div></section><section><h2>Transcript</h2><ul>${transcript}</ul></section><section><h2>Copyable Incident Handoff</h2><pre><code>${escapeHtml(report.incidentMarkdown)}</code></pre></section></main></body></html>`;
|
|
12228
12212
|
};
|
|
12229
12213
|
var createVoiceCallDebuggerRoutes = (options) => {
|
|
12230
12214
|
const path = options.path ?? "/api/voice-call-debugger/:sessionId";
|
|
@@ -13403,7 +13387,6 @@ var assertVoiceCampaignReadinessEvidence = (report, input = {}) => {
|
|
|
13403
13387
|
}
|
|
13404
13388
|
return assertion;
|
|
13405
13389
|
};
|
|
13406
|
-
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13407
13390
|
var getString8 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
13408
13391
|
var campaignAttemptSessionId = (attempt) => getString8(attempt.metadata?.sessionId) ?? getString8(attempt.metadata?.voiceSessionId) ?? getString8(attempt.metadata?.callSessionId);
|
|
13409
13392
|
var resolveCampaignOperationsRecordHref = (value, input) => {
|
|
@@ -13421,7 +13404,7 @@ var resolveCampaignOperationsRecordHref = (value, input) => {
|
|
|
13421
13404
|
};
|
|
13422
13405
|
var renderVoiceCampaignsHTML = (records, options = {}) => {
|
|
13423
13406
|
const title = options.title ?? "Voice Campaigns";
|
|
13424
|
-
const rows = records.map((record) => `<tr><td>${
|
|
13407
|
+
const rows = records.map((record) => `<tr><td>${escapeHtml(record.campaign.name)}</td><td>${escapeHtml(record.campaign.status)}</td><td>${String(record.recipients.length)}</td><td>${String(record.attempts.length)}</td><td>${new Date(record.campaign.updatedAt).toLocaleString()}</td></tr>`).join("");
|
|
13425
13408
|
const summary = summarizeVoiceCampaigns(records);
|
|
13426
13409
|
const attemptRows = records.flatMap((record) => record.attempts.slice(-8).reverse().map((attempt) => {
|
|
13427
13410
|
const recipient = record.recipients.find((item) => item.id === attempt.recipientId);
|
|
@@ -13432,15 +13415,15 @@ var renderVoiceCampaignsHTML = (records, options = {}) => {
|
|
|
13432
13415
|
recipient,
|
|
13433
13416
|
sessionId
|
|
13434
13417
|
});
|
|
13435
|
-
return `<tr><td>${
|
|
13418
|
+
return `<tr><td>${escapeHtml(record.campaign.name)}</td><td>${escapeHtml(attempt.status)}</td><td>${escapeHtml(recipient?.phone ?? attempt.recipientId)}</td><td>${escapeHtml(sessionId ?? "")}</td><td>${href ? `<a href="${escapeHtml(href)}">Open operations record</a>` : ""}</td></tr>`;
|
|
13436
13419
|
})).slice(0, 20).join("");
|
|
13437
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13420
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero{background:linear-gradient(135deg,rgba(251,146,60,.18),rgba(45,212,191,.12));border:1px solid #334155;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#fdba74;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.grid article,table{background:#172033;border:1px solid #334155;border-radius:18px}.grid article{padding:16px}.grid span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0}table{border-collapse:collapse;margin-top:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #334155;padding:12px;text-align:left}a{color:#fdba74}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted outbound</p><h1>${escapeHtml(title)}</h1><p>Campaign orchestration, recipients, attempts, retries, and outcomes without a hosted dialer dashboard.</p><section class="grid"><article><span>Campaigns</span><strong>${String(summary.campaigns.total)}</strong></article><article><span>Recipients</span><strong>${String(summary.recipients.total)}</strong></article><article><span>Attempts</span><strong>${String(summary.attempts.total)}</strong></article><article><span>Running</span><strong>${String(summary.campaigns.running)}</strong></article></section></section><table><thead><tr><th>Name</th><th>Status</th><th>Recipients</th><th>Attempts</th><th>Updated</th></tr></thead><tbody>${rows || '<tr><td colspan="5">No campaigns yet.</td></tr>'}</tbody></table><h2>Recent attempts</h2><table><thead><tr><th>Campaign</th><th>Status</th><th>Recipient</th><th>Session</th><th>Debug</th></tr></thead><tbody>${attemptRows || '<tr><td colspan="5">No attempts yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
13438
13421
|
};
|
|
13439
13422
|
var renderVoiceCampaignObservabilityHTML = (report, options = {}) => {
|
|
13440
13423
|
const title = options.title ?? "Voice Campaign Observability";
|
|
13441
|
-
const campaignRows = report.campaigns.map((campaign) => `<tr><td>${
|
|
13442
|
-
const failureRows = report.failureReasons.map((failure) => `<tr><td>${
|
|
13443
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13424
|
+
const campaignRows = report.campaigns.map((campaign) => `<tr><td>${escapeHtml(campaign.name)}</td><td>${escapeHtml(campaign.status)}</td><td>${String(campaign.queueDepth)}</td><td>${String(campaign.activeAttempts)}</td><td>${String(campaign.stuckRecipients + campaign.stuckAttempts)}</td><td>${campaign.lease ? escapeHtml(campaign.lease.workerId) : "none"}</td></tr>`).join("");
|
|
13425
|
+
const failureRows = report.failureReasons.map((failure) => `<tr><td>${escapeHtml(failure.reason)}</td><td>${String(failure.count)}</td></tr>`).join("");
|
|
13426
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0b1220;color:#e5edf7;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(20,184,166,.2),rgba(251,146,60,.14));border:1px solid #334155;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.2rem,5vw,4.6rem);line-height:.95;margin:.2rem 0 1rem}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));margin:18px 0}.card,table{background:#111c2f;border:1px solid #334155;border-radius:18px}.card{padding:16px}.card span{color:#9fb0c5}.card strong{display:block;font-size:2rem;margin:.25rem 0}table{border-collapse:collapse;margin-top:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #334155;padding:12px;text-align:left}.warn{color:#fde68a}.bad{color:#fecaca}</style></head><body><main><section class="hero"><p class="eyebrow">Campaign ops</p><h1>${escapeHtml(title)}</h1><p>Queue depth, active leases, attempt rates, failure reasons, and stuck work for self-hosted outbound voice.</p><section class="grid"><article class="card"><span>Queued recipients</span><strong>${String(report.queue.queuedRecipients)}</strong></article><article class="card"><span>Active attempts</span><strong>${String(report.queue.activeAttempts)}</strong></article><article class="card"><span>Running campaigns</span><strong>${String(report.queue.runningCampaigns)}</strong></article><article class="card"><span>Active leases</span><strong>${report.leases.known ? String(report.leases.active) : "n/a"}</strong></article><article class="card"><span>Attempts/window</span><strong>${String(report.attemptRate.started)}</strong></article><article class="card"><span>Stuck work</span><strong class="${report.stuck.attempts.length + report.stuck.recipients.length > 0 ? "bad" : ""}">${String(report.stuck.attempts.length + report.stuck.recipients.length)}</strong></article></section></section><h2>Campaigns</h2><table><thead><tr><th>Name</th><th>Status</th><th>Queued</th><th>Active</th><th>Stuck</th><th>Lease</th></tr></thead><tbody>${campaignRows || '<tr><td colspan="6">No campaigns yet.</td></tr>'}</tbody></table><h2>Failure Reasons</h2><table><thead><tr><th>Reason</th><th>Count</th></tr></thead><tbody>${failureRows || '<tr><td colspan="2">No failures recorded.</td></tr>'}</tbody></table></main></body></html>`;
|
|
13444
13427
|
};
|
|
13445
13428
|
var readJsonBody = async (request) => {
|
|
13446
13429
|
const text = await request.text();
|
|
@@ -13484,7 +13467,6 @@ var createVoiceCampaignRoutes = (options) => {
|
|
|
13484
13467
|
|
|
13485
13468
|
// src/competitiveCoverage.ts
|
|
13486
13469
|
import { Elysia as Elysia15 } from "elysia";
|
|
13487
|
-
var escapeHtml18 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13488
13470
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
13489
13471
|
var resolveSurfaceStatus = (surface) => {
|
|
13490
13472
|
if (surface.status)
|
|
@@ -13652,24 +13634,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
13652
13634
|
`);
|
|
13653
13635
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
13654
13636
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
13655
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
13656
|
-
return `<article class="surface ${
|
|
13657
|
-
<header><div><p class="eyebrow">${
|
|
13658
|
-
<p>${
|
|
13637
|
+
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${escapeHtml(item.name)}</strong>${item.kind ? ` <span>${escapeHtml(item.kind)}</span>` : ""}${item.status ? ` <em>${escapeHtml(item.status)}</em>` : ""}${item.href ? ` <a href="${escapeHtml(item.href)}">open</a>` : ""}</li>`).join("");
|
|
13638
|
+
return `<article class="surface ${escapeHtml(surface.status)} ${escapeHtml(surface.depth)}">
|
|
13639
|
+
<header><div><p class="eyebrow">${escapeHtml(surface.coverage)} \xB7 ${escapeHtml(surface.depth)}</p><h2>${escapeHtml(surface.surface)}</h2></div><strong>${escapeHtml(surface.status)}</strong></header>
|
|
13640
|
+
<p>${escapeHtml(surface.why)}</p>
|
|
13659
13641
|
<dl>
|
|
13660
|
-
<div><dt>Competitors</dt><dd>${
|
|
13661
|
-
<div><dt>Operations record</dt><dd>${
|
|
13662
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
13663
|
-
<div><dt>Frameworks</dt><dd>${
|
|
13642
|
+
<div><dt>Competitors</dt><dd>${escapeHtml((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
13643
|
+
<div><dt>Operations record</dt><dd>${escapeHtml(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
13644
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml(surface.readinessGate ?? "unknown")}</dd></div>
|
|
13645
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
13664
13646
|
</dl>
|
|
13665
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
13666
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
13647
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml(surface.remainingGap)}</p>` : ""}
|
|
13648
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml(surface.nextMove)}</p>` : ""}
|
|
13667
13649
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
13668
13650
|
</article>`;
|
|
13669
13651
|
}).join(`
|
|
13670
13652
|
`);
|
|
13671
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
13672
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13653
|
+
const issueList = report.issues.map((issue) => `<li class="${escapeHtml(issue.severity)}"><strong>${escapeHtml(issue.code)}</strong>${issue.surface ? ` ${escapeHtml(issue.surface)}` : ""}: ${escapeHtml(issue.message)}</li>`).join("");
|
|
13654
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0e1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.surface,.issues{background:#17201c;border:1px solid #2e3c35;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.16),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.surfaces{display:grid;gap:14px}.surface header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.surface.pass{border-color:rgba(34,197,94,.55)}.surface.warn{border-color:rgba(245,158,11,.72)}.surface.fail{border-color:rgba(239,68,68,.75)}.surface.advantage h2{color:#bbf7d0}.surface.intentional-gap h2{color:#cbd5e1}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}dt{color:#9fb0a8;font-size:.8rem;font-weight:800}dd{margin:0;overflow-wrap:anywhere}.gap{color:#fde68a}.next{color:#bfdbfe}.muted{color:#a8b5ad}a{color:#5eead4}.issues li{margin:.4rem 0}.issues .error{color:#fecaca}.issues .warning{color:#fde68a}@media(max-width:760px){main{padding:18px}.surface header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted market proof</p><h1>${escapeHtml(title)}</h1><p>Generated ${escapeHtml(report.generatedAt)}. This report scores whether AbsoluteJS Voice merely covers a hosted-platform buyer surface or beats it for a code-owned/self-hosted buyer.</p><div class="summary"><span class="pill">Status ${escapeHtml(report.status)}</span><span class="pill">Vapi-style ${escapeHtml(report.vapiCoverageEstimate)}</span><span class="pill">Market ${escapeHtml(report.marketCoverageEstimate)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.advantage)} advantage</span><span class="pill">${String(report.summary.intentionalGaps)} intentional gaps</span></div></section><section class="issues"><h2>Issues</h2><ul>${issueList || "<li>No issues.</li>"}</ul></section><section class="surfaces">${surfaceCards || '<article class="surface"><p>No competitive surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
13673
13655
|
};
|
|
13674
13656
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
13675
13657
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -13953,7 +13935,6 @@ var parseRetentionScopes = (value) => {
|
|
|
13953
13935
|
const allowed = new Set(allRetentionScopes);
|
|
13954
13936
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
13955
13937
|
};
|
|
13956
|
-
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13957
13938
|
var buildStorageSurfaces = (options) => [
|
|
13958
13939
|
{
|
|
13959
13940
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -14190,12 +14171,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
14190
14171
|
zeroRetentionAvailable: true
|
|
14191
14172
|
};
|
|
14192
14173
|
};
|
|
14193
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
14174
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml(scope.skippedReason ?? "")}</td><td><code>${escapeHtml(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
14194
14175
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
14195
14176
|
const title = options.title ?? "Voice Data Control";
|
|
14196
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
14197
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
14198
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
14177
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
14178
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml(key.name)}</td><td><code>${escapeHtml(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml(key.recommendation)}</td></tr>`).join("");
|
|
14179
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1120px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml(title)}</h1><p>Self-hosted data-control proof for retention, redaction, audit export, deletion planning, customer-owned storage, and provider key handling.</p><section class="summary"><div class="card"><strong>Redaction</strong><br>${report.redaction.enabled ? "enabled" : "disabled"}</div><div class="card"><strong>Retention dry-run deletes</strong><br>${report.retentionPlan.deletedCount}</div><div class="card"><strong>Audit export events</strong><br>${report.auditExport?.events.length ?? 0}</div><div class="card"><strong>Zero retention recipe</strong><br>${report.zeroRetentionAvailable ? "available" : "missing"}</div></section><h2>Customer-Owned Storage</h2><table><thead><tr><th>Surface</th><th>Status</th><th>Control</th><th>Self-hosted</th></tr></thead><tbody>${storageRows}</tbody></table><h2>Retention Plan</h2><table><thead><tr><th>Scope</th><th>Scanned</th><th>Would delete</th><th>Skipped</th><th>Ids</th></tr></thead><tbody>${renderDataRetentionReportRows(report.retentionPlan)}</tbody></table><h2>Provider Keys</h2><table><thead><tr><th>Provider</th><th>Env</th><th>Required</th><th>Recommendation</th></tr></thead><tbody>${keyRows}</tbody></table><p><a href="./data-control/audit.md">Redacted audit Markdown</a> \xB7 <a href="./data-control/audit.html">Redacted audit HTML</a></p></main></body></html>`;
|
|
14199
14180
|
};
|
|
14200
14181
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
14201
14182
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -15275,12 +15256,11 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
15275
15256
|
};
|
|
15276
15257
|
|
|
15277
15258
|
// src/deliveryRuntime.ts
|
|
15278
|
-
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15279
15259
|
var renderSummaryCard = (label, summary) => {
|
|
15280
15260
|
if (!summary) {
|
|
15281
|
-
return `<article><span>${
|
|
15261
|
+
return `<article><span>${escapeHtml(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
15282
15262
|
}
|
|
15283
|
-
return `<article><span>${
|
|
15263
|
+
return `<article><span>${escapeHtml(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending · ${String(summary.failed)} failed · ${String(summary.deadLettered)} dead-lettered</p></article>`;
|
|
15284
15264
|
};
|
|
15285
15265
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
15286
15266
|
audit: leases,
|
|
@@ -15491,9 +15471,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
15491
15471
|
});
|
|
15492
15472
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
15493
15473
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
15494
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
15495
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
15496
|
-
const snippet =
|
|
15474
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
15475
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
15476
|
+
const snippet = escapeHtml(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
15497
15477
|
createVoiceDeliveryRuntimePresetConfig({
|
|
15498
15478
|
audit: {
|
|
15499
15479
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -15519,7 +15499,7 @@ app.use(
|
|
|
15519
15499
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
15520
15500
|
})
|
|
15521
15501
|
);`);
|
|
15522
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15502
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;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}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}.primitive{background:#111a15;border-color:#41604a}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}.primitive p{color:#c8d8ca;line-height:1.55}.primitive code{color:#bbf7d0}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceDeliveryRuntimeRoutes(...)</code> builds this control plane</h2><p>Own the audit and trace delivery queues in your app, mount one runtime route group, and pass the same runtime into production readiness so failed or dead-lettered exports block deploys.</p><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
15523
15503
|
};
|
|
15524
15504
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
15525
15505
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
@@ -15562,9 +15542,20 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
15562
15542
|
return routes;
|
|
15563
15543
|
};
|
|
15564
15544
|
|
|
15545
|
+
// src/internal/status.ts
|
|
15546
|
+
var voiceStatusRank = (status) => status === "fail" ? 2 : status === "warn" ? 1 : 0;
|
|
15547
|
+
var worstVoiceStatus = (statuses) => {
|
|
15548
|
+
let worst = "pass";
|
|
15549
|
+
for (const status of statuses) {
|
|
15550
|
+
if (voiceStatusRank(status) > voiceStatusRank(worst)) {
|
|
15551
|
+
worst = status;
|
|
15552
|
+
}
|
|
15553
|
+
}
|
|
15554
|
+
return worst;
|
|
15555
|
+
};
|
|
15556
|
+
|
|
15565
15557
|
// src/deliverySinkRoutes.ts
|
|
15566
15558
|
import { Elysia as Elysia18 } from "elysia";
|
|
15567
|
-
var escapeHtml21 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15568
15559
|
var deliveryStatus = (summary) => {
|
|
15569
15560
|
if (!summary) {
|
|
15570
15561
|
return "warn";
|
|
@@ -15582,7 +15573,7 @@ var rollupDeliverySinkStatus = (report) => {
|
|
|
15582
15573
|
deliveryStatus(report.auditDeliveries?.summary),
|
|
15583
15574
|
deliveryStatus(report.traceDeliveries?.summary)
|
|
15584
15575
|
];
|
|
15585
|
-
return
|
|
15576
|
+
return worstVoiceStatus(statuses);
|
|
15586
15577
|
};
|
|
15587
15578
|
var deliverySinkLabel = (kind) => `${String(kind).replaceAll(/[-_]+/g, " ")} sink`;
|
|
15588
15579
|
var createVoiceDeliverySinkDescriptor = (input) => ({
|
|
@@ -15663,13 +15654,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
15663
15654
|
return "";
|
|
15664
15655
|
}
|
|
15665
15656
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
15666
|
-
const body = `<span>${
|
|
15667
|
-
return `<article>${surface.href ? `<a href="${
|
|
15657
|
+
const body = `<span>${escapeHtml(surface.label)}</span><strong>${escapeHtml(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
15658
|
+
return `<article>${surface.href ? `<a href="${escapeHtml(surface.href)}">${body}</a>` : body}</article>`;
|
|
15668
15659
|
};
|
|
15669
15660
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
15670
15661
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
15671
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
15672
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15662
|
+
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${escapeHtml(sink.kind)}</span><strong style="font-size:1.5rem">${escapeHtml(sink.label)}</strong>${sink.description ? `<p class="muted">${escapeHtml(sink.description)}</p>` : ""}${sink.mode ? `<p class="muted">Mode: ${escapeHtml(sink.mode)}</p>` : ""}${sink.target ? `<p class="muted">Target: <code>${escapeHtml(sink.target)}</code></p>` : ""}${sink.href ? `<p><a href="${escapeHtml(sink.href)}">Open sink</a></p>` : ""}</article>`).join("") : '<article><span>Sink</span><strong style="font-size:1.5rem">Not described</strong><p class="muted">Pass sink descriptors to document your file, webhook, S3, SQLite, or Postgres targets.</p></article>';
|
|
15663
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#11120d;color:#fbf7e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{max-width:1120px;margin:auto;padding:32px}a{color:#fde68a;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(253,230,138,.2),rgba(34,197,94,.14));border:1px solid #3a3420;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fde68a;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.65)}.status.fail{border-color:rgba(239,68,68,.75)}.muted{color:#b8b093}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#191a13;border:1px solid #33311f;border-radius:22px;padding:18px}article span{color:#b8b093;display:block;font-weight:800}article strong{display:block;font-size:2.4rem;margin-top:8px}pre{background:#0c0d09;border:1px solid #33311f;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}code{color:#fef3c7}</style></head><body><main><p><a href="/production-readiness">Production readiness</a></p><section class="hero"><p class="eyebrow">Composable sink primitive</p><h1>${escapeHtml(title)}</h1><p class="muted">Delivery queues prove audit and trace exports without owning your infrastructure. Swap file, webhook, S3, SQLite, or Postgres sinks behind the same readiness surface.</p><p class="status ${escapeHtml(report.status)}">Overall: ${escapeHtml(report.status.toUpperCase())}</p><p class="muted">Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}</p></section><section class="grid">${renderSurfaceCard(report.auditDeliveries)}${renderSurfaceCard(report.traceDeliveries)}${sinks}</section><section class="card"><h2>Primitive shape</h2><p class="muted">Mount delivery sink routes beside audit and trace delivery queues. Production readiness can consume the same stores for pass/fail evidence.</p><pre>createVoiceDeliverySinkRoutes({
|
|
15673
15664
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
15674
15665
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
15675
15666
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -15701,8 +15692,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
15701
15692
|
|
|
15702
15693
|
// src/demoReadyRoutes.ts
|
|
15703
15694
|
import { Elysia as Elysia19 } from "elysia";
|
|
15704
|
-
var
|
|
15705
|
-
var rollupStatus = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
15695
|
+
var rollupStatus = (sections) => worstVoiceStatus(sections.map((section) => section.status));
|
|
15706
15696
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
15707
15697
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
15708
15698
|
const query = input.query ?? {};
|
|
@@ -15785,12 +15775,12 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
15785
15775
|
};
|
|
15786
15776
|
};
|
|
15787
15777
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
15788
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
15789
|
-
<div><span>${
|
|
15790
|
-
<strong>${
|
|
15791
|
-
${section.href ? `<a href="${
|
|
15778
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml(section.status)}">
|
|
15779
|
+
<div><span>${escapeHtml(section.status.toUpperCase())}</span><h2>${escapeHtml(section.label)}</h2>${section.description ? `<p>${escapeHtml(section.description)}</p>` : ""}</div>
|
|
15780
|
+
<strong>${escapeHtml(String(section.value ?? section.status))}</strong>
|
|
15781
|
+
${section.href ? `<a href="${escapeHtml(section.href)}">Open</a>` : ""}
|
|
15792
15782
|
</article>`).join("");
|
|
15793
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15783
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(report.title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;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}.sections{display:grid;gap:14px}.section{align-items:center;background:#151d26;border:1px solid #283544;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.section span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.section h2{margin:.2rem 0}.section p{color:#b9c0c8;margin:.2rem 0 0}.section strong{font-size:1.4rem}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.65)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}@media(max-width:760px){main{padding:20px}.section{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Demo readiness</p><h1>${escapeHtml(report.title)}</h1><p>One customer-facing checklist for the self-hosted voice proof surfaces: ops status, production readiness, phone setup, and phone smoke traces.</p><p class="status ${escapeHtml(report.status)}">Overall: ${escapeHtml(report.status.toUpperCase())}</p><p>Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}</p></section><section class="sections">${sections || '<article class="section warn"><div><span>WARN</span><h2>No checks configured</h2><p>Add ops status, production readiness, phone setup, or phone smoke loaders.</p></div><strong>warn</strong></article>'}</section></main></body></html>`;
|
|
15794
15784
|
};
|
|
15795
15785
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
15796
15786
|
const path = options.path ?? "/api/demo-ready";
|
|
@@ -15819,7 +15809,6 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
15819
15809
|
|
|
15820
15810
|
// src/diagnosticsRoutes.ts
|
|
15821
15811
|
import { Elysia as Elysia20 } from "elysia";
|
|
15822
|
-
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15823
15812
|
var getString9 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
15824
15813
|
var getNumber6 = (value) => {
|
|
15825
15814
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
|
|
@@ -15888,9 +15877,9 @@ var renderDiagnosticsIndex = (input) => {
|
|
|
15888
15877
|
const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
|
|
15889
15878
|
const summary = summarizeVoiceTrace(events);
|
|
15890
15879
|
const encoded = encodeURIComponent(sessionId);
|
|
15891
|
-
return `<tr><td>${
|
|
15880
|
+
return `<tr><td>${escapeHtml(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
|
|
15892
15881
|
}).join("");
|
|
15893
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15882
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
15894
15883
|
};
|
|
15895
15884
|
var withRedaction = (events, query, defaultRedact) => {
|
|
15896
15885
|
const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean2(query.redact);
|
|
@@ -15966,7 +15955,6 @@ import { Elysia as Elysia22 } from "elysia";
|
|
|
15966
15955
|
|
|
15967
15956
|
// src/handoffHealth.ts
|
|
15968
15957
|
import { Elysia as Elysia21 } from "elysia";
|
|
15969
|
-
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15970
15958
|
var getString10 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15971
15959
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
15972
15960
|
var increment4 = (record, key) => {
|
|
@@ -16084,10 +16072,10 @@ var renderActionSummary = (summary) => {
|
|
|
16084
16072
|
return [
|
|
16085
16073
|
'<section class="voice-handoff-health-columns">',
|
|
16086
16074
|
"<article><h3>Actions</h3>",
|
|
16087
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
16075
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
16088
16076
|
"</article>",
|
|
16089
16077
|
"<article><h3>Adapters</h3>",
|
|
16090
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
16078
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
16091
16079
|
"</article>",
|
|
16092
16080
|
"</section>"
|
|
16093
16081
|
].join("");
|
|
@@ -16101,22 +16089,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
16101
16089
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
16102
16090
|
'<div class="voice-handoff-health-events">',
|
|
16103
16091
|
...summary.events.map((event) => [
|
|
16104
|
-
`<article class="${
|
|
16092
|
+
`<article class="${escapeHtml(event.status)}">`,
|
|
16105
16093
|
'<div class="voice-handoff-health-event-header">',
|
|
16106
|
-
`<strong>${
|
|
16107
|
-
`<span>${
|
|
16094
|
+
`<strong>${escapeHtml(event.action ?? "handoff")}</strong>`,
|
|
16095
|
+
`<span>${escapeHtml(event.status)}</span>`,
|
|
16108
16096
|
"</div>",
|
|
16109
|
-
`<p><small>${
|
|
16110
|
-
event.target ? `<p>Target: ${
|
|
16111
|
-
event.reason ? `<p>Reason: ${
|
|
16097
|
+
`<p><small>${escapeHtml(event.sessionId)}</small></p>`,
|
|
16098
|
+
event.target ? `<p>Target: ${escapeHtml(event.target)}</p>` : "",
|
|
16099
|
+
event.reason ? `<p>Reason: ${escapeHtml(event.reason)}</p>` : "",
|
|
16112
16100
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
16113
16101
|
"<li>",
|
|
16114
|
-
`${
|
|
16115
|
-
delivery.deliveredTo ? ` to ${
|
|
16116
|
-
delivery.error ? ` (${
|
|
16102
|
+
`${escapeHtml(delivery.adapterId)}: ${escapeHtml(delivery.status)}`,
|
|
16103
|
+
delivery.deliveredTo ? ` to ${escapeHtml(delivery.deliveredTo)}` : "",
|
|
16104
|
+
delivery.error ? ` (${escapeHtml(delivery.error)})` : "",
|
|
16117
16105
|
"</li>"
|
|
16118
16106
|
].join("")).join("")}</ul>` : "",
|
|
16119
|
-
event.replayHref ? `<p><a href="${
|
|
16107
|
+
event.replayHref ? `<p><a href="${escapeHtml(event.replayHref)}">Open replay</a></p>` : "",
|
|
16120
16108
|
"</article>"
|
|
16121
16109
|
].join("")),
|
|
16122
16110
|
"</div>"
|
|
@@ -16269,12 +16257,11 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
16269
16257
|
thresholds
|
|
16270
16258
|
};
|
|
16271
16259
|
};
|
|
16272
|
-
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16273
16260
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
16274
16261
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
16275
16262
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
16276
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
16277
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16263
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml(metric.label)}</td><td>${escapeHtml(formatMetricValue(metric))}</td><td>${escapeHtml(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml(key)}</code></td></tr>`).join("");
|
|
16264
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
|
|
16278
16265
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>AbsoluteJS Voice Quality</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}nav{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 1.25rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;padding:.35rem .75rem;font-weight:800}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}table{border-collapse:collapse;width:100%;background:white;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}.pass td{border-left:4px solid #16a34a}.fail td{border-left:4px solid #dc2626}code{background:#f3f4f6;padding:.15rem .3rem;border-radius:.3rem}</style></head><body><main>${links}<h1>Voice quality gates</h1><p class="status ${report.status}">${report.status}</p><p>${report.eventCount} event(s) checked.</p><table><thead><tr><th>Metric</th><th>Actual</th><th>Threshold</th><th>Status</th><th>Key</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
16279
16266
|
};
|
|
16280
16267
|
var createVoiceQualityRoutes = (options) => {
|
|
@@ -16308,7 +16295,6 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
16308
16295
|
};
|
|
16309
16296
|
|
|
16310
16297
|
// src/evalRoutes.ts
|
|
16311
|
-
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16312
16298
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
16313
16299
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
16314
16300
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -16639,7 +16625,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
16639
16625
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
16640
16626
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
16641
16627
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
16642
|
-
const snippet =
|
|
16628
|
+
const snippet = escapeHtml(`app.use(
|
|
16643
16629
|
createVoiceEvalRoutes({
|
|
16644
16630
|
path: '/evals',
|
|
16645
16631
|
store: traceStore,
|
|
@@ -16660,44 +16646,44 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
16660
16646
|
};
|
|
16661
16647
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
16662
16648
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
16663
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16664
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
16649
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
|
|
16650
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml(bucket.key)}</td><td>${bucket.total}</td><td>${bucket.passed}</td><td>${bucket.failed}</td></tr>`).join("") : '<tr><td colspan="4">No eval buckets yet.</td></tr>';
|
|
16665
16651
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
16666
16652
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
16667
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16668
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16653
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">${escapeHtml(session.sessionId)}</a>` : escapeHtml(session.sessionId);
|
|
16654
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml(formatTime(session.endedAt))}</td><td>${escapeHtml(failedMetrics || "none")}</td></tr>`;
|
|
16669
16655
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
16670
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16656
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,.primitive{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3;margin:1rem 0}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}<h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
16671
16657
|
};
|
|
16672
16658
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
16673
16659
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
16674
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16675
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
16676
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
16677
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
16678
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16660
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
|
|
16661
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
16662
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml(id)}</li>`).join("") : "<li>none</li>";
|
|
16663
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml(id)}</li>`).join("") : "<li>none</li>";
|
|
16664
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1000px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{background:#dcfce7;color:#166534}.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{background:white;border:1px solid #e7e5e4;border-radius:1rem;margin:1rem 0;padding:1rem}</style></head><body><main>${links}<h1>${escapeHtml(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml(formatPercent(comparison.current.passRate))}</strong></article><article class="card"><span>Failed delta</span><strong>${comparison.deltas.failed}</strong></article><article class="card"><span>Pass rate delta</span><strong>${escapeHtml(formatPercent(comparison.deltas.passRate))}</strong></article></div><section><h2>Regression Reasons</h2><ul>${reasons}</ul></section><section><h2>New Failed Sessions</h2><ul>${newFailures}</ul></section><section><h2>Recovered Sessions</h2><ul>${recovered}</ul></section></main></body></html>`;
|
|
16679
16665
|
};
|
|
16680
16666
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
16681
16667
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
16682
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16668
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
|
|
16683
16669
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
16684
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
16670
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("")}</ul>` : "";
|
|
16685
16671
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
16686
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16687
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16672
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">${escapeHtml(session.sessionId)}</a>` : escapeHtml(session.sessionId);
|
|
16673
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml(session.issues.join(", ") || "none")}</td></tr>`;
|
|
16688
16674
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
16689
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
16675
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml(scenario.description)}</p>` : ""}<p class="status ${scenario.status}">${scenario.status}</p><p>${scenario.passed} passed, ${scenario.failed} failed, ${scenario.matchedSessions} matched.</p>${scenarioIssues}<table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Issues</th></tr></thead><tbody>${sessions}</tbody></table></section>`;
|
|
16690
16676
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
16691
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16677
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${scenarios}</main></body></html>`;
|
|
16692
16678
|
};
|
|
16693
16679
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
16694
16680
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
16695
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16681
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
|
|
16696
16682
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
16697
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
16698
|
-
return `<section class="${fixture.status}"><h2>${
|
|
16683
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml(scenario.label)}</td><td>${escapeHtml(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
16684
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml(fixture.description)}</p>` : ""}<p class="status ${fixture.status}">${fixture.status}</p><table><thead><tr><th>Scenario</th><th>Status</th><th>Sessions</th><th>Issues</th></tr></thead><tbody>${scenarios}</tbody></table></section>`;
|
|
16699
16685
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
16700
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16686
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${fixtures}</main></body></html>`;
|
|
16701
16687
|
};
|
|
16702
16688
|
var createVoiceEvalRoutes = (options) => {
|
|
16703
16689
|
const path = options.path ?? "/evals";
|
|
@@ -17506,7 +17492,6 @@ var wrapVoiceHTMLInHTMXContainer = (html, attrs) => {
|
|
|
17506
17492
|
};
|
|
17507
17493
|
|
|
17508
17494
|
// src/client/htmxDashboardRenderers.ts
|
|
17509
|
-
var escapeHtml27 = (text) => text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17510
17495
|
var formatUsd = (value, currency = "USD") => new Intl.NumberFormat("en-US", {
|
|
17511
17496
|
currency,
|
|
17512
17497
|
maximumFractionDigits: 4,
|
|
@@ -17521,8 +17506,8 @@ var formatRelative = (ms) => {
|
|
|
17521
17506
|
return `${String(minutes).padStart(2, "0")}:${String(remaining).padStart(2, "0")}`;
|
|
17522
17507
|
};
|
|
17523
17508
|
var polledWrapperAttributes = (attrs) => buildVoiceHTMXAttributes(attrs);
|
|
17524
|
-
var renderCostRow = (bucket, currency, isTotal) => `<tr data-bucket-key="${
|
|
17525
|
-
<td style="padding:8px 12px;">${
|
|
17509
|
+
var renderCostRow = (bucket, currency, isTotal) => `<tr data-bucket-key="${escapeHtml(bucket.bucketKey)}" style="${isTotal ? "border-top:2px solid rgba(255,255,255,0.15);font-weight:600;" : ""}">
|
|
17510
|
+
<td style="padding:8px 12px;">${escapeHtml(bucket.bucketKey)}</td>
|
|
17526
17511
|
<td style="padding:8px 12px;text-align:right;">${formatInteger(bucket.callCount)}</td>
|
|
17527
17512
|
<td style="padding:8px 12px;text-align:right;">${formatUsd(bucket.llmUsd, currency)}</td>
|
|
17528
17513
|
<td style="padding:8px 12px;text-align:right;">${formatUsd(bucket.ttsUsd, currency)}</td>
|
|
@@ -17539,7 +17524,7 @@ var defaultCostDashboard = ({
|
|
|
17539
17524
|
}) => {
|
|
17540
17525
|
const body = report.buckets.map((bucket) => renderCostRow(bucket, currency, false)).join("");
|
|
17541
17526
|
const total = renderCostRow(report.grandTotal, currency, true);
|
|
17542
|
-
const inner = report.buckets.length === 0 ? `<p style="font-size:13px;opacity:0.7;">${
|
|
17527
|
+
const inner = report.buckets.length === 0 ? `<p style="font-size:13px;opacity:0.7;">${escapeHtml(emptyMessage)}</p>` : `<table style="border-collapse:collapse;font-size:13px;width:100%;">
|
|
17543
17528
|
<thead><tr style="opacity:0.7;text-align:left;">
|
|
17544
17529
|
<th style="padding:8px 12px;">Bucket</th>
|
|
17545
17530
|
<th style="padding:8px 12px;text-align:right;">Calls</th>
|
|
@@ -17551,7 +17536,7 @@ var defaultCostDashboard = ({
|
|
|
17551
17536
|
</tr></thead><tbody>${body}${total}</tbody></table>`;
|
|
17552
17537
|
return `<section aria-label="voice-cost-dashboard" class="absolute-voice-cost-dashboard"${polledWrapperAttributes(attributes)} style="background:#0f172a;border-radius:16px;color:#f8fafc;font-family:ui-sans-serif,system-ui,sans-serif;padding:20px;">
|
|
17553
17538
|
<header style="align-items:baseline;display:flex;gap:12px;margin-bottom:12px;">
|
|
17554
|
-
<strong style="font-size:16px;">${
|
|
17539
|
+
<strong style="font-size:16px;">${escapeHtml(title)}</strong>
|
|
17555
17540
|
<span style="font-size:13px;opacity:0.7;">${report.buckets.length} buckets \xB7 grand total ${formatUsd(report.grandTotal.totalUsd, currency)}</span>
|
|
17556
17541
|
</header>
|
|
17557
17542
|
${inner}
|
|
@@ -17565,8 +17550,8 @@ var REPLAY_CATEGORY_COLOR = {
|
|
|
17565
17550
|
};
|
|
17566
17551
|
var renderReplayEntry = (event, startedAt) => `<li style="align-items:center;border-left:3px solid ${REPLAY_CATEGORY_COLOR[event.category]};display:flex;font-size:13px;gap:12px;padding-left:12px;">
|
|
17567
17552
|
<span style="color:#cbd5e1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;width:60px;">${formatRelative(event.at - startedAt)}</span>
|
|
17568
|
-
<strong style="font-size:13px;">${
|
|
17569
|
-
${event.detail ? `<span style="opacity:0.85;">${
|
|
17553
|
+
<strong style="font-size:13px;">${escapeHtml(event.label)}</strong>
|
|
17554
|
+
${event.detail ? `<span style="opacity:0.85;">${escapeHtml(event.detail)}</span>` : ""}
|
|
17570
17555
|
</li>`;
|
|
17571
17556
|
var defaultReplayTimeline = ({
|
|
17572
17557
|
attributes,
|
|
@@ -17574,9 +17559,9 @@ var defaultReplayTimeline = ({
|
|
|
17574
17559
|
report,
|
|
17575
17560
|
title
|
|
17576
17561
|
}) => {
|
|
17577
|
-
const headline =
|
|
17562
|
+
const headline = escapeHtml(title ?? report.metadata.title ?? "Replay");
|
|
17578
17563
|
const items = report.events.map((event) => renderReplayEntry(event, report.startedAt)).join("");
|
|
17579
|
-
const inner = report.events.length === 0 ? `<p style="font-size:13px;opacity:0.7;">${
|
|
17564
|
+
const inner = report.events.length === 0 ? `<p style="font-size:13px;opacity:0.7;">${escapeHtml(emptyMessage)}</p>` : `<ol style="display:flex;flex-direction:column;gap:6px;list-style:none;margin:0;padding:0;">${items}</ol>`;
|
|
17580
17565
|
return `<section aria-label="voice-replay-timeline" class="absolute-voice-replay-timeline"${polledWrapperAttributes(attributes)} style="background:#0f172a;border-radius:16px;color:#f8fafc;font-family:ui-sans-serif,system-ui,sans-serif;padding:20px;">
|
|
17581
17566
|
<header style="align-items:baseline;display:flex;gap:12px;margin-bottom:12px;">
|
|
17582
17567
|
<strong style="font-size:16px;">${headline}</strong>
|
|
@@ -17594,8 +17579,8 @@ var LIVE_CATEGORY_COLOR = {
|
|
|
17594
17579
|
};
|
|
17595
17580
|
var renderLiveEntry = (event, firstAt) => `<li style="align-items:center;border-left:3px solid ${LIVE_CATEGORY_COLOR[event.kind] ?? "#94a3b8"};display:flex;font-size:13px;gap:12px;padding-left:12px;">
|
|
17596
17581
|
<span style="color:#cbd5e1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;width:60px;">${formatRelative(event.at - firstAt)}</span>
|
|
17597
|
-
<strong style="font-size:13px;">${
|
|
17598
|
-
${event.detail ? `<span style="opacity:0.85;">${
|
|
17582
|
+
<strong style="font-size:13px;">${escapeHtml(event.title)}</strong>
|
|
17583
|
+
${event.detail ? `<span style="opacity:0.85;">${escapeHtml(event.detail)}</span>` : ""}
|
|
17599
17584
|
</li>`;
|
|
17600
17585
|
var defaultLiveCallViewer = ({
|
|
17601
17586
|
attributes,
|
|
@@ -17604,13 +17589,13 @@ var defaultLiveCallViewer = ({
|
|
|
17604
17589
|
}) => {
|
|
17605
17590
|
const firstAt = state.events[0]?.at ?? Date.now();
|
|
17606
17591
|
const items = state.events.map((event) => renderLiveEntry(event, firstAt)).join("");
|
|
17607
|
-
return `<section aria-label="voice-live-call-viewer" class="absolute-voice-live-call-viewer" data-agent-state="${
|
|
17592
|
+
return `<section aria-label="voice-live-call-viewer" class="absolute-voice-live-call-viewer" data-agent-state="${escapeHtml(state.agentState)}"${polledWrapperAttributes(attributes)} style="background:#0f172a;border-radius:16px;color:#f8fafc;font-family:ui-sans-serif,system-ui,sans-serif;padding:20px;">
|
|
17608
17593
|
<header style="align-items:center;display:flex;gap:12px;margin-bottom:12px;">
|
|
17609
|
-
<strong style="font-size:16px;">${
|
|
17610
|
-
<span style="background:rgba(59,130,246,0.18);border-radius:999px;font-size:11px;padding:3px 10px;text-transform:uppercase;">${
|
|
17611
|
-
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${
|
|
17594
|
+
<strong style="font-size:16px;">${escapeHtml(title)}</strong>
|
|
17595
|
+
<span style="background:rgba(59,130,246,0.18);border-radius:999px;font-size:11px;padding:3px 10px;text-transform:uppercase;">${escapeHtml(state.agentState)}</span>
|
|
17596
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${escapeHtml(state.sessionId)} \xB7 ${formatRelative(state.callDurationMs)}</span>
|
|
17612
17597
|
</header>
|
|
17613
|
-
${state.partialTranscript ? `<p style="background:rgba(16,185,129,0.12);border-radius:12px;font-size:13px;margin:0 0 12px;opacity:0.95;padding:10px 12px;">"${
|
|
17598
|
+
${state.partialTranscript ? `<p style="background:rgba(16,185,129,0.12);border-radius:12px;font-size:13px;margin:0 0 12px;opacity:0.95;padding:10px 12px;">"${escapeHtml(state.partialTranscript)}"</p>` : ""}
|
|
17614
17599
|
<ol style="display:flex;flex-direction:column;gap:6px;list-style:none;margin:0;max-height:320px;overflow-y:auto;padding:0;">${items}</ol>
|
|
17615
17600
|
</section>`;
|
|
17616
17601
|
};
|
|
@@ -18152,14 +18137,12 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
18152
18137
|
total: entries.length
|
|
18153
18138
|
};
|
|
18154
18139
|
};
|
|
18155
|
-
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18156
18140
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
18157
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
18141
|
+
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml(entry.ok ? "success" : "error")}</span><strong>${escapeHtml(entry.actionId)}</strong><p>${escapeHtml(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml(entry.error)}</p>` : ""}</article>`).join("");
|
|
18158
18142
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Ops Action History</title><style>body{background:#11140f;color:#f7f1df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,article{background:#181d15;border:1px solid #2c3327;border-radius:24px;padding:20px}.hero{margin-bottom:16px}h1{font-size:clamp(2rem,6vw,4rem);line-height:.95}section{display:grid;gap:12px}article.ok{border-color:rgba(34,197,94,.55)}article.fail{border-color:rgba(239,68,68,.75)}span{color:#facc15;font-weight:900;text-transform:uppercase}p{color:#c8ccb8}</style></head><body><main><section class="hero"><span>Operator proof</span><h1>Voice Ops Action History</h1><p>${String(report.total)} action(s), ${String(report.failed)} failed.</p></section><section>${rows || "<p>No operator actions have been recorded.</p>"}</section></main></body></html>`;
|
|
18159
18143
|
};
|
|
18160
18144
|
|
|
18161
18145
|
// src/incidentTimeline.ts
|
|
18162
|
-
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18163
18146
|
var resolveValue = async (value) => typeof value === "function" ? await value() : value;
|
|
18164
18147
|
var linkForSession = (link, sessionId) => {
|
|
18165
18148
|
if (!link || !sessionId) {
|
|
@@ -18226,7 +18209,7 @@ var defaultIncidentRecoveryActions = (events, links) => {
|
|
|
18226
18209
|
}
|
|
18227
18210
|
return actions;
|
|
18228
18211
|
};
|
|
18229
|
-
var worstStatus = (statuses) =>
|
|
18212
|
+
var worstStatus = (statuses) => worstVoiceStatus(statuses);
|
|
18230
18213
|
var statusRank2 = (status) => status === "fail" ? 3 : status === "warn" ? 2 : status === "pass" ? 1 : 0;
|
|
18231
18214
|
var isRecord2 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
18232
18215
|
var getIncidentRecoveryBody = (event) => {
|
|
@@ -18280,8 +18263,8 @@ var buildVoiceIncidentRecoveryOutcomeReport = async (options) => {
|
|
|
18280
18263
|
};
|
|
18281
18264
|
var renderVoiceIncidentRecoveryOutcomeHTML = (report, options = {}) => {
|
|
18282
18265
|
const title = options.title ?? "AbsoluteJS Voice Incident Recovery Outcomes";
|
|
18283
|
-
const rows = report.entries.map((entry) => `<article class="${
|
|
18284
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18266
|
+
const rows = report.entries.map((entry) => `<article class="${escapeHtml(entry.outcome)}"><span>${escapeHtml(entry.outcome.toUpperCase())}</span><h2>${escapeHtml(entry.actionId)}</h2><p>${escapeHtml(new Date(entry.at).toLocaleString())}</p><strong>${escapeHtml(entry.beforeStatus ?? "unknown")} -> ${escapeHtml(entry.afterStatus ?? "unknown")}</strong>${entry.detail ? `<p>${escapeHtml(entry.detail)}</p>` : ""}</article>`).join("");
|
|
18267
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#10120d;color:#fbf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,article{background:#181711;border:1px solid #39301d;border-radius:24px;padding:20px}.hero{margin-bottom:16px}h1{font-size:clamp(2rem,6vw,4.5rem);line-height:.95}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{border:1px solid #4a3f23;border-radius:999px;padding:8px 12px}section{display:grid;gap:12px}article.improved{border-color:rgba(34,197,94,.65)}article.failed,article.regressed{border-color:rgba(239,68,68,.8)}article.unchanged{border-color:rgba(245,158,11,.7)}article span{color:#fcd34d;font-weight:900;letter-spacing:.08em}article strong{display:block;font-size:1.4rem;margin:.5rem 0}p{color:#cfc5a8}</style></head><body><main><section class="hero"><span>Recovery proof</span><h1>${escapeHtml(title)}</h1><div class="summary"><span>${String(report.improved)} improved</span><span>${String(report.unchanged)} unchanged</span><span>${String(report.regressed)} regressed</span><span>${String(report.failed)} failed</span><span>${String(report.total)} total</span></div></section><section>${rows || "<p>No incident recovery actions have been recorded.</p>"}</section></main></body></html>`;
|
|
18285
18268
|
};
|
|
18286
18269
|
var buildVoiceIncidentRecoveryOutcomeReadinessCheck = (report, options = {}) => {
|
|
18287
18270
|
const failOnFailed = options.failOnFailed ?? true;
|
|
@@ -18478,8 +18461,8 @@ ${rows || "| n/a | 0 | 0 | 0 | 0 | 0 | n/a | n/a |"}
|
|
|
18478
18461
|
};
|
|
18479
18462
|
var renderVoiceIncidentRecoveryTrendHTML = (report, options = {}) => {
|
|
18480
18463
|
const title = options.title ?? "AbsoluteJS Voice Incident Recovery Trend";
|
|
18481
|
-
const rows = report.cycles.map((cycle) => `<tr><td>${
|
|
18482
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18464
|
+
const rows = report.cycles.map((cycle) => `<tr><td>${escapeHtml(new Date(cycle.checkedAt).toLocaleString())}</td><td>${String(cycle.total)}</td><td>${String(cycle.improved)}</td><td>${String(cycle.unchanged)}</td><td>${String(cycle.regressed)}</td><td>${String(cycle.failed)}</td><td>${escapeHtml(percent(cycle.improvementRate))}</td><td>${escapeHtml(percent(cycle.regressionRate))}</td></tr>`).join("");
|
|
18465
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#10120d;color:#fbf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,table{background:#181711;border:1px solid #39301d;border-radius:24px}.hero{margin-bottom:16px;padding:24px}h1{font-size:clamp(2rem,6vw,4.5rem);line-height:.95}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{border:1px solid #4a3f23;border-radius:999px;padding:8px 12px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #39301d;padding:12px;text-align:left}.pass{color:#86efac}.warn,.empty{color:#fcd34d}.fail{color:#fca5a5}p{color:#cfc5a8}</style></head><body><main><section class="hero"><span>Recovery trend</span><h1>${escapeHtml(title)}</h1><p class="${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><div class="summary"><span>${String(report.summary.cycles)} cycles</span><span>${String(report.summary.total)} actions</span><span>${escapeHtml(percent(report.summary.improvementRate))} improved</span><span>${escapeHtml(percent(report.summary.regressionRate))} regressed</span><span>${escapeHtml(percent(report.trend.improvementRateDelta))} improvement delta</span></div></section><table><thead><tr><th>Checked at</th><th>Total</th><th>Improved</th><th>Unchanged</th><th>Regressed</th><th>Failed</th><th>Improve %</th><th>Regress %</th></tr></thead><tbody>${rows || '<tr><td colspan="8">No recovery outcome history has been recorded.</td></tr>'}</tbody></table></main></body></html>`;
|
|
18483
18466
|
};
|
|
18484
18467
|
var pushOperationalStatusEvents = (events, report, links) => {
|
|
18485
18468
|
if (!report) {
|
|
@@ -18710,22 +18693,22 @@ ${report.actions.map((action) => `- ${action.method ?? "GET"} ${action.id}: ${ac
|
|
|
18710
18693
|
var renderVoiceIncidentTimelineHTML = (report, options = {}) => {
|
|
18711
18694
|
const title = options.title ?? "AbsoluteJS Voice Incident Timeline";
|
|
18712
18695
|
const actionPath = options.actionPath ?? "/api/voice/incident-timeline/actions";
|
|
18713
|
-
const events = report.events.map((event) => `<article class="${
|
|
18714
|
-
<span>${
|
|
18715
|
-
<h2>${
|
|
18716
|
-
<p>${
|
|
18717
|
-
${event.value === undefined ? "" : `<strong>${
|
|
18718
|
-
${event.detail ? `<p>${
|
|
18719
|
-
<div>${event.href ? `<a href="${
|
|
18696
|
+
const events = report.events.map((event) => `<article class="${escapeHtml(event.severity)}">
|
|
18697
|
+
<span>${escapeHtml(event.severity.toUpperCase())} / ${escapeHtml(event.category)}</span>
|
|
18698
|
+
<h2>${escapeHtml(event.label)}</h2>
|
|
18699
|
+
<p>${escapeHtml(new Date(event.at).toLocaleString())}${event.sessionId ? ` \xB7 session ${escapeHtml(event.sessionId)}` : ""}</p>
|
|
18700
|
+
${event.value === undefined ? "" : `<strong>${escapeHtml(String(event.value))}</strong>`}
|
|
18701
|
+
${event.detail ? `<p>${escapeHtml(event.detail)}</p>` : ""}
|
|
18702
|
+
<div>${event.href ? `<a href="${escapeHtml(event.href)}">Open source</a>` : ""}${event.action?.href ? `<a href="${escapeHtml(event.action.href)}">${escapeHtml(event.action.label)}</a>` : ""}</div>
|
|
18720
18703
|
</article>`).join("");
|
|
18721
18704
|
const actions = report.actions.map((action) => {
|
|
18722
|
-
const label =
|
|
18723
|
-
const detail = action.detail ? `<p>${
|
|
18724
|
-
const href = action.href ? `<a href="${
|
|
18725
|
-
const control = action.method === "POST" ? `<button type="button" data-voice-incident-action="${
|
|
18726
|
-
return `<article class="action"><span>${
|
|
18705
|
+
const label = escapeHtml(action.label);
|
|
18706
|
+
const detail = action.detail ? `<p>${escapeHtml(action.detail)}</p>` : "";
|
|
18707
|
+
const href = action.href ? `<a href="${escapeHtml(action.href)}">Open target</a>` : "";
|
|
18708
|
+
const control = action.method === "POST" ? `<button type="button" data-voice-incident-action="${escapeHtml(action.id)}" ${action.disabled ? "disabled" : ""}>${label}</button>` : href;
|
|
18709
|
+
return `<article class="action"><span>${escapeHtml(action.method ?? "GET")}</span><h2>${label}</h2>${detail}<div>${control}${href && action.method === "POST" ? href : ""}</div></article>`;
|
|
18727
18710
|
}).join("");
|
|
18728
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18711
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#11110d;color:#faf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero{background:linear-gradient(135deg,rgba(248,113,113,.2),rgba(245,158,11,.13),rgba(34,197,94,.12));border:1px solid #39301d;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fcd34d;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.75)}.status.fail{border-color:rgba(239,68,68,.85)}.grid{display:grid;gap:14px}.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:0 0 18px}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{background:#181711;border:1px solid #39301d;border-radius:999px;padding:8px 12px}article{background:#181711;border:1px solid #39301d;border-radius:22px;padding:18px}article.critical{border-color:rgba(239,68,68,.85)}article.warn{border-color:rgba(245,158,11,.75)}article.info{border-color:rgba(34,197,94,.55)}article.action{border-color:#5b4a22}article span{color:#fcd34d;font-size:.78rem;font-weight:900;letter-spacing:.08em}article h2{margin:.35rem 0}.muted,article p{color:#cfc5a8}article strong{display:block;font-size:1.3rem;margin:.5rem 0}a{color:#fde68a;margin-right:12px}button{background:#fcd34d;border:0;border-radius:999px;color:#171307;cursor:pointer;font-weight:900;padding:10px 14px}button:disabled{cursor:not-allowed;opacity:.55}</style></head><body><main><section class="hero"><p class="eyebrow">Operational triage</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">Overall: ${escapeHtml(report.status.toUpperCase())}</p><p class="muted">Generated ${escapeHtml(new Date(report.generatedAt).toLocaleString())}</p><div class="summary"><span>${String(report.summary.critical)} critical</span><span>${String(report.summary.warn)} warn</span><span>${String(report.summary.info)} info</span><span>${String(report.summary.total)} total</span></div></section><h2>Recovery actions</h2><section class="actions">${actions || '<article class="action"><span>NONE</span><h2>No recovery actions</h2><p>No executable actions are available for this report.</p></article>'}</section><h2>Timeline</h2><section class="grid">${events || '<article class="info"><span>INFO</span><h2>No incident events</h2><p>No non-pass operational events were found in this window.</p></article>'}</section></main><script>const voiceIncidentActionPath=${JSON.stringify(actionPath)};document.querySelectorAll("[data-voice-incident-action]").forEach((button)=>{button.addEventListener("click",async()=>{const id=button.getAttribute("data-voice-incident-action");if(!id)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(voiceIncidentActionPath+"/"+encodeURIComponent(id),{method:"POST"});button.textContent=response.ok?"Done":"Failed";if(response.ok)setTimeout(()=>location.reload(),700)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1600)}})});</script></body></html>`;
|
|
18729
18712
|
};
|
|
18730
18713
|
var createVoiceIncidentTimelineRoutes = (options) => {
|
|
18731
18714
|
const path = options.path ?? "/api/voice/incident-timeline";
|
|
@@ -18938,7 +18921,6 @@ var createVoiceIncidentTimelineRoutes = (options) => {
|
|
|
18938
18921
|
|
|
18939
18922
|
// src/liveLatency.ts
|
|
18940
18923
|
import { Elysia as Elysia29 } from "elysia";
|
|
18941
|
-
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18942
18924
|
var percentile = (values, percentileValue) => {
|
|
18943
18925
|
if (values.length === 0) {
|
|
18944
18926
|
return;
|
|
@@ -19005,8 +18987,8 @@ await traceStore.append({
|
|
|
19005
18987
|
sessionId,
|
|
19006
18988
|
type: 'client.live_latency'
|
|
19007
18989
|
});`;
|
|
19008
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
19009
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18990
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml(sample.sessionId)}</td><td>${escapeHtml(formatMs3(sample.latencyMs))}</td><td>${escapeHtml(sample.status ?? "unknown")}</td><td>${escapeHtml(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
18991
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;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;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml(formatMs3(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
19010
18992
|
};
|
|
19011
18993
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
19012
18994
|
const path = options.path ?? "/api/live-latency";
|
|
@@ -19373,13 +19355,7 @@ import {
|
|
|
19373
19355
|
summarizeMediaQualityReport as summarizeMediaQualityReport2,
|
|
19374
19356
|
summarizeMediaTransportReport as summarizeMediaTransportReport2
|
|
19375
19357
|
} from "@absolutejs/media";
|
|
19376
|
-
var
|
|
19377
|
-
var statusRank3 = {
|
|
19378
|
-
pass: 0,
|
|
19379
|
-
warn: 1,
|
|
19380
|
-
fail: 2
|
|
19381
|
-
};
|
|
19382
|
-
var worstStatus2 = (statuses) => statuses.reduce((worst, status) => statusRank3[status] > statusRank3[worst] ? status : worst, "pass");
|
|
19358
|
+
var worstStatus2 = (statuses) => worstVoiceStatus(statuses);
|
|
19383
19359
|
var buildVoiceMediaPipelineReport = (options = {}) => {
|
|
19384
19360
|
const frames = options.frames ?? [];
|
|
19385
19361
|
const calibration = buildMediaPipelineCalibrationReport(options);
|
|
@@ -19557,9 +19533,9 @@ var renderVoiceMediaPipelineHTML = (report, title = "Voice Media Pipeline Proof"
|
|
|
19557
19533
|
...report.calibration.issues,
|
|
19558
19534
|
...report.interruption.issues,
|
|
19559
19535
|
...report.quality.issues
|
|
19560
|
-
].map((issue) => `<li class="${
|
|
19561
|
-
const segments = report.vad.segments.map((segment) => `<tr><td>${
|
|
19562
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
19536
|
+
].map((issue) => `<li class="${escapeHtml(issue.severity)}"><strong>${escapeHtml(issue.code)}</strong>: ${escapeHtml(issue.message)}</li>`).join("");
|
|
19537
|
+
const segments = report.vad.segments.map((segment) => `<tr><td>${escapeHtml(segment.segmentId)}</td><td>${escapeHtml(segment.frameCount)}</td><td>${escapeHtml(segment.durationMs ?? "n/a")}</td><td>${escapeHtml(segment.turnId ?? "n/a")}</td></tr>`).join("");
|
|
19538
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}.metric{background:#101814;border:1px solid #2e3d36;border-radius:18px;padding:14px}.metric span{color:#a8b5ad;display:block;font-size:.78rem;text-transform:uppercase}.metric strong{display:block;font-size:1.65rem;margin-top:5px}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:7px 11px}.pass{color:#86efac}.warn,.warning{color:#fde68a}.fail,.error{color:#fecaca}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3d36;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Native media pipeline</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">${escapeHtml(report.status)}</p><p>${escapeHtml(report.surface)}</p><section class="summary"><div class="metric"><span>Frames</span><strong>${String(report.frames)}</strong></div><div class="metric"><span>Input audio</span><strong>${String(report.calibration.inputAudioFrames)}</strong></div><div class="metric"><span>Assistant audio</span><strong>${String(report.calibration.assistantAudioFrames)}</strong></div><div class="metric"><span>Trace linked</span><strong>${String(report.calibration.traceLinkedFrames)}</strong></div><div class="metric"><span>First audio</span><strong>${escapeHtml(report.calibration.firstAudioLatencyMs ?? "n/a")}ms</strong></div><div class="metric"><span>VAD segments</span><strong>${String(report.vad.segments.length)}</strong></div><div class="metric"><span>Media quality</span><strong>${escapeHtml(report.quality.status)}</strong></div><div class="metric"><span>Media gaps</span><strong>${String(report.quality.gapCount)}</strong></div><div class="metric"><span>Media jitter</span><strong>${escapeHtml(report.quality.jitterMs ?? "n/a")}ms</strong></div><div class="metric"><span>Speech ratio</span><strong>${String(report.quality.speechRatio)}</strong></div><div class="metric"><span>Timestamp drift</span><strong>${escapeHtml(report.quality.timestampDriftMs ?? "n/a")}ms</strong></div><div class="metric"><span>Interruptions</span><strong>${String(report.interruption.interruptionFrames)}</strong></div><div class="metric"><span>Processor graph</span><strong>${String(report.processorGraph?.nodes.length ?? 0)} nodes</strong></div><div class="metric"><span>Graph out/drop</span><strong>${String(report.processorGraph?.emittedFrames ?? 0)}/${String(report.processorGraph?.droppedFrames ?? 0)}</strong></div><div class="metric"><span>Resampling</span><strong>${report.calibration.resamplingRequired ? "required" : "not required"}</strong></div><div class="metric"><span>Transport</span><strong>${escapeHtml(report.transport?.state ?? "n/a")}</strong></div><div class="metric"><span>Transport in/out</span><strong>${String(report.transport?.inputFrames ?? 0)}/${String(report.transport?.outputFrames ?? 0)}</strong></div><div class="metric"><span>Backpressure</span><strong>${String(report.transport?.backpressureEvents ?? 0)}</strong></div></section></section><section class="card"><h2>Issues</h2><ul>${issues || '<li class="pass">No media pipeline issues.</li>'}</ul></section><section class="card"><h2>VAD Segments</h2><table><thead><tr><th>Segment</th><th>Frames</th><th>Duration ms</th><th>Turn</th></tr></thead><tbody>${segments || '<tr><td colspan="4">No VAD segments.</td></tr>'}</tbody></table></section></main></body></html>`;
|
|
19563
19539
|
};
|
|
19564
19540
|
var createVoiceMediaPipelineRoutes = (options = {}) => {
|
|
19565
19541
|
const path = options.path ?? "/api/voice/media-pipeline";
|
|
@@ -21756,7 +21732,6 @@ import { Elysia as Elysia44 } from "elysia";
|
|
|
21756
21732
|
|
|
21757
21733
|
// src/resilienceRoutes.ts
|
|
21758
21734
|
import { Elysia as Elysia34 } from "elysia";
|
|
21759
|
-
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21760
21735
|
var getString14 = (value) => typeof value === "string" ? value : undefined;
|
|
21761
21736
|
var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
21762
21737
|
var getBoolean3 = (value) => value === true;
|
|
@@ -21904,13 +21879,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
21904
21879
|
};
|
|
21905
21880
|
var renderProviderCards2 = (title, providers) => {
|
|
21906
21881
|
if (providers.length === 0) {
|
|
21907
|
-
return `<p class="muted">No ${
|
|
21882
|
+
return `<p class="muted">No ${escapeHtml(title)} provider health yet.</p>`;
|
|
21908
21883
|
}
|
|
21909
21884
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
21910
|
-
<article class="card provider ${
|
|
21885
|
+
<article class="card provider ${escapeHtml(provider.status)}">
|
|
21911
21886
|
<div class="card-header">
|
|
21912
|
-
<strong>${
|
|
21913
|
-
<span>${
|
|
21887
|
+
<strong>${escapeHtml(provider.provider)}</strong>
|
|
21888
|
+
<span>${escapeHtml(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
21914
21889
|
</div>
|
|
21915
21890
|
<dl>
|
|
21916
21891
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -21919,7 +21894,7 @@ var renderProviderCards2 = (title, providers) => {
|
|
|
21919
21894
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
21920
21895
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
21921
21896
|
</dl>
|
|
21922
|
-
${provider.lastError ? `<p class="muted">${
|
|
21897
|
+
${provider.lastError ? `<p class="muted">${escapeHtml(provider.lastError)}</p>` : ""}
|
|
21923
21898
|
</article>
|
|
21924
21899
|
`).join("")}</div>`;
|
|
21925
21900
|
};
|
|
@@ -21928,24 +21903,24 @@ var renderTimeline2 = (events) => {
|
|
|
21928
21903
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
21929
21904
|
}
|
|
21930
21905
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
21931
|
-
<article class="card event ${
|
|
21906
|
+
<article class="card event ${escapeHtml(event.status ?? "unknown")}">
|
|
21932
21907
|
<div class="card-header">
|
|
21933
|
-
<strong>${
|
|
21908
|
+
<strong>${escapeHtml(event.kind.toUpperCase())} ${escapeHtml(event.operation ?? "generate")}</strong>
|
|
21934
21909
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
21935
21910
|
</div>
|
|
21936
21911
|
<p>
|
|
21937
|
-
<span class="pill">${
|
|
21938
|
-
<span class="pill">provider: ${
|
|
21939
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
21912
|
+
<span class="pill">${escapeHtml(event.status ?? "unknown")}</span>
|
|
21913
|
+
<span class="pill">provider: ${escapeHtml(event.provider ?? "unknown")}</span>
|
|
21914
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml(event.fallbackProvider)}</span>` : ""}
|
|
21940
21915
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
21941
21916
|
</p>
|
|
21942
21917
|
<dl>
|
|
21943
21918
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
21944
21919
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
21945
21920
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
21946
|
-
<div><dt>Session</dt><dd>${
|
|
21921
|
+
<div><dt>Session</dt><dd>${escapeHtml(event.sessionId)}</dd></div>
|
|
21947
21922
|
</dl>
|
|
21948
|
-
${event.error ? `<p class="muted">${
|
|
21923
|
+
${event.error ? `<p class="muted">${escapeHtml(event.error)}</p>` : ""}
|
|
21949
21924
|
</article>
|
|
21950
21925
|
`).join("")}</div>`;
|
|
21951
21926
|
};
|
|
@@ -21955,9 +21930,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
21955
21930
|
const status = latest?.status ?? "idle";
|
|
21956
21931
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
21957
21932
|
return `<div>
|
|
21958
|
-
<dt>${
|
|
21959
|
-
<dd>${
|
|
21960
|
-
<small>${
|
|
21933
|
+
<dt>${escapeHtml(kind.toUpperCase())}</dt>
|
|
21934
|
+
<dd>${escapeHtml(provider)}${escapeHtml(fallback)}</dd>
|
|
21935
|
+
<small>${escapeHtml(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
|
|
21961
21936
|
</div>`;
|
|
21962
21937
|
};
|
|
21963
21938
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -21965,10 +21940,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
21965
21940
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
21966
21941
|
}
|
|
21967
21942
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
21968
|
-
<article class="card session ${
|
|
21943
|
+
<article class="card session ${escapeHtml(session.status)}">
|
|
21969
21944
|
<div class="card-header">
|
|
21970
|
-
<strong>${
|
|
21971
|
-
<span>${
|
|
21945
|
+
<strong>${escapeHtml(session.sessionId)}</strong>
|
|
21946
|
+
<span>${escapeHtml(session.status)}</span>
|
|
21972
21947
|
</div>
|
|
21973
21948
|
<p>
|
|
21974
21949
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -21995,21 +21970,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
21995
21970
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
21996
21971
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
21997
21972
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
21998
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
21999
|
-
<p class="muted">${
|
|
21973
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml(pathPrefix)}">
|
|
21974
|
+
<p class="muted">${escapeHtml(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
22000
21975
|
<div class="simulate-actions">
|
|
22001
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
22002
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
21976
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
21977
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml(provider.provider)}">Mark ${escapeHtml(provider.provider)} recovered</button>`).join("")}
|
|
22003
21978
|
</div>
|
|
22004
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
21979
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
22005
21980
|
<pre class="simulate-output" hidden></pre>
|
|
22006
21981
|
</div>`;
|
|
22007
21982
|
};
|
|
22008
21983
|
var renderVoiceResilienceHTML = (input) => {
|
|
22009
21984
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
22010
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
22011
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
22012
|
-
const snippet =
|
|
21985
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml(kind)}: ${String(count)}</span>`).join("");
|
|
21986
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join(" \xB7 ") : "";
|
|
21987
|
+
const snippet = escapeHtml(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
22013
21988
|
kind: 'stt',
|
|
22014
21989
|
providers: ['deepgram', 'assemblyai'],
|
|
22015
21990
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -22047,7 +22022,7 @@ app.use(
|
|
|
22047
22022
|
<head>
|
|
22048
22023
|
<meta charset="utf-8" />
|
|
22049
22024
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
22050
|
-
<title>${
|
|
22025
|
+
<title>${escapeHtml(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
22051
22026
|
<style>
|
|
22052
22027
|
:root { color-scheme: dark; }
|
|
22053
22028
|
body { background: radial-gradient(circle at top left, #172554, #09090b 36%, #050505); color: #f4f4f5; font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; }
|
|
@@ -22323,7 +22298,6 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
22323
22298
|
};
|
|
22324
22299
|
|
|
22325
22300
|
// src/telephony/matrix.ts
|
|
22326
|
-
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22327
22301
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
22328
22302
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
22329
22303
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -22384,13 +22358,13 @@ var badgeStyles = {
|
|
|
22384
22358
|
};
|
|
22385
22359
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
22386
22360
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
22387
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
22361
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
22388
22362
|
<p style="color:#52606d; margin: 0 0 24px;">${matrix.summary.ready}/${matrix.summary.providers} ready, ${matrix.summary.contractsPassing}/${matrix.summary.providers} contract passing, ${matrix.summary.smokePassing}/${matrix.summary.providers} smoke passing.</p>
|
|
22389
22363
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
22390
22364
|
${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; border-radius:18px; padding:18px; background:#fff; box-shadow:0 18px 48px rgba(15,23,42,.08);">
|
|
22391
22365
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
22392
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
22393
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
22366
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml(entry.name)}</h2>
|
|
22367
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml(entry.status.toUpperCase())}</span>
|
|
22394
22368
|
</div>
|
|
22395
22369
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
22396
22370
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -22398,9 +22372,9 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
22398
22372
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
22399
22373
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
22400
22374
|
</dl>
|
|
22401
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
22402
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
22403
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
22375
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml(entry.setup.urls.stream || "missing")}</code></p>
|
|
22376
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml(entry.setup.urls.webhook || "missing")}</code></p>
|
|
22377
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml(issue.severity)}: ${escapeHtml(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
22404
22378
|
</article>`).join("")}
|
|
22405
22379
|
</section>
|
|
22406
22380
|
</main>`;
|
|
@@ -23788,7 +23762,6 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
23788
23762
|
return parameters;
|
|
23789
23763
|
};
|
|
23790
23764
|
var joinUrlPath = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
23791
|
-
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23792
23765
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
23793
23766
|
if (!webhook?.verificationUrl) {
|
|
23794
23767
|
return;
|
|
@@ -23833,23 +23806,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
23833
23806
|
};
|
|
23834
23807
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
23835
23808
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
23836
|
-
<h1>${
|
|
23809
|
+
<h1>${escapeHtml(title)}</h1>
|
|
23837
23810
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
23838
23811
|
<section>
|
|
23839
23812
|
<h2>URLs</h2>
|
|
23840
23813
|
<ul>
|
|
23841
|
-
<li><strong>TwiML:</strong> <code>${
|
|
23842
|
-
<li><strong>Media stream:</strong> <code>${
|
|
23843
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
23814
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml(status.urls.twiml)}</code></li>
|
|
23815
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml(status.urls.stream)}</code></li>
|
|
23816
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml(status.urls.webhook)}</code></li>
|
|
23844
23817
|
</ul>
|
|
23845
23818
|
</section>
|
|
23846
23819
|
<section>
|
|
23847
23820
|
<h2>Signing</h2>
|
|
23848
23821
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
23849
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
23822
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml(status.signing.verificationUrl)}</code></p>` : ""}
|
|
23850
23823
|
</section>
|
|
23851
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
23852
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
23824
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
23825
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
23853
23826
|
</main>`;
|
|
23854
23827
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
23855
23828
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -23860,20 +23833,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
23860
23833
|
});
|
|
23861
23834
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
23862
23835
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
23863
|
-
<h1>${
|
|
23836
|
+
<h1>${escapeHtml(title)}</h1>
|
|
23864
23837
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
23865
23838
|
<section>
|
|
23866
23839
|
<h2>Checks</h2>
|
|
23867
23840
|
<ul>
|
|
23868
|
-
${report.checks.map((check) => `<li><strong>${
|
|
23841
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml(check.name)}</strong>: ${escapeHtml(check.status)}${check.message ? ` - ${escapeHtml(check.message)}` : ""}</li>`).join("")}
|
|
23869
23842
|
</ul>
|
|
23870
23843
|
</section>
|
|
23871
23844
|
<section>
|
|
23872
23845
|
<h2>Observed URLs</h2>
|
|
23873
23846
|
<ul>
|
|
23874
|
-
<li><strong>TwiML:</strong> <code>${
|
|
23875
|
-
<li><strong>Stream:</strong> <code>${
|
|
23876
|
-
<li><strong>Webhook:</strong> <code>${
|
|
23847
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml(report.setup.urls.twiml)}</code></li>
|
|
23848
|
+
<li><strong>Stream:</strong> <code>${escapeHtml(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
23849
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml(report.setup.urls.webhook)}</code></li>
|
|
23877
23850
|
</ul>
|
|
23878
23851
|
</section>
|
|
23879
23852
|
</main>`;
|
|
@@ -24556,7 +24529,6 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
24556
24529
|
|
|
24557
24530
|
// src/telephony/plivo.ts
|
|
24558
24531
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
24559
|
-
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
24560
24532
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
24561
24533
|
var resolveRequestOrigin2 = (request) => {
|
|
24562
24534
|
const url = new URL(request.url);
|
|
@@ -24987,21 +24959,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
24987
24959
|
};
|
|
24988
24960
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
24989
24961
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
24990
|
-
<h1>${
|
|
24962
|
+
<h1>${escapeHtml(title)}</h1>
|
|
24991
24963
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
24992
24964
|
<ul>
|
|
24993
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
24994
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
24995
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
24965
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml(status.urls.answer)}</code></li>
|
|
24966
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml(status.urls.stream)}</code></li>
|
|
24967
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml(status.urls.webhook)}</code></li>
|
|
24996
24968
|
</ul>
|
|
24997
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
24998
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
24969
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml(name)}</code></li>`).join("")}</ul>` : ""}
|
|
24970
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml(warning)}</li>`).join("")}</ul>` : ""}
|
|
24999
24971
|
</main>`;
|
|
25000
24972
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
25001
24973
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
25002
|
-
<h1>${
|
|
24974
|
+
<h1>${escapeHtml(title)}</h1>
|
|
25003
24975
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
25004
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
24976
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml(check.name)}</strong>: ${escapeHtml(check.status)}${check.message ? ` - ${escapeHtml(check.message)}` : ""}</li>`).join("")}</ul>
|
|
25005
24977
|
</main>`;
|
|
25006
24978
|
var runPlivoSmokeTest = async (input) => {
|
|
25007
24979
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -25205,7 +25177,6 @@ import { Buffer as Buffer5 } from "buffer";
|
|
|
25205
25177
|
import { Database as Database4 } from "bun:sqlite";
|
|
25206
25178
|
import { Elysia as Elysia39 } from "elysia";
|
|
25207
25179
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
25208
|
-
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
25209
25180
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
25210
25181
|
var resolveRequestOrigin3 = (request) => {
|
|
25211
25182
|
const url = new URL(request.url);
|
|
@@ -25599,21 +25570,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
25599
25570
|
};
|
|
25600
25571
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
25601
25572
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
25602
|
-
<h1>${
|
|
25573
|
+
<h1>${escapeHtml(title)}</h1>
|
|
25603
25574
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
25604
25575
|
<ul>
|
|
25605
|
-
<li><strong>TeXML:</strong> <code>${
|
|
25606
|
-
<li><strong>Media stream:</strong> <code>${
|
|
25607
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
25576
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml(status.urls.texml)}</code></li>
|
|
25577
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml(status.urls.stream)}</code></li>
|
|
25578
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml(status.urls.webhook)}</code></li>
|
|
25608
25579
|
</ul>
|
|
25609
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
25610
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
25580
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml(name)}</code></li>`).join("")}</ul>` : ""}
|
|
25581
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml(warning)}</li>`).join("")}</ul>` : ""}
|
|
25611
25582
|
</main>`;
|
|
25612
25583
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
25613
25584
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
25614
|
-
<h1>${
|
|
25585
|
+
<h1>${escapeHtml(title)}</h1>
|
|
25615
25586
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
25616
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
25587
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml(check.name)}</strong>: ${escapeHtml(check.status)}${check.message ? ` - ${escapeHtml(check.message)}` : ""}</li>`).join("")}</ul>
|
|
25617
25588
|
</main>`;
|
|
25618
25589
|
var runTelnyxSmokeTest = async (input) => {
|
|
25619
25590
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -26107,12 +26078,11 @@ var defaultThresholds = {
|
|
|
26107
26078
|
}
|
|
26108
26079
|
};
|
|
26109
26080
|
var providerKinds = ["llm", "stt", "tts"];
|
|
26110
|
-
var
|
|
26081
|
+
var statusRank3 = {
|
|
26111
26082
|
pass: 0,
|
|
26112
26083
|
warn: 1,
|
|
26113
26084
|
fail: 2
|
|
26114
26085
|
};
|
|
26115
|
-
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26116
26086
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
26117
26087
|
var rate4 = (count, total) => count / Math.max(1, total);
|
|
26118
26088
|
var uniqueSorted5 = (values) => [
|
|
@@ -26304,7 +26274,7 @@ var evaluateVoiceProviderSloEvidence = (report, input = {}) => {
|
|
|
26304
26274
|
const timeouts = kindReports.reduce((total, kind) => total + kind.timeouts, 0);
|
|
26305
26275
|
const unresolvedErrors = kindReports.reduce((total, kind) => total + kind.unresolvedErrors, 0);
|
|
26306
26276
|
const maxStatus2 = input.maxStatus ?? "pass";
|
|
26307
|
-
if (
|
|
26277
|
+
if (statusRank3[report.status] > statusRank3[maxStatus2]) {
|
|
26308
26278
|
issues.push(`Expected provider SLO status at most ${maxStatus2}, found ${report.status}.`);
|
|
26309
26279
|
}
|
|
26310
26280
|
if (input.minEvents !== undefined && report.events < input.minEvents) {
|
|
@@ -26408,11 +26378,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
26408
26378
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
26409
26379
|
const kindCards = providerKinds.map((kind) => {
|
|
26410
26380
|
const kindReport = report.kinds[kind];
|
|
26411
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
26381
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml(metric.label)}</dt><dd>${escapeHtml(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
26412
26382
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
26413
|
-
return `<article class="${
|
|
26383
|
+
return `<article class="${escapeHtml(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
26414
26384
|
}).join("");
|
|
26415
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
26385
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml(issue.status)}"><strong>${escapeHtml(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
26416
26386
|
const snippet = `createVoiceProviderSloRoutes({
|
|
26417
26387
|
store: runtimeStorage.traces,
|
|
26418
26388
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -26422,7 +26392,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
26422
26392
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
26423
26393
|
}
|
|
26424
26394
|
})`;
|
|
26425
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26395
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101318;color:#f8f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,article,.primitive{background:#171b22;border:1px solid #2c3340;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.2),rgba(245,158,11,.12))}.eyebrow{color:#7dd3fc;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.9rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status,article h2 span{border:1px solid #475569;border-radius:999px;display:inline-flex;font-size:.85rem;padding:6px 10px}.pass{border-color:rgba(34,197,94,.65)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}dt{color:#cbd5e1;font-size:.78rem;text-transform:uppercase}dd{font-size:1.7rem;font-weight:900;margin:0}small{color:#a8b3c2}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#101318;border:1px solid #2c3340;border-radius:16px;padding:12px}li span{color:#cbd5e1;display:block;margin-top:4px}.primitive{background:#11161d}.primitive code{color:#bae6fd}.primitive pre{background:#070b10;border:1px solid #243041;border-radius:16px;color:#e0f2fe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Provider latency and fallback proof</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">${escapeHtml(report.status)}</p><p>${report.events} provider routing event(s), ${report.eventsWithLatency} latency sample(s).</p></section><section class="grid">${kindCards}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderSloRoutes(...)</code> turns provider speed into release evidence</h2><p>Pair this report with production readiness so LLM/STT/TTS latency, timeout, fallback, and unresolved error regressions block deploys.</p><pre><code>${escapeHtml(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
26426
26396
|
};
|
|
26427
26397
|
var createVoiceProviderSloRoutes = (options) => {
|
|
26428
26398
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -26467,7 +26437,6 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
26467
26437
|
|
|
26468
26438
|
// src/sessionObservability.ts
|
|
26469
26439
|
import { Elysia as Elysia42 } from "elysia";
|
|
26470
|
-
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26471
26440
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26472
26441
|
var resolveHref = (href, sessionId) => {
|
|
26473
26442
|
if (href === false) {
|
|
@@ -26610,8 +26579,8 @@ var buildVoiceSessionObservabilityReport = async (options) => {
|
|
|
26610
26579
|
turns: buildTurnWaterfalls(record)
|
|
26611
26580
|
};
|
|
26612
26581
|
};
|
|
26613
|
-
var renderLinks = (links) => links.length === 0 ? "" : `<div class="actions">${links.map((link) => `<a href="${
|
|
26614
|
-
var renderTurns = (turns) => turns.length === 0 ? '<p class="muted">No turn-level events recorded yet.</p>' : turns.map((turn) => `<article class="turn"><header><strong>${
|
|
26582
|
+
var renderLinks = (links) => links.length === 0 ? "" : `<div class="actions">${links.map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</div>`;
|
|
26583
|
+
var renderTurns = (turns) => turns.length === 0 ? '<p class="muted">No turn-level events recorded yet.</p>' : turns.map((turn) => `<article class="turn"><header><strong>${escapeHtml(turn.turnId)}</strong><span>${formatMs4(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>${escapeHtml(stage.type)}</td><td>${escapeHtml(stage.label)}</td><td>${escapeHtml(stage.provider ?? "")}</td><td>${escapeHtml(stage.status ?? "")}</td><td>${formatMs4(stage.elapsedMs)}</td></tr>`).join("")}</tbody></table></article>`).join("");
|
|
26615
26584
|
var renderVoiceSessionObservabilityMarkdown = (report) => `# Voice session observability: ${report.sessionId}
|
|
26616
26585
|
|
|
26617
26586
|
Status: ${report.status}
|
|
@@ -26652,7 +26621,7 @@ ${turn.stages.map((stage) => `- +${stage.offsetMs}ms ${stage.type}: ${stage.labe
|
|
|
26652
26621
|
## Incident Handoff
|
|
26653
26622
|
|
|
26654
26623
|
${report.incidentMarkdown}`;
|
|
26655
|
-
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>${
|
|
26624
|
+
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>${escapeHtml(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>${escapeHtml(report.sessionId)}</h1><p class="status ${escapeHtml(report.status)}">${escapeHtml(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>${formatMs4(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>${escapeHtml(report.incidentMarkdown)}</code></pre></section></main></body></html>`;
|
|
26656
26625
|
var routeSessionId = (params) => typeof params.sessionId === "string" ? params.sessionId : "";
|
|
26657
26626
|
var linkByRel = (links) => {
|
|
26658
26627
|
const map = new Map;
|
|
@@ -27100,7 +27069,6 @@ None.
|
|
|
27100
27069
|
};
|
|
27101
27070
|
|
|
27102
27071
|
// src/opsRecovery.ts
|
|
27103
|
-
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27104
27072
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
27105
27073
|
var hrefForSession = (value, sessionId) => {
|
|
27106
27074
|
if (typeof value === "function") {
|
|
@@ -27116,7 +27084,7 @@ var hrefForSession = (value, sessionId) => {
|
|
|
27116
27084
|
return value;
|
|
27117
27085
|
};
|
|
27118
27086
|
var operationsRecordHrefForSession = (links, sessionId) => hrefForSession(links?.operationsRecords, sessionId);
|
|
27119
|
-
var rollupStatus2 = (issues) => issues.
|
|
27087
|
+
var rollupStatus2 = (issues) => worstVoiceStatus(issues.map((issue) => issue.severity));
|
|
27120
27088
|
var providerUnresolved = (provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed";
|
|
27121
27089
|
var collectFailedSessions = (events, limit, links) => events.filter((event) => {
|
|
27122
27090
|
if (event.type !== "session.error") {
|
|
@@ -27314,13 +27282,13 @@ ${failedSessions || "None."}
|
|
|
27314
27282
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
27315
27283
|
`;
|
|
27316
27284
|
};
|
|
27317
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
27285
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml(label)}</span><strong>not configured</strong></article>`;
|
|
27318
27286
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
27319
27287
|
const title = options.title ?? "Voice Ops Recovery";
|
|
27320
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
27321
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
27322
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
27323
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27288
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml(issue.severity)}</td><td><code>${escapeHtml(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml(issue.href)}">${escapeHtml(issue.label)}</a>` : escapeHtml(issue.label)}</td><td>${escapeHtml(String(issue.value ?? ""))}</td><td>${escapeHtml(issue.detail ?? "")}</td></tr>`).join("");
|
|
27289
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml(provider.provider)}</td><td>${escapeHtml(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml(provider.lastError ?? "")}</td></tr>`).join("");
|
|
27290
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">${escapeHtml(session.sessionId)}</a>` : escapeHtml(session.sessionId)}${session.provider ? ` via ${escapeHtml(session.provider)}` : ""}${session.error ? `: ${escapeHtml(session.error)}` : ""}</li>`).join("");
|
|
27291
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml(title)}</h1><p><span class="status">${escapeHtml(report.status)}</span> Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
27324
27292
|
};
|
|
27325
27293
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
27326
27294
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
@@ -27386,7 +27354,6 @@ var buildVoiceReadinessRecoveryActions = (input, options = {}) => {
|
|
|
27386
27354
|
sourceChecks: sourceChecks.length
|
|
27387
27355
|
};
|
|
27388
27356
|
};
|
|
27389
|
-
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27390
27357
|
var formatVoiceProofFreshnessDuration = (valueMs) => {
|
|
27391
27358
|
if (valueMs < 1000) {
|
|
27392
27359
|
return `${Math.max(0, Math.round(valueMs))}ms`;
|
|
@@ -27557,7 +27524,7 @@ var createVoiceProductionReadinessProofRuntime = (options = {}) => {
|
|
|
27557
27524
|
store
|
|
27558
27525
|
};
|
|
27559
27526
|
};
|
|
27560
|
-
var rollupStatus3 = (checks) => checks.
|
|
27527
|
+
var rollupStatus3 = (checks) => worstVoiceStatus(checks.map((check) => check.status));
|
|
27561
27528
|
var readinessGateCodes = {
|
|
27562
27529
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
27563
27530
|
"Audit evidence": "voice.readiness.audit_evidence",
|
|
@@ -29479,25 +29446,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
29479
29446
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
29480
29447
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
29481
29448
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
29482
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
29483
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
29449
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
29450
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml(report.profile.name)}</h2><p>${escapeHtml(report.profile.description)}</p><p>${escapeHtml(report.profile.purpose)}</p><div class="profile-surfaces">${report.profile.surfaces.map((surface) => `<article class="${surface.configured ? "pass" : "warn"}"><span>${surface.configured ? "CONFIGURED" : "EXPECTED"}</span><strong>${surface.href ? `<a href="${escapeHtml(surface.href)}">${escapeHtml(surface.label)}</a>` : escapeHtml(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
29484
29451
|
const checks = report.checks.map((check, index) => {
|
|
29485
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
29486
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
29487
|
-
return `<article class="check ${
|
|
29452
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml(action.href)}">${escapeHtml(action.label)}</button>` : `<a href="${escapeHtml(action.href)}">${escapeHtml(action.label)}</a>`).join("");
|
|
29453
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml(check.status)}: observed ${escapeHtml(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml(check.gateExplanation.unit)}` : ""}. ${escapeHtml(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
29454
|
+
return `<article class="check ${escapeHtml(check.status)}">
|
|
29488
29455
|
<div>
|
|
29489
|
-
<span>${
|
|
29490
|
-
<h2>${
|
|
29491
|
-
${check.detail ? `<p>${
|
|
29456
|
+
<span>${escapeHtml(check.status.toUpperCase())}</span>
|
|
29457
|
+
<h2>${escapeHtml(check.label)}</h2>
|
|
29458
|
+
${check.detail ? `<p>${escapeHtml(check.detail)}</p>` : ""}
|
|
29492
29459
|
${explanation}
|
|
29493
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
29460
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml(check.proofSource.href)}">${escapeHtml(check.proofSource.sourceLabel)}</a>` : escapeHtml(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
29494
29461
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
29495
29462
|
</div>
|
|
29496
|
-
<strong>${
|
|
29497
|
-
${check.href ? `<a href="${
|
|
29463
|
+
<strong>${escapeHtml(String(check.value ?? check.status))}</strong>
|
|
29464
|
+
${check.href ? `<a href="${escapeHtml(check.href)}">Open surface</a>` : ""}
|
|
29498
29465
|
</article>`;
|
|
29499
29466
|
}).join("");
|
|
29500
|
-
const snippet =
|
|
29467
|
+
const snippet = escapeHtml(`createVoiceProductionReadinessRoutes({
|
|
29501
29468
|
htmlPath: '/production-readiness',
|
|
29502
29469
|
path: '/api/production-readiness',
|
|
29503
29470
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -29513,7 +29480,7 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
29513
29480
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
29514
29481
|
store: traceStore
|
|
29515
29482
|
});`);
|
|
29516
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29483
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero,.primitive,.profile{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.primitive,.profile{background:#111722}.primitive{border-color:#3a3f2d}.eyebrow{color:#fbbf24;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{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.primitive code{color:#fde68a}.primitive p{color:#c8ccd3;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#0b0f16;border:1px solid #2c3440;border-radius:18px;color:#fef3c7;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.check.pass,.profile-surfaces .pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn,.profile-surfaces .warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span,.profile-surfaces span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p,.profile p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check .gate-explanation{background:#0b0f16;border:1px solid #2c3440;border-radius:14px;color:#fef3c7;margin-top:10px;padding:10px}.check strong{font-size:1.5rem}.profile-surfaces{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}.profile-surfaces article{background:#141922;border:1px solid #26313d;border-radius:16px;padding:14px}.profile-surfaces strong{display:block;margin-top:6px}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml(title)}</h1><p>One deployable pass/fail report for quality gates, provider failover, session health, handoffs, routing evidence, and optional carrier readiness.</p><p class="status ${escapeHtml(report.status)}">Overall: ${escapeHtml(report.status.toUpperCase())}</p><p>Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}</p>${thresholdLink}</section>${profile}<section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProductionReadinessRoutes(...)</code> builds this deploy gate</h2><p>Mount one package primitive to expose JSON readiness, HTML readiness, and a machine-readable gate route. Feed it the proof stores and contract reports your app already owns.</p><pre><code>${snippet}</code></pre></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
|
|
29517
29484
|
};
|
|
29518
29485
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
29519
29486
|
const path = options.path ?? "/api/production-readiness";
|
|
@@ -29591,10 +29558,9 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
29591
29558
|
};
|
|
29592
29559
|
|
|
29593
29560
|
// src/operationalStatus.ts
|
|
29594
|
-
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29595
29561
|
var resolveValue2 = async (value) => typeof value === "function" ? await value() : value;
|
|
29596
29562
|
var isDeliveryRuntime = (value) => Boolean(value && typeof value === "object" && "isRunning" in value && "summarize" in value);
|
|
29597
|
-
var worstStatus3 = (statuses) =>
|
|
29563
|
+
var worstStatus3 = (statuses) => worstVoiceStatus(statuses);
|
|
29598
29564
|
var proofPackStatusToCheck = (status, href) => {
|
|
29599
29565
|
const checkStatus = status.state === "failed" || status.state === "missing" ? "fail" : status.state === "fresh" ? "pass" : "warn";
|
|
29600
29566
|
const age = typeof status.ageMs === "number" ? `${Math.round(status.ageMs / 1000)}s old` : undefined;
|
|
@@ -29661,14 +29627,14 @@ var buildVoiceOperationalStatusReport = async (options) => {
|
|
|
29661
29627
|
};
|
|
29662
29628
|
var renderVoiceOperationalStatusHTML = (report, options = {}) => {
|
|
29663
29629
|
const title = options.title ?? "AbsoluteJS Voice Operational Status";
|
|
29664
|
-
const checks = report.checks.map((check) => `<article class="${
|
|
29665
|
-
<span>${
|
|
29666
|
-
<h2>${
|
|
29667
|
-
<strong>${
|
|
29668
|
-
${check.detail ? `<p>${
|
|
29669
|
-
${check.href ? `<a href="${
|
|
29630
|
+
const checks = report.checks.map((check) => `<article class="${escapeHtml(check.status)}">
|
|
29631
|
+
<span>${escapeHtml(check.status.toUpperCase())}</span>
|
|
29632
|
+
<h2>${escapeHtml(check.label)}</h2>
|
|
29633
|
+
<strong>${escapeHtml(String(check.value ?? check.status))}</strong>
|
|
29634
|
+
${check.detail ? `<p>${escapeHtml(check.detail)}</p>` : ""}
|
|
29635
|
+
${check.href ? `<a href="${escapeHtml(check.href)}">Open surface</a>` : ""}
|
|
29670
29636
|
</article>`).join("");
|
|
29671
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29637
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#10130f;color:#f8f3df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1040px;padding:32px}.hero{background:linear-gradient(135deg,rgba(132,204,22,.18),rgba(14,165,233,.13));border:1px solid #2c3a28;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#bef264;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}article{background:#171d15;border:1px solid #2c3a28;border-radius:22px;padding:18px}article.pass{border-color:rgba(34,197,94,.65)}article.warn{border-color:rgba(245,158,11,.75)}article.fail{border-color:rgba(239,68,68,.85)}article span{color:#bef264;font-size:.78rem;font-weight:900;letter-spacing:.08em}article.warn span{color:#fbbf24}article.fail span{color:#fca5a5}article strong{display:block;font-size:1.6rem;margin:.4rem 0}article p{color:#c5ceb9}a{color:#bef264}</style></head><body><main><section class="hero"><p class="eyebrow">Operational status</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">Overall: ${escapeHtml(report.status.toUpperCase())}</p><p>${String(report.summary.pass)}/${String(report.summary.total)} checks passing. Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}.</p></section><section class="grid">${checks || '<article class="pass"><span>PASS</span><h2>No operational checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
|
|
29672
29638
|
};
|
|
29673
29639
|
var createVoiceOperationalStatusRoutes = (options) => {
|
|
29674
29640
|
const path = options.path ?? "/api/voice/operational-status";
|
|
@@ -29736,7 +29702,6 @@ var DEFAULT_LINKS = [
|
|
|
29736
29702
|
label: "Handoffs"
|
|
29737
29703
|
}
|
|
29738
29704
|
];
|
|
29739
|
-
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29740
29705
|
var countProviderStatuses = (providers) => {
|
|
29741
29706
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
29742
29707
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -29805,16 +29770,16 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
29805
29770
|
trace
|
|
29806
29771
|
};
|
|
29807
29772
|
};
|
|
29808
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
29773
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml(input.label)}</span><strong>${escapeHtml(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml(input.status)}">${escapeHtml(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml(input.href)}">Open</a>` : ""}</article>`;
|
|
29809
29774
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
29810
29775
|
const links = report.links.map((link) => `<article class="surface">
|
|
29811
|
-
<div><h2>${
|
|
29812
|
-
<p><a href="${
|
|
29776
|
+
<div><h2>${escapeHtml(link.label)}</h2>${link.description ? `<p>${escapeHtml(link.description)}</p>` : ""}</div>
|
|
29777
|
+
<p><a href="${escapeHtml(link.href)}">Open ${escapeHtml(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml(link.statusHref)}">Status</a>` : ""}</p>
|
|
29813
29778
|
</article>`).join("");
|
|
29814
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
29815
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
29779
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml(session.sessionId)}</td><td>${escapeHtml(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
29780
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml(event.kind)}</td><td>${escapeHtml(event.provider ?? "unknown")}</td><td>${escapeHtml(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
29816
29781
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
29817
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29782
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
|
|
29818
29783
|
};
|
|
29819
29784
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
29820
29785
|
const path = options.path ?? "/ops-console";
|
|
@@ -30011,14 +29976,13 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
30011
29976
|
};
|
|
30012
29977
|
|
|
30013
29978
|
// src/opsStatusRoutes.ts
|
|
30014
|
-
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30015
29979
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
30016
29980
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
30017
29981
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
30018
29982
|
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;
|
|
30019
|
-
return `<article class="surface ${
|
|
29983
|
+
return `<article class="surface ${escapeHtml(surface.status)}"><span>${escapeHtml(surface.status.toUpperCase())}</span><h2>${escapeHtml(key)}</h2><strong>${escapeHtml(value)}</strong></article>`;
|
|
30020
29984
|
}).join("");
|
|
30021
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29985
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(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>${escapeHtml(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml(report.status)}">Overall: ${escapeHtml(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>`;
|
|
30022
29986
|
};
|
|
30023
29987
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
30024
29988
|
const path = options.path ?? "/api/voice/ops-status";
|
|
@@ -30204,7 +30168,6 @@ var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
|
30204
30168
|
|
|
30205
30169
|
// src/outcomeContract.ts
|
|
30206
30170
|
import { Elysia as Elysia49 } from "elysia";
|
|
30207
|
-
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30208
30171
|
var resolveSessionHref4 = (value, sessionId) => {
|
|
30209
30172
|
if (value === false) {
|
|
30210
30173
|
return;
|
|
@@ -30415,13 +30378,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
30415
30378
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
30416
30379
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
30417
30380
|
const contracts = report.contracts.map((contract) => {
|
|
30418
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
30381
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml(href)}">${escapeHtml(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
30419
30382
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
30420
30383
|
<div class="contract-header">
|
|
30421
30384
|
<div>
|
|
30422
|
-
<p class="eyebrow">${
|
|
30423
|
-
<h2>${
|
|
30424
|
-
${contract.description ? `<p>${
|
|
30385
|
+
<p class="eyebrow">${escapeHtml(contract.contractId)}</p>
|
|
30386
|
+
<h2>${escapeHtml(contract.label ?? contract.contractId)}</h2>
|
|
30387
|
+
${contract.description ? `<p>${escapeHtml(contract.description)}</p>` : ""}
|
|
30425
30388
|
${sessionLinks}
|
|
30426
30389
|
</div>
|
|
30427
30390
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -30433,10 +30396,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
30433
30396
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
30434
30397
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
30435
30398
|
</div>
|
|
30436
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
30399
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
30437
30400
|
</section>`;
|
|
30438
30401
|
}).join("");
|
|
30439
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30402
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(14,165,233,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary,.grid{display:flex;flex-wrap:wrap;gap:10px}.pill,.grid span{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}li{margin:8px 0}@media(max-width:800px){main{padding:18px}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Business Outcome Verification</p><h1>${escapeHtml(title)}</h1><div class="summary"><span class="pill ${report.status}">${report.status}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No outcome contracts configured.</p></section>'}</main></body></html>`;
|
|
30440
30403
|
};
|
|
30441
30404
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
30442
30405
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -30470,7 +30433,6 @@ var defaultRequirements = [
|
|
|
30470
30433
|
"lifecycle-outcome",
|
|
30471
30434
|
"no-session-error"
|
|
30472
30435
|
];
|
|
30473
|
-
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30474
30436
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
30475
30437
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
30476
30438
|
const value = event.payload[key];
|
|
@@ -30579,10 +30541,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
30579
30541
|
});
|
|
30580
30542
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
30581
30543
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
30582
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
30583
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
30584
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
30585
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30544
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml(issue.requirement)}</strong>: ${escapeHtml(issue.message)}</li>`).join("");
|
|
30545
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml(outcome)}</span>`).join("");
|
|
30546
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml(requirement)}</span>`).join("");
|
|
30547
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0e141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1050px;padding:32px}.hero,.panel{background:#151d26;border:1px solid #283544;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.metric{background:#0f151d;border:1px solid #283544;border-radius:16px;padding:14px}.metric strong{display:block;font-size:1.8rem}.pill{background:#0f151d;border:1px solid #3f3f46;border-radius:999px;display:inline-flex;margin:4px;padding:7px 10px}.issues{color:#fca5a5}code{color:#fde68a}@media(max-width:720px){main{padding:18px}}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent production smoke</p><h1>${escapeHtml(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml(report.sessionId)}</code>` : ""}.</p></section><section class="panel"><h2>Observed Trace Evidence</h2><div class="grid"><div class="metric"><span>Media starts</span><strong>${String(report.observed.mediaStarts)}</strong></div><div class="metric"><span>Transcripts</span><strong>${String(report.observed.transcripts)}</strong></div><div class="metric"><span>Assistant responses</span><strong>${String(report.observed.assistantResponses)}</strong></div><div class="metric"><span>Session errors</span><strong>${String(report.observed.sessionErrors)}</strong></div></div><p>${outcomes || '<span class="pill">No lifecycle outcome</span>'}</p></section><section class="panel"><h2>Requirements</h2><p>${requirements}</p>${issues ? `<ul class="issues">${issues}</ul>` : '<p class="pass">All required phone-agent smoke evidence is present.</p>'}</section></main></body></html>`;
|
|
30586
30548
|
};
|
|
30587
30549
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
30588
30550
|
query,
|
|
@@ -31505,7 +31467,6 @@ import { Elysia as Elysia55 } from "elysia";
|
|
|
31505
31467
|
|
|
31506
31468
|
// src/providerDecisionTraces.ts
|
|
31507
31469
|
import { Elysia as Elysia54 } from "elysia";
|
|
31508
|
-
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31509
31470
|
var getString18 = (value) => typeof value === "string" ? value : undefined;
|
|
31510
31471
|
var getNumber11 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
31511
31472
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -31520,8 +31481,7 @@ var surfaceForKind = (kind) => {
|
|
|
31520
31481
|
return "live-call";
|
|
31521
31482
|
}
|
|
31522
31483
|
};
|
|
31523
|
-
var
|
|
31524
|
-
var reportStatus = (issues) => issues.reduce((status, issue) => statusRank5[issue.status] > statusRank5[status] ? issue.status : status, "pass");
|
|
31484
|
+
var reportStatus = (issues) => worstVoiceStatus(issues.map((issue) => issue.status));
|
|
31525
31485
|
var uniqueSorted6 = (values) => [
|
|
31526
31486
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
31527
31487
|
].sort();
|
|
@@ -31746,7 +31706,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
31746
31706
|
<head>
|
|
31747
31707
|
<meta charset="utf-8" />
|
|
31748
31708
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
31749
|
-
<title>${
|
|
31709
|
+
<title>${escapeHtml(title)}</title>
|
|
31750
31710
|
<style>
|
|
31751
31711
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
31752
31712
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -31760,8 +31720,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
31760
31720
|
</head>
|
|
31761
31721
|
<body>
|
|
31762
31722
|
<main>
|
|
31763
|
-
<p class="status ${report.status}">${
|
|
31764
|
-
<h1>${
|
|
31723
|
+
<p class="status ${report.status}">${escapeHtml(report.status)}</p>
|
|
31724
|
+
<h1>${escapeHtml(title)}</h1>
|
|
31765
31725
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
31766
31726
|
<section class="grid">
|
|
31767
31727
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -31772,10 +31732,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
31772
31732
|
</section>
|
|
31773
31733
|
<section class="surfaces">
|
|
31774
31734
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
31775
|
-
<header><strong>${
|
|
31735
|
+
<header><strong>${escapeHtml(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml(surface.status)}</span></header>
|
|
31776
31736
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
31777
|
-
<p class="muted">Providers: ${
|
|
31778
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
31737
|
+
<p class="muted">Providers: ${escapeHtml(surface.providers.join(", ") || "none")}</p>
|
|
31738
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml(reason)}</code>`).join(" ")}</p>
|
|
31779
31739
|
</article>`).join(`
|
|
31780
31740
|
`)}
|
|
31781
31741
|
</section>
|
|
@@ -34186,7 +34146,6 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
34186
34146
|
}
|
|
34187
34147
|
};
|
|
34188
34148
|
};
|
|
34189
|
-
var escapeHtml47 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34190
34149
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
34191
34150
|
var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
|
|
34192
34151
|
`# ${title}`,
|
|
@@ -34221,11 +34180,11 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
34221
34180
|
].join(`
|
|
34222
34181
|
`);
|
|
34223
34182
|
var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
|
|
34224
|
-
const cards = report.recommendations.map((recommendation) => `<article class="${
|
|
34225
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
34226
|
-
const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${
|
|
34227
|
-
const profileRows = report.profiles.length === 0 ? "<li>No benchmark profiles were present.</li>" : report.profiles.map((profile) => `<li><strong>${
|
|
34228
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
34183
|
+
const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml(recommendation.status)}"><p class="eyebrow">${escapeHtml(recommendation.surface)} \xB7 ${escapeHtml(recommendation.status)}</p><h2>${escapeHtml(recommendation.recommendation)}</h2><p>${escapeHtml(recommendation.nextMove)}</p><pre>${escapeHtml(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
|
|
34184
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("");
|
|
34185
|
+
const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml(provider.label ?? provider.id)}</strong><span>${escapeHtml(provider.role ?? "provider")} \xB7 ${escapeHtml(provider.status)} \xB7 p95 ${escapeHtml(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml(provider.nextMove)}</small></li>`).join("");
|
|
34186
|
+
const profileRows = report.profiles.length === 0 ? "<li>No benchmark profiles were present.</li>" : report.profiles.map((profile) => `<li><strong>${escapeHtml(profile.label ?? profile.id)}</strong><span>${escapeHtml(profile.status)} \xB7 ${escapeHtml(formatProviderMix(profile.bestProviders))}</span><small>${escapeHtml(profile.nextMove)}</small></li>`).join("");
|
|
34187
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml(title)}</h1><p>Generated ${escapeHtml(report.generatedAt)} from ${escapeHtml(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml(formatProviderMix(report.bestProviders))}</span><span class="pill">Profiles ${String(report.profiles.length)}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Benchmark Profiles</h2><ul>${profileRows}</ul></section><section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
|
|
34229
34188
|
};
|
|
34230
34189
|
var renderVoiceRealCallProfileHistoryMarkdown = (report, title = "Voice Real-Call Profile History") => [
|
|
34231
34190
|
`# ${title}`,
|
|
@@ -34259,11 +34218,11 @@ var renderVoiceRealCallProfileHistoryMarkdown = (report, title = "Voice Real-Cal
|
|
|
34259
34218
|
].join(`
|
|
34260
34219
|
`);
|
|
34261
34220
|
var renderVoiceRealCallProfileHistoryHTML = (report, title = "Voice Real-Call Profile History") => {
|
|
34262
|
-
const profileRows = report.summary.profiles?.length ? report.summary.profiles.map((profile) => `<tr><td>${
|
|
34263
|
-
const defaultRows = report.defaults.profiles.length > 0 ? report.defaults.profiles.map((profile) => `<tr><td>${
|
|
34264
|
-
const recommendations = report.recommendations.recommendations.map((recommendation) => `<article class="${
|
|
34265
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
34266
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
34221
|
+
const profileRows = report.summary.profiles?.length ? report.summary.profiles.map((profile) => `<tr><td>${escapeHtml(profile.label ?? profile.id)}</td><td>${escapeHtml(profile.status ?? "unknown")}</td><td>${escapeHtml(profile.maxLiveP95Ms ?? "n/a")}</td><td>${escapeHtml(profile.maxProviderP95Ms ?? "n/a")}</td><td>${escapeHtml(profile.maxTurnP95Ms ?? "n/a")}</td><td>${escapeHtml(formatProviderMix(profile.providers ?? []))}</td></tr>`).join("") : '<tr><td colspan="6">No profiles present.</td></tr>';
|
|
34222
|
+
const defaultRows = report.defaults.profiles.length > 0 ? report.defaults.profiles.map((profile) => `<tr><td>${escapeHtml(profile.label ?? profile.profileId)}</td><td>${escapeHtml(profile.status)}</td><td>${escapeHtml(Object.entries(profile.providerRoutes).map(([role, provider]) => `${role}: ${provider}`).join(", ") || "n/a")}</td><td>${escapeHtml(profile.latencyBudgets.maxLiveP95Ms ?? "n/a")}</td><td>${escapeHtml(profile.latencyBudgets.maxProviderP95Ms ?? "n/a")}</td><td>${escapeHtml(profile.latencyBudgets.maxTurnP95Ms ?? "n/a")}</td></tr>`).join("") : '<tr><td colspan="6">No actionable defaults present.</td></tr>';
|
|
34223
|
+
const recommendations = report.recommendations.recommendations.map((recommendation) => `<article class="${escapeHtml(recommendation.status)}"><p class="eyebrow">${escapeHtml(recommendation.surface)} \xB7 ${escapeHtml(recommendation.status)}</p><h2>${escapeHtml(recommendation.recommendation)}</h2><p>${escapeHtml(recommendation.nextMove)}</p></article>`).join("");
|
|
34224
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("");
|
|
34225
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#111510;color:#f6f0dd;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article,.card{background:#182117;border:1px solid #32412d;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(132,204,22,.16),rgba(20,184,166,.12))}.eyebrow{color:#bef264;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #52624b;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #32412d;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Real-call benchmark history</p><h1>${escapeHtml(title)}</h1><p>Generated ${escapeHtml(report.generatedAt)} from ${escapeHtml(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml(report.status)}</span><span class="pill">Reports ${String(report.reports)}</span><span class="pill">Profiles ${String(report.summary.profileCount)}</span><span class="pill">Defaults ${String(report.defaults.summary.actionableProfiles)}/${String(report.defaults.summary.profileCount)}</span><span class="pill">Cycles ${String(report.summary.cycles ?? 0)}</span><span class="pill">Best mix ${escapeHtml(formatProviderMix(report.recommendations.bestProviders))}</span></div></section><section class="card"><h2>Profiles</h2><table><thead><tr><th>Profile</th><th>Status</th><th>Live p95</th><th>Provider p95</th><th>Turn p95</th><th>Provider mix</th></tr></thead><tbody>${profileRows}</tbody></table></section><section class="card"><h2>Actionable Defaults</h2><table><thead><tr><th>Profile</th><th>Status</th><th>Provider routes</th><th>Live budget</th><th>Provider budget</th><th>Turn budget</th></tr></thead><tbody>${defaultRows}</tbody></table></section>${recommendations}<section class="card"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
|
|
34267
34226
|
};
|
|
34268
34227
|
var renderVoiceRealCallEvidenceRuntimeMarkdown = (report, title = "Voice Real-Call Evidence Runtime") => [
|
|
34269
34228
|
`# ${title}`,
|
|
@@ -34286,9 +34245,9 @@ var renderVoiceRealCallEvidenceRuntimeMarkdown = (report, title = "Voice Real-Ca
|
|
|
34286
34245
|
].join(`
|
|
34287
34246
|
`);
|
|
34288
34247
|
var renderVoiceRealCallEvidenceRuntimeHTML = (report, title = "Voice Real-Call Evidence Runtime") => {
|
|
34289
|
-
const issueItems = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
34290
|
-
const profileRows = report.history.summary.profiles?.length ? report.history.summary.profiles.map((profile) => `<tr><td>${
|
|
34291
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
34248
|
+
const issueItems = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("");
|
|
34249
|
+
const profileRows = report.history.summary.profiles?.length ? report.history.summary.profiles.map((profile) => `<tr><td>${escapeHtml(profile.label ?? profile.id)}</td><td>${escapeHtml(profile.status ?? "unknown")}</td><td>${escapeHtml(profile.sessionCount ?? "n/a")}</td><td>${escapeHtml(profile.maxLiveP95Ms ?? "n/a")}</td><td>${escapeHtml(profile.maxProviderP95Ms ?? "n/a")}</td><td>${escapeHtml(formatProviderMix(profile.providers ?? []))}</td></tr>`).join("") : '<tr><td colspan="6">No profile history has been collected yet.</td></tr>';
|
|
34250
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0f1618;color:#f2f7f2;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.card{background:#162225;border:1px solid #2f4548;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(132,204,22,.1))}.eyebrow{color:#99f6e4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.1rem,6vw,4.3rem);letter-spacing:-.06em;line-height:.94;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #4b6669;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail,.empty,.stale{border-color:rgba(239,68,68,.75)}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2f4548;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Real-call evidence runtime</p><h1>${escapeHtml(title)}</h1><p>Generated ${escapeHtml(report.generatedAt)} from ${escapeHtml(report.source)}.</p><div class="summary"><span class="pill ${escapeHtml(report.status)}">Status ${escapeHtml(report.status)}</span><span class="pill">Stored ${String(report.summary.storedEvidence)}</span><span class="pill">Collected ${String(report.summary.collectedEvidence)}</span><span class="pill">Appended ${String(report.appended)}</span><span class="pill">Duplicates ${String(report.skippedDuplicates)}</span><span class="pill">Sessions ${String(report.summary.sessions)}</span><span class="pill">Profiles ${String(report.summary.profiles)}</span></div></section><section class="card"><h2>Rolling Profile History</h2><table><thead><tr><th>Profile</th><th>Status</th><th>Sessions</th><th>Live p95</th><th>Provider p95</th><th>Provider mix</th></tr></thead><tbody>${profileRows}</tbody></table></section><section class="card"><h2>Issues</h2><ul>${issueItems}</ul></section></main></body></html>`;
|
|
34292
34251
|
};
|
|
34293
34252
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
34294
34253
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
|
@@ -34641,7 +34600,6 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
34641
34600
|
|
|
34642
34601
|
// src/providerCapabilities.ts
|
|
34643
34602
|
import { Elysia as Elysia56 } from "elysia";
|
|
34644
|
-
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34645
34603
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
34646
34604
|
configured: true,
|
|
34647
34605
|
features: options.features?.[provider],
|
|
@@ -34706,27 +34664,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
34706
34664
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
34707
34665
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
34708
34666
|
const cards = report.capabilities.map((capability) => {
|
|
34709
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
34710
|
-
return `<article class="card ${
|
|
34667
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml(feature)}</span>`).join("");
|
|
34668
|
+
return `<article class="card ${escapeHtml(capability.status)}">
|
|
34711
34669
|
<div class="card-header">
|
|
34712
34670
|
<div>
|
|
34713
|
-
<p class="eyebrow">${
|
|
34714
|
-
<h2>${
|
|
34671
|
+
<p class="eyebrow">${escapeHtml(capability.kind)}</p>
|
|
34672
|
+
<h2>${escapeHtml(capability.label ?? capability.provider)}</h2>
|
|
34715
34673
|
</div>
|
|
34716
|
-
<strong>${
|
|
34674
|
+
<strong>${escapeHtml(capability.status)}</strong>
|
|
34717
34675
|
</div>
|
|
34718
|
-
${capability.description ? `<p>${
|
|
34676
|
+
${capability.description ? `<p>${escapeHtml(capability.description)}</p>` : ""}
|
|
34719
34677
|
<dl>
|
|
34720
34678
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
34721
34679
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
34722
|
-
<div><dt>Model</dt><dd>${
|
|
34680
|
+
<div><dt>Model</dt><dd>${escapeHtml(capability.model ?? "default")}</dd></div>
|
|
34723
34681
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
34724
34682
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
34725
34683
|
</dl>
|
|
34726
34684
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
34727
34685
|
</article>`;
|
|
34728
34686
|
}).join("");
|
|
34729
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
34687
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.16),rgba(34,197,94,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary,.features{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.selected,.healthy{color:#86efac}.unconfigured,.degraded,.rate-limited,.suppressed{color:#fca5a5}.idle,.recoverable{color:#fde68a}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Discovery</p><h1>${escapeHtml(title)}</h1><div class="summary"><span class="pill">${String(report.configured)} configured</span><span class="pill">${String(report.selected)} selected</span><span class="pill">${String(report.unconfigured)} missing</span><span class="pill">${String(report.total)} total</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider capabilities configured.</p></article>'}</section></main></body></html>`;
|
|
34730
34688
|
};
|
|
34731
34689
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
34732
34690
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -34761,12 +34719,11 @@ var defaultRequirement = {
|
|
|
34761
34719
|
requireFallback: false,
|
|
34762
34720
|
requireTimeoutBudget: false
|
|
34763
34721
|
};
|
|
34764
|
-
var
|
|
34722
|
+
var statusRank4 = {
|
|
34765
34723
|
pass: 0,
|
|
34766
34724
|
warn: 1,
|
|
34767
34725
|
fail: 2
|
|
34768
34726
|
};
|
|
34769
|
-
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34770
34727
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
34771
34728
|
var uniqueSorted7 = (values) => [
|
|
34772
34729
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -34777,7 +34734,7 @@ var surfaceProviderNames = (surface) => uniqueSorted7([
|
|
|
34777
34734
|
...isProviderList(surface.fallback) ? surface.fallback : [],
|
|
34778
34735
|
...isProviderList(surface.allowProviders) ? surface.allowProviders : []
|
|
34779
34736
|
]);
|
|
34780
|
-
var surfaceStatus = (issues) => issues.reduce((status, issue) =>
|
|
34737
|
+
var surfaceStatus = (issues) => issues.reduce((status, issue) => statusRank4[issue.status] > statusRank4[status] ? issue.status : status, "pass");
|
|
34781
34738
|
var resolvedRequirement = (surface, options) => ({
|
|
34782
34739
|
...defaultRequirement,
|
|
34783
34740
|
...options.defaultRequirement ?? {},
|
|
@@ -34909,21 +34866,21 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
34909
34866
|
};
|
|
34910
34867
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
34911
34868
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
34912
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
34913
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
34869
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml(surface.status)}">
|
|
34870
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml(surface.surface)}</p><h2>${escapeHtml(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml(surface.status)}</strong></div>
|
|
34914
34871
|
<dl>
|
|
34915
|
-
<div><dt>Providers</dt><dd>${
|
|
34916
|
-
<div><dt>Fallback</dt><dd>${
|
|
34872
|
+
<div><dt>Providers</dt><dd>${escapeHtml(surface.providers.join(", ") || "none")}</dd></div>
|
|
34873
|
+
<div><dt>Fallback</dt><dd>${escapeHtml(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
34917
34874
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
34918
34875
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
34919
34876
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
34920
34877
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
34921
34878
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
34922
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
34879
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml(surface.fallbackMode || "default")}</dd></div>
|
|
34923
34880
|
</dl>
|
|
34924
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
34881
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml(issue.status)}</strong> ${escapeHtml(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
34925
34882
|
</article>`).join("");
|
|
34926
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
34883
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#172033;border:1px solid #2d3b55;border-radius:22px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(59,130,246,.18),rgba(20,184,166,.12))}.eyebrow{color:#93c5fd;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f172a;border:1px solid #334155;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass strong{color:#86efac}.warn strong{color:#fde68a}.fail strong{color:#fca5a5}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0;overflow-wrap:anywhere}li{margin:.35rem 0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Policy Proof</p><h1>${escapeHtml(title)}</h1><div class="summary"><span class="pill">${escapeHtml(report.profileId)}</span><span class="pill">${escapeHtml(report.status)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.providers)} providers</span><span class="pill">${String(report.issues.length)} issues</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider orchestration surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
34927
34884
|
};
|
|
34928
34885
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
34929
34886
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
@@ -34961,7 +34918,6 @@ var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
|
34961
34918
|
|
|
34962
34919
|
// src/providerStackRecommendations.ts
|
|
34963
34920
|
import { Elysia as Elysia58 } from "elysia";
|
|
34964
|
-
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34965
34921
|
var profileProviderPriorities = {
|
|
34966
34922
|
"meeting-recorder": {
|
|
34967
34923
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -35068,13 +35024,13 @@ var recommendVoiceProviderStack = (input) => {
|
|
|
35068
35024
|
stacks
|
|
35069
35025
|
};
|
|
35070
35026
|
};
|
|
35071
|
-
var rollupContractStatus = (checks) => checks.
|
|
35072
|
-
var
|
|
35027
|
+
var rollupContractStatus = (checks) => worstVoiceStatus(checks.map((check) => check.status));
|
|
35028
|
+
var statusRank5 = {
|
|
35073
35029
|
pass: 0,
|
|
35074
35030
|
warn: 1,
|
|
35075
35031
|
fail: 2
|
|
35076
35032
|
};
|
|
35077
|
-
var statusExceeds = (actual, max) =>
|
|
35033
|
+
var statusExceeds = (actual, max) => statusRank5[actual] > statusRank5[max];
|
|
35078
35034
|
var buildVoiceProviderContractMatrix = (input) => {
|
|
35079
35035
|
const rows = input.contracts.map((contract) => {
|
|
35080
35036
|
const configured = contract.configured !== false;
|
|
@@ -35276,17 +35232,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
35276
35232
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
35277
35233
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
35278
35234
|
const rows = report.rows.map((row) => {
|
|
35279
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
35280
|
-
return `<article class="row ${
|
|
35235
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml(check.status)}"><strong>${escapeHtml(check.label)}</strong><span>${escapeHtml(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml(check.remediation.href)}">${escapeHtml(check.remediation.label)}</a>` : escapeHtml(check.remediation.label)}: ${escapeHtml(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
35236
|
+
return `<article class="row ${escapeHtml(row.status)}">
|
|
35281
35237
|
<div>
|
|
35282
|
-
<p class="eyebrow">${
|
|
35283
|
-
<h2>${
|
|
35284
|
-
<p class="status ${
|
|
35238
|
+
<p class="eyebrow">${escapeHtml(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
35239
|
+
<h2>${escapeHtml(row.provider)}</h2>
|
|
35240
|
+
<p class="status ${escapeHtml(row.status)}">${escapeHtml(row.status.toUpperCase())}</p>
|
|
35285
35241
|
</div>
|
|
35286
35242
|
<ul>${checks}</ul>
|
|
35287
35243
|
</article>`;
|
|
35288
35244
|
}).join("");
|
|
35289
|
-
const snippet =
|
|
35245
|
+
const snippet = escapeHtml(`const providerContracts = () =>
|
|
35290
35246
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
35291
35247
|
env: process.env,
|
|
35292
35248
|
providers: {
|
|
@@ -35307,7 +35263,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
35307
35263
|
providerContractMatrix: () =>
|
|
35308
35264
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
35309
35265
|
});`);
|
|
35310
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
35266
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
35311
35267
|
};
|
|
35312
35268
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
35313
35269
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -35448,7 +35404,6 @@ var DEFAULT_REALTIME_FORMAT2 = {
|
|
|
35448
35404
|
encoding: "pcm_s16le",
|
|
35449
35405
|
sampleRateHz: 24000
|
|
35450
35406
|
};
|
|
35451
|
-
var escapeHtml51 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
35452
35407
|
var formatLabel = (format) => `${format.container}/${format.encoding}/${String(format.sampleRateHz)}hz/${String(format.channels)}ch`;
|
|
35453
35408
|
var formatMatches = (actual, expected) => actual.container === expected.container && actual.encoding === expected.encoding && actual.sampleRateHz === expected.sampleRateHz && actual.channels === expected.channels;
|
|
35454
35409
|
var validateFormat = (label, actual, expected, issues) => {
|
|
@@ -35702,9 +35657,9 @@ var renderVoiceRealtimeChannelMarkdown = (report) => [
|
|
|
35702
35657
|
].join(`
|
|
35703
35658
|
`);
|
|
35704
35659
|
var renderVoiceRealtimeChannelHTML = (report, title = "Voice Realtime Channel Proof") => {
|
|
35705
|
-
const issues = report.issues.map((issue) => `<li class="${
|
|
35706
|
-
const rows = report.runtime.samples.map((sample) => `<tr><td>${
|
|
35707
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
35660
|
+
const issues = report.issues.map((issue) => `<li class="${escapeHtml(issue.severity)}"><strong>${escapeHtml(issue.code)}</strong>: ${escapeHtml(issue.message)}</li>`).join("");
|
|
35661
|
+
const rows = report.runtime.samples.map((sample) => `<tr><td>${escapeHtml(sample.kind)}</td><td>${escapeHtml(sample.source ?? "runtime")}</td><td>${escapeHtml(sample.format ? formatLabel(sample.format) : "n/a")}</td><td>${escapeHtml(sample.latencyMs ?? "n/a")}</td><td>${escapeHtml(sample.ok ?? true)}</td></tr>`).join("");
|
|
35662
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.card{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(59,130,246,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}.metric{background:#101814;border:1px solid #2e3d36;border-radius:18px;padding:14px}.metric span{color:#a8b5ad;display:block;font-size:.78rem;text-transform:uppercase}.metric strong{display:block;font-size:1.65rem;margin-top:5px}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:7px 11px}.pass{color:#86efac}.warn{color:#fde68a}.fail,.error{color:#fecaca}.warning{color:#fde68a}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3d36;padding:10px;text-align:left}.links a{color:#5eead4;margin-right:12px}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime / duplex readiness</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">${escapeHtml(report.status)}</p><p>Provider <strong>${escapeHtml(report.provider)}</strong> \xB7 ${escapeHtml(report.surface)}</p><p class="links">${report.readinessHref ? `<a href="${escapeHtml(report.readinessHref)}">Readiness</a>` : ""}${report.operationsRecordHref ? `<a href="${escapeHtml(report.operationsRecordHref)}">Operations record</a>` : ""}</p><section class="summary"><div class="metric"><span>Input</span><strong>${escapeHtml(formatLabel(report.inputFormat))}</strong></div><div class="metric"><span>Output</span><strong>${escapeHtml(formatLabel(report.outputFormat))}</strong></div><div class="metric"><span>Browser capture</span><strong>${escapeHtml(report.browserCapture ? `${String(report.browserCapture.sampleRateHz)}hz` : "missing")}</strong></div><div class="metric"><span>Resampling</span><strong>${report.browserCapture?.resamplingRequired ? "required" : "not required"}</strong></div><div class="metric"><span>Input samples</span><strong>${String(report.runtime.inputAudioSamples)}</strong></div><div class="metric"><span>Assistant samples</span><strong>${String(report.runtime.assistantAudioSamples)}</strong></div></section></section><section class="card"><h2>Issues</h2><ul>${issues || '<li class="pass">No realtime channel issues.</li>'}</ul></section><section class="card"><h2>Runtime Samples</h2><table><thead><tr><th>Kind</th><th>Source</th><th>Format</th><th>Latency ms</th><th>OK</th></tr></thead><tbody>${rows || '<tr><td colspan="5">No runtime samples configured.</td></tr>'}</tbody></table></section></main></body></html>`;
|
|
35708
35663
|
};
|
|
35709
35664
|
var createVoiceRealtimeChannelRoutes = (options) => {
|
|
35710
35665
|
const path = options.path ?? "/api/voice/realtime-channel";
|
|
@@ -35779,14 +35734,13 @@ var defaultProviderEnv2 = {
|
|
|
35779
35734
|
"openai-realtime": ["OPENAI_API_KEY"]
|
|
35780
35735
|
};
|
|
35781
35736
|
var defaultRealtimeProviders = ["openai-realtime", "gemini-live"];
|
|
35782
|
-
var
|
|
35737
|
+
var statusRank6 = {
|
|
35783
35738
|
pass: 0,
|
|
35784
35739
|
warn: 1,
|
|
35785
35740
|
fail: 2
|
|
35786
35741
|
};
|
|
35787
|
-
var statusExceeds2 = (actual, max) =>
|
|
35788
|
-
var rollupStatus4 = (checks) => checks.
|
|
35789
|
-
var escapeHtml52 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
35742
|
+
var statusExceeds2 = (actual, max) => statusRank6[actual] > statusRank6[max];
|
|
35743
|
+
var rollupStatus4 = (checks) => worstVoiceStatus(checks.map((check) => check.status));
|
|
35790
35744
|
var resolveProviderHref = (value, provider) => typeof value === "string" ? value : value?.[provider];
|
|
35791
35745
|
var createVoiceRealtimeProviderContractMatrixPreset = (options = {}) => {
|
|
35792
35746
|
const providers = options.providers ?? defaultRealtimeProviders;
|
|
@@ -35960,10 +35914,10 @@ var assertVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
|
35960
35914
|
var resolveMatrix = async (matrix) => typeof matrix === "function" ? await matrix() : matrix;
|
|
35961
35915
|
var renderVoiceRealtimeProviderContractHTML = (report, title = "Voice Realtime Provider Contracts") => {
|
|
35962
35916
|
const rows = report.rows.map((row) => {
|
|
35963
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
35964
|
-
return `<article class="row ${
|
|
35917
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml(check.status)}"><strong>${escapeHtml(check.label)}</strong><span>${escapeHtml(check.detail ?? check.status)}</span></li>`).join("");
|
|
35918
|
+
return `<article class="row ${escapeHtml(row.status)}"><div><p class="eyebrow">${row.selected ? "selected" : "available"}</p><h2>${escapeHtml(row.provider)}</h2><p class="status ${escapeHtml(row.status)}">${escapeHtml(row.status)}</p></div><ul>${checks}</ul></article>`;
|
|
35965
35919
|
}).join("");
|
|
35966
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
35920
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.row{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.1))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.row{display:grid;gap:18px;grid-template-columns:minmax(190px,.4fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#101814;border:1px solid #2e3d36;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.pass{color:#86efac}.warn{color:#fde68a}.fail{color:#fecaca}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime provider contracts</p><h1>${escapeHtml(title)}</h1><p>Provider-level proof for duplex audio, browser format negotiation, turn commit, latency, reconnect, barge-in, trace evidence, fallback, and readiness gates.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section>${rows || '<article class="row"><p>No realtime provider contracts configured.</p></article>'}</main></body></html>`;
|
|
35967
35921
|
};
|
|
35968
35922
|
var createVoiceRealtimeProviderContractRoutes = (options) => {
|
|
35969
35923
|
const path = options.path ?? "/api/voice/realtime-provider-contracts";
|
|
@@ -35997,7 +35951,6 @@ var createVoiceRealtimeProviderContractRoutes = (options) => {
|
|
|
35997
35951
|
|
|
35998
35952
|
// src/reconnectContract.ts
|
|
35999
35953
|
import { Elysia as Elysia61 } from "elysia";
|
|
36000
|
-
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
36001
35954
|
var unique2 = (values) => [...new Set(values)];
|
|
36002
35955
|
var isReconnectPayload = (value) => {
|
|
36003
35956
|
if (!value || typeof value !== "object") {
|
|
@@ -36210,8 +36163,8 @@ var createVoiceReconnectProofRoutes = (options = {}) => {
|
|
|
36210
36163
|
});
|
|
36211
36164
|
};
|
|
36212
36165
|
var renderVoiceReconnectContractHTML = (report) => {
|
|
36213
|
-
const issues = report.issues.map((issue) => `<li class="${
|
|
36214
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Reconnect Contract</title><style>body{background:#0d1117;color:#f8fafc;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,.card{background:#151b23;border:1px solid #30363d;border-radius:18px;margin-bottom:16px;padding:20px}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.25rem,7vw,4.5rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0d1117;border:1px solid #30363d;border-radius:999px;padding:7px 10px}.pass{color:#86efac}.fail,.error{color:#fca5a5}.warning{color:#fde68a}li{margin:8px 0}</style></head><body><main><section class="hero"><p class="eyebrow">Reconnect Resume Proof</p><h1>Voice reconnect contract</h1><div class="summary"><span class="pill ${report.pass ? "pass" : "fail"}">${report.pass ? "pass" : "fail"}</span><span class="pill">${String(report.snapshotCount)} snapshots</span><span class="pill">${String(report.summary.attempts)} attempts</span><span class="pill">statuses ${
|
|
36166
|
+
const issues = report.issues.map((issue) => `<li class="${escapeHtml(issue.severity)}"><strong>${escapeHtml(issue.code)}</strong>: ${escapeHtml(issue.message)}</li>`).join("");
|
|
36167
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Reconnect Contract</title><style>body{background:#0d1117;color:#f8fafc;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,.card{background:#151b23;border:1px solid #30363d;border-radius:18px;margin-bottom:16px;padding:20px}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.25rem,7vw,4.5rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0d1117;border:1px solid #30363d;border-radius:999px;padding:7px 10px}.pass{color:#86efac}.fail,.error{color:#fca5a5}.warning{color:#fde68a}li{margin:8px 0}</style></head><body><main><section class="hero"><p class="eyebrow">Reconnect Resume Proof</p><h1>Voice reconnect contract</h1><div class="summary"><span class="pill ${report.pass ? "pass" : "fail"}">${report.pass ? "pass" : "fail"}</span><span class="pill">${String(report.snapshotCount)} snapshots</span><span class="pill">${String(report.summary.attempts)} attempts</span><span class="pill">statuses ${escapeHtml(report.statuses.join(", ") || "none")}</span></div></section><section class="card"><h2>Summary</h2><p>reconnected ${String(report.summary.reconnected)} \xB7 resumed ${String(report.summary.resumed)} \xB7 exhausted ${String(report.summary.exhausted)} \xB7 duplicate turns ${String(report.summary.duplicateTurnIds.length)}</p></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No contract issues.</p>'}</section></main></body></html>`;
|
|
36215
36168
|
};
|
|
36216
36169
|
var createVoiceReconnectContractRoutes = (options) => {
|
|
36217
36170
|
const path = options.path ?? "/api/voice/reconnect-contract";
|
|
@@ -36458,7 +36411,6 @@ var createDefaultTurn = (caseId) => ({
|
|
|
36458
36411
|
});
|
|
36459
36412
|
var defaultApi = {};
|
|
36460
36413
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
36461
|
-
var escapeHtml54 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
36462
36414
|
var resolveSessionHref5 = (value, sessionId) => {
|
|
36463
36415
|
if (value === false) {
|
|
36464
36416
|
return;
|
|
@@ -36709,7 +36661,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
36709
36661
|
};
|
|
36710
36662
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
36711
36663
|
const title = options.title ?? "Voice Tool Contracts";
|
|
36712
|
-
const snippet =
|
|
36664
|
+
const snippet = escapeHtml(`app.use(
|
|
36713
36665
|
createVoiceToolContractRoutes({
|
|
36714
36666
|
htmlPath: '/tool-contracts',
|
|
36715
36667
|
path: '/api/tool-contracts',
|
|
@@ -36735,20 +36687,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
36735
36687
|
);`);
|
|
36736
36688
|
const contracts = report.contracts.map((contract) => {
|
|
36737
36689
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
36738
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
36690
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml(testCase.operationsRecordHref)}">${escapeHtml(testCase.label ?? testCase.caseId)}</a>` : escapeHtml(testCase.label ?? testCase.caseId)}</td>
|
|
36739
36691
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
36740
|
-
<td>${
|
|
36741
|
-
<td>${
|
|
36692
|
+
<td>${escapeHtml(testCase.status)}</td>
|
|
36693
|
+
<td>${escapeHtml(testCase.sessionId)}</td>
|
|
36742
36694
|
<td>${String(testCase.attempts)}</td>
|
|
36743
36695
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
36744
36696
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
36745
|
-
<td>${
|
|
36697
|
+
<td>${escapeHtml(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
36746
36698
|
</tr>`).join("");
|
|
36747
36699
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
36748
36700
|
<div class="contract-header">
|
|
36749
36701
|
<div>
|
|
36750
|
-
<p class="eyebrow">${
|
|
36751
|
-
<h2>${
|
|
36702
|
+
<p class="eyebrow">${escapeHtml(contract.toolName)}</p>
|
|
36703
|
+
<h2>${escapeHtml(contract.label ?? contract.contractId)}</h2>
|
|
36752
36704
|
</div>
|
|
36753
36705
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
36754
36706
|
</div>
|
|
@@ -36758,7 +36710,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
36758
36710
|
</table>
|
|
36759
36711
|
</section>`;
|
|
36760
36712
|
}).join("");
|
|
36761
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
36713
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.primitive{background:#151b20;border-color:#5a4421}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}.primitive p{color:#d8dee6;line-height:1.55}.primitive pre{background:#0f1217;border:1px solid #2a323a;border-radius:16px;color:#fef3c7;overflow:auto;padding:14px}.primitive code{color:#fef3c7}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceToolContractRoutes(...)</code> certifies tool behavior</h2><p>Define deterministic tool cases for retries, idempotency, timeouts, result shape, and error handling so assistant tools fail in pre-production instead of live calls.</p><pre><code>${snippet}</code></pre></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
|
|
36762
36714
|
};
|
|
36763
36715
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
36764
36716
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -36785,7 +36737,6 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
36785
36737
|
};
|
|
36786
36738
|
|
|
36787
36739
|
// src/simulationSuite.ts
|
|
36788
|
-
var escapeHtml55 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
36789
36740
|
var summarizeSection = (report) => ({
|
|
36790
36741
|
failed: report.failed,
|
|
36791
36742
|
passed: report.passed,
|
|
@@ -36981,15 +36932,15 @@ var renderSection = (label, summary) => {
|
|
|
36981
36932
|
if (!summary) {
|
|
36982
36933
|
return "";
|
|
36983
36934
|
}
|
|
36984
|
-
return `<article class="${
|
|
36935
|
+
return `<article class="${escapeHtml(summary.status)}"><span>${escapeHtml(label)}</span><strong>${escapeHtml(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
36985
36936
|
};
|
|
36986
36937
|
var renderAction = (action) => {
|
|
36987
|
-
const content = `<strong>${
|
|
36988
|
-
return action.href ? `<a class="action" href="${
|
|
36938
|
+
const content = `<strong>${escapeHtml(action.label)}</strong><p>${escapeHtml(action.description)}</p><span>${escapeHtml(action.section)} / ${escapeHtml(action.severity)}</span>`;
|
|
36939
|
+
return action.href ? `<a class="action" href="${escapeHtml(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
36989
36940
|
};
|
|
36990
36941
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
36991
36942
|
const title = options.title ?? "Voice Simulation Suite";
|
|
36992
|
-
const snippet =
|
|
36943
|
+
const snippet = escapeHtml(`app.use(
|
|
36993
36944
|
createVoiceSimulationSuiteRoutes({
|
|
36994
36945
|
htmlPath: '/voice/simulations',
|
|
36995
36946
|
path: '/api/voice/simulations',
|
|
@@ -37022,7 +36973,7 @@ app.use(
|
|
|
37022
36973
|
store: traceStore
|
|
37023
36974
|
})
|
|
37024
36975
|
);`);
|
|
37025
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
36976
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#355078}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p,.primitive p{color:#d8dee6;line-height:1.55;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}.primitive pre{background:#0b1118;color:#dbeafe}.primitive code{color:#bfdbfe}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceSimulationSuiteRoutes(...)</code> builds this pre-production proof surface</h2><p>Run session quality checks, scenario evals, fixture-backed simulations, tool contracts, and outcome contracts from one route group before live traffic sees a regression.</p><pre><code>${snippet}</code></pre></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
37026
36977
|
};
|
|
37027
36978
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
37028
36979
|
const path = options.path ?? "/api/voice/simulations";
|
|
@@ -37228,7 +37179,6 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
37228
37179
|
};
|
|
37229
37180
|
};
|
|
37230
37181
|
var escapeMarkdown3 = (value) => value.replaceAll("|", "\\|");
|
|
37231
|
-
var escapeHtml56 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37232
37182
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
37233
37183
|
var readinessThresholdRows = (report) => [
|
|
37234
37184
|
{
|
|
@@ -37319,10 +37269,10 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
37319
37269
|
};
|
|
37320
37270
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
37321
37271
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
37322
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
37323
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
37324
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
37325
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
37272
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml(row.control)}</td><td>${escapeHtml(formatMs5(row.value))}</td><td>${escapeHtml(row.usedBy)}</td></tr>`).join("");
|
|
37273
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("");
|
|
37274
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml(source)}</code></li>`).join("");
|
|
37275
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1040px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}.status{font-size:1.6rem;font-weight:800;text-transform:uppercase}</style></head><body><main><h1>${escapeHtml(title)}</h1><p>This page shows the calibrated thresholds currently driving production readiness gates.</p><section class="summary"><div class="card"><strong>Status</strong><br><span class="status">${escapeHtml(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml(formatMs5(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml(formatMs5(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml(formatMs5(report.bargeIn.thresholdMs))}</div></section><h2>Active Readiness Thresholds</h2><table><thead><tr><th>Threshold</th><th>Active value</th><th>Used by</th></tr></thead><tbody>${rows}</tbody></table><h2>Sources</h2><ul>${sources}</ul><h2>Issues</h2><ul>${issues}</ul></main></body></html>`;
|
|
37326
37276
|
};
|
|
37327
37277
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
37328
37278
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
@@ -37480,7 +37430,6 @@ var byteLength2 = (audio) => {
|
|
|
37480
37430
|
}
|
|
37481
37431
|
return audio instanceof ArrayBuffer ? audio.byteLength : audio.byteLength;
|
|
37482
37432
|
};
|
|
37483
|
-
var escapeHtml57 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37484
37433
|
var buildVoiceTelephonyMediaReport = (input = {}) => {
|
|
37485
37434
|
const carriers = input.carriers ?? [
|
|
37486
37435
|
{ carrier: "twilio" },
|
|
@@ -37569,8 +37518,8 @@ var getLatestVoiceTelephonyMediaReport = async (options) => {
|
|
|
37569
37518
|
};
|
|
37570
37519
|
var renderVoiceTelephonyMediaHTML = (report, options = {}) => {
|
|
37571
37520
|
const title = options.title ?? "Voice Telephony Media Proof";
|
|
37572
|
-
const rows = report.carriers.map((carrier) => `<tr><td>${
|
|
37573
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
37521
|
+
const rows = report.carriers.map((carrier) => `<tr><td>${escapeHtml(carrier.carrier)}</td><td>${escapeHtml(carrier.status)}</td><td>${String(carrier.audioBytes)}</td><td>${String(carrier.lifecycle.mediaEvents)}</td><td>${escapeHtml(carrier.lifecycle.started ? "yes" : "no")}</td><td>${escapeHtml(carrier.lifecycle.stopped ? "yes" : "no")}</td><td>${escapeHtml(carrier.frame?.kind ?? "missing")}</td><td>${escapeHtml(carrier.frame?.format?.encoding ?? "missing")}</td><td>${escapeHtml(carrier.issues.join(" ") || "none")}</td></tr>`).join("");
|
|
37522
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#111827;color:#e5e7eb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,table{background:#0f172a;border:1px solid #334155;border-radius:20px;margin-bottom:16px}.hero{padding:22px}.eyebrow{color:#67e8f9;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fecaca}code{color:#bfdbfe}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #334155;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Carrier media serializer proof</p><h1>${escapeHtml(title)}</h1><p class="status ${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><p>Twilio, Telnyx, and Plivo media payload envelopes are parsed into generic <code>MediaFrame</code> objects, serialized back into carrier envelopes, and checked for start/media/stop lifecycle sequencing by <code>@absolutejs/media</code>.</p></section><table><thead><tr><th>Carrier</th><th>Status</th><th>Audio bytes</th><th>Media events</th><th>Started</th><th>Stopped</th><th>Frame kind</th><th>Encoding</th><th>Issues</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
37574
37523
|
};
|
|
37575
37524
|
var createVoiceTelephonyMediaRoutes = (options = {}) => {
|
|
37576
37525
|
const path = options.path ?? "/api/voice/telephony/media";
|
|
@@ -37601,7 +37550,6 @@ var createVoiceTelephonyMediaRoutes = (options = {}) => {
|
|
|
37601
37550
|
|
|
37602
37551
|
// src/traceDeliveryRoutes.ts
|
|
37603
37552
|
import { Elysia as Elysia66 } from "elysia";
|
|
37604
|
-
var escapeHtml58 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37605
37553
|
var getString19 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
37606
37554
|
var getNumber12 = (value) => {
|
|
37607
37555
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -37682,14 +37630,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
37682
37630
|
if (entries.length === 0) {
|
|
37683
37631
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
37684
37632
|
}
|
|
37685
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
37633
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml(sinkId)}</strong>: ${escapeHtml(result.status)}${result.deliveredTo ? ` to ${escapeHtml(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
37686
37634
|
};
|
|
37687
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
37635
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml(event.type)} <small>${escapeHtml(event.id)}</small>${event.sessionId ? ` session=${escapeHtml(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
37688
37636
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
37689
37637
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
37690
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
37691
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
37692
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
37638
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
37639
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml(delivery.deliveryStatus)}</span><h2>${escapeHtml(delivery.id)}</h2><p>${escapeHtml(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
37640
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(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>${escapeHtml(title)}</h1><p>Checked ${escapeHtml(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>`;
|
|
37693
37641
|
};
|
|
37694
37642
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
37695
37643
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -37731,7 +37679,6 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
37731
37679
|
import { Elysia as Elysia67 } from "elysia";
|
|
37732
37680
|
var DEFAULT_WARN_AFTER_MS2 = 1800;
|
|
37733
37681
|
var DEFAULT_FAIL_AFTER_MS2 = 3200;
|
|
37734
|
-
var escapeHtml59 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37735
37682
|
var firstNumber3 = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
37736
37683
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
37737
37684
|
var createTraceStageIndex = (events) => {
|
|
@@ -37867,11 +37814,11 @@ await traceStore.append({
|
|
|
37867
37814
|
turnId,
|
|
37868
37815
|
type: 'turn_latency.stage'
|
|
37869
37816
|
});`;
|
|
37870
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
37871
|
-
<header><div><p class="eyebrow">${
|
|
37872
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
37817
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml(turn.status)}">
|
|
37818
|
+
<header><div><p class="eyebrow">${escapeHtml(turn.sessionId)} \xB7 ${escapeHtml(turn.turnId)}</p><h2>${escapeHtml(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml(turn.status)}</strong></header>
|
|
37819
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml(stage.label)}</dt><dd>${escapeHtml(formatMs6(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
37873
37820
|
</article>`).join("");
|
|
37874
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
37821
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn,.primitive{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml(title)}</h1><div class="summary"><span class="pill ${escapeHtml(report.status)}">${escapeHtml(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml(formatMs6(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
37875
37822
|
};
|
|
37876
37823
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
37877
37824
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -37900,7 +37847,6 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
37900
37847
|
// src/turnQuality.ts
|
|
37901
37848
|
import { Elysia as Elysia68 } from "elysia";
|
|
37902
37849
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
37903
|
-
var escapeHtml60 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37904
37850
|
var getTurnLatencyMs = (turn) => {
|
|
37905
37851
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
37906
37852
|
if (firstTranscriptAt === undefined) {
|
|
@@ -37970,24 +37916,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
37970
37916
|
};
|
|
37971
37917
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
37972
37918
|
const title = options.title ?? "Voice Turn Quality";
|
|
37973
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
37919
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml(turn.status)}">
|
|
37974
37920
|
<div class="turn-header">
|
|
37975
37921
|
<div>
|
|
37976
|
-
<p class="eyebrow">${
|
|
37977
|
-
<h2>${
|
|
37922
|
+
<p class="eyebrow">${escapeHtml(turn.sessionId)} \xB7 ${escapeHtml(turn.turnId)}</p>
|
|
37923
|
+
<h2>${escapeHtml(turn.text || "Empty turn")}</h2>
|
|
37978
37924
|
</div>
|
|
37979
|
-
<strong>${
|
|
37925
|
+
<strong>${escapeHtml(turn.status)}</strong>
|
|
37980
37926
|
</div>
|
|
37981
37927
|
<dl>
|
|
37982
|
-
<div><dt>Source</dt><dd>${
|
|
37928
|
+
<div><dt>Source</dt><dd>${escapeHtml(turn.source ?? "unknown")}</dd></div>
|
|
37983
37929
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
37984
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
37985
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
37930
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
37931
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
37986
37932
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
37987
37933
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
37988
37934
|
</dl>
|
|
37989
37935
|
</article>`).join("");
|
|
37990
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
37936
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.unknown{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml(title)}</h1><div class="summary"><span class="pill ${escapeHtml(report.status)}">${escapeHtml(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
37991
37937
|
};
|
|
37992
37938
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
37993
37939
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -38015,9 +37961,8 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
38015
37961
|
|
|
38016
37962
|
// src/voiceMonitoring.ts
|
|
38017
37963
|
import { Elysia as Elysia69 } from "elysia";
|
|
38018
|
-
var escapeHtml61 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
38019
37964
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
38020
|
-
var rollupStatus5 = (runs) => runs.
|
|
37965
|
+
var rollupStatus5 = (runs) => worstVoiceStatus(runs.map((run) => run.status));
|
|
38021
37966
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
38022
37967
|
const issues = new Map(initial.map((issue) => [issue.id, { ...issue }]));
|
|
38023
37968
|
return {
|
|
@@ -38268,14 +38213,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
38268
38213
|
};
|
|
38269
38214
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
38270
38215
|
const title = options.title ?? "Voice Monitors";
|
|
38271
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
38272
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
38273
|
-
const snippet =
|
|
38216
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml(run.label)}</td><td class="${escapeHtml(run.status)}">${escapeHtml(run.status)}</td><td>${escapeHtml(run.severity)}</td><td>${escapeHtml(String(run.value ?? ""))}</td><td>${escapeHtml(String(run.threshold ?? ""))}</td><td>${escapeHtml(run.detail ?? "")}</td></tr>`).join("");
|
|
38217
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml(issue.label)}</strong> <span class="${escapeHtml(issue.status)}">${escapeHtml(issue.status)}</span> ${escapeHtml(issue.detail ?? "")}</li>`).join("");
|
|
38218
|
+
const snippet = escapeHtml(`app.use(createVoiceMonitorRoutes({
|
|
38274
38219
|
evidence,
|
|
38275
38220
|
issueStore,
|
|
38276
38221
|
monitors: [defineVoiceMonitor(...)]
|
|
38277
38222
|
}));`);
|
|
38278
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
38223
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml(title)}</h1><p class="pill ${escapeHtml(report.status)}">Status: ${escapeHtml(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
38279
38224
|
};
|
|
38280
38225
|
var actorFromRequest = async (request) => {
|
|
38281
38226
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -40568,9 +40513,7 @@ var createVoiceLLMJudge = (options) => ({
|
|
|
40568
40513
|
rubric: options.rubric
|
|
40569
40514
|
});
|
|
40570
40515
|
var createVoiceAIJudgeCompletion = (options) => async ({ prompt, systemPrompt }) => {
|
|
40571
|
-
const messages = [
|
|
40572
|
-
{ content: prompt, role: "user" }
|
|
40573
|
-
];
|
|
40516
|
+
const messages = [{ content: prompt, role: "user" }];
|
|
40574
40517
|
const stream = options.provider.stream({
|
|
40575
40518
|
messages,
|
|
40576
40519
|
model: options.model,
|
|
@@ -40698,7 +40641,13 @@ var successRateFor = (calls, successOutcomes) => {
|
|
|
40698
40641
|
return successes / flagged.length;
|
|
40699
40642
|
};
|
|
40700
40643
|
var buildVoiceVariableAnalytics = (input) => {
|
|
40701
|
-
const successOutcomes = new Set((input.successOutcomes ?? [
|
|
40644
|
+
const successOutcomes = new Set((input.successOutcomes ?? [
|
|
40645
|
+
"won",
|
|
40646
|
+
"resolved",
|
|
40647
|
+
"qualified",
|
|
40648
|
+
"completed",
|
|
40649
|
+
"booked"
|
|
40650
|
+
]).map((outcome) => outcome.toLowerCase()));
|
|
40702
40651
|
const totalCalls = input.calls.length;
|
|
40703
40652
|
const overall = {
|
|
40704
40653
|
avgCostUsd: mean(input.calls.map((call) => call.costUsd).filter((cost) => typeof cost === "number")),
|
|
@@ -43213,7 +43162,6 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
43213
43162
|
"completed",
|
|
43214
43163
|
"failed"
|
|
43215
43164
|
];
|
|
43216
|
-
var escapeHtml62 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
43217
43165
|
var loadRouteJson = async (input) => {
|
|
43218
43166
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
43219
43167
|
headers: {
|
|
@@ -43451,10 +43399,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
43451
43399
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
43452
43400
|
const urls = entry?.setup.urls;
|
|
43453
43401
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
43454
|
-
return `<tr><td>${
|
|
43402
|
+
return `<tr><td>${escapeHtml(carrier.name ?? carrier.provider)}</td><td>${escapeHtml(carrier.provider)}</td><td><code>${escapeHtml(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml(entry.status)}">${escapeHtml(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
43455
43403
|
}).join("");
|
|
43456
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
43457
|
-
const snippet =
|
|
43404
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml(stage)}</code></li>`).join("");
|
|
43405
|
+
const snippet = escapeHtml(`const phoneAgent = createVoicePhoneAgent({
|
|
43458
43406
|
carriers: [
|
|
43459
43407
|
{
|
|
43460
43408
|
provider: 'twilio',
|
|
@@ -43488,11 +43436,11 @@ app.use(
|
|
|
43488
43436
|
);`);
|
|
43489
43437
|
const checklist = report.carriers.map((carrier) => {
|
|
43490
43438
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
43491
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
43492
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
43493
|
-
return `<article><h3>${
|
|
43439
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("") ?? "";
|
|
43440
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml(step)}</li>`).join("") ?? "";
|
|
43441
|
+
return `<article><h3>${escapeHtml(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
43494
43442
|
}).join("");
|
|
43495
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
43443
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive{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}.primitive{background:#151d27;border-color:#365a60}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.primitive p{color:#cbd5de;line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #283544;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml(report.title)}</h1><p>One self-hosted entrypoint for carrier routes, setup reports, smoke checks, and normalized call lifecycle stages.</p><p class="badge ${report.ready ? "pass" : "fail"}">Ready: ${String(report.ready)}</p>${report.matrixPath ? `<p><a href="${escapeHtml(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoicePhoneAgent(...)</code> builds this carrier control plane</h2><p>Mount carrier routes once, expose setup and smoke proof, then feed the same carrier matrix and phone-agent smoke reports into production readiness so carrier regressions block deploys.</p><pre><code>${snippet}</code></pre></section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
|
|
43496
43444
|
};
|
|
43497
43445
|
var createVoicePhoneAgent = (options) => {
|
|
43498
43446
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -47128,367 +47076,6 @@ var createVoiceSTTRoutingCorrectionHandler = (mode = "generic") => {
|
|
|
47128
47076
|
}
|
|
47129
47077
|
return createPhraseHintCorrectionHandler();
|
|
47130
47078
|
};
|
|
47131
|
-
// src/testing/telephony.ts
|
|
47132
|
-
var DEFAULT_PCM16_FORMAT = {
|
|
47133
|
-
channels: 1,
|
|
47134
|
-
container: "raw",
|
|
47135
|
-
encoding: "pcm_s16le",
|
|
47136
|
-
sampleRateHz: 16000
|
|
47137
|
-
};
|
|
47138
|
-
var DEFAULT_SCENARIOS = [
|
|
47139
|
-
{
|
|
47140
|
-
expectClear: false,
|
|
47141
|
-
expectMark: true,
|
|
47142
|
-
expectOutboundMedia: true,
|
|
47143
|
-
id: "telephony-turn",
|
|
47144
|
-
title: "Telephony bridge streams assistant audio and mark"
|
|
47145
|
-
},
|
|
47146
|
-
{
|
|
47147
|
-
expectClear: true,
|
|
47148
|
-
expectMark: true,
|
|
47149
|
-
expectOutboundMedia: true,
|
|
47150
|
-
id: "telephony-barge-in",
|
|
47151
|
-
secondInboundDelayMs: 5,
|
|
47152
|
-
title: "Telephony bridge clears queued outbound audio on barge-in"
|
|
47153
|
-
},
|
|
47154
|
-
{
|
|
47155
|
-
expectClear: true,
|
|
47156
|
-
expectMark: true,
|
|
47157
|
-
expectOutboundMedia: true,
|
|
47158
|
-
id: "telephony-streaming",
|
|
47159
|
-
secondInboundDelayMs: 8,
|
|
47160
|
-
title: "Telephony bridge keeps streaming chunks and still clears on re-entry",
|
|
47161
|
-
ttsChunkCount: 3,
|
|
47162
|
-
ttsChunkDelayMs: 4
|
|
47163
|
-
}
|
|
47164
|
-
];
|
|
47165
|
-
var waitFor = async (check, timeoutMs, intervalMs = 5) => {
|
|
47166
|
-
const deadline = Date.now() + timeoutMs;
|
|
47167
|
-
while (Date.now() < deadline) {
|
|
47168
|
-
if (check()) {
|
|
47169
|
-
return true;
|
|
47170
|
-
}
|
|
47171
|
-
await Bun.sleep(intervalMs);
|
|
47172
|
-
}
|
|
47173
|
-
return check();
|
|
47174
|
-
};
|
|
47175
|
-
var toUint8Array2 = (audio) => audio instanceof Uint8Array ? audio : audio instanceof ArrayBuffer ? new Uint8Array(audio) : new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
47176
|
-
var createFakeSTTAdapter = (inputSpy, sttDelayMs) => ({
|
|
47177
|
-
kind: "stt",
|
|
47178
|
-
open: (_options) => {
|
|
47179
|
-
const listeners = {
|
|
47180
|
-
close: new Set,
|
|
47181
|
-
endOfTurn: new Set,
|
|
47182
|
-
error: new Set,
|
|
47183
|
-
final: new Set,
|
|
47184
|
-
partial: new Set
|
|
47185
|
-
};
|
|
47186
|
-
let delivered = false;
|
|
47187
|
-
return {
|
|
47188
|
-
close: async () => {
|
|
47189
|
-
for (const handler of listeners.close) {
|
|
47190
|
-
handler({ type: "close" });
|
|
47191
|
-
}
|
|
47192
|
-
},
|
|
47193
|
-
on: (event, handler) => {
|
|
47194
|
-
listeners[event].add(handler);
|
|
47195
|
-
return () => {
|
|
47196
|
-
listeners[event].delete(handler);
|
|
47197
|
-
};
|
|
47198
|
-
},
|
|
47199
|
-
send: async (audio) => {
|
|
47200
|
-
inputSpy.push(toUint8Array2(audio));
|
|
47201
|
-
if (delivered) {
|
|
47202
|
-
return;
|
|
47203
|
-
}
|
|
47204
|
-
delivered = true;
|
|
47205
|
-
if (sttDelayMs > 0) {
|
|
47206
|
-
await Bun.sleep(sttDelayMs);
|
|
47207
|
-
}
|
|
47208
|
-
const receivedAt = Date.now();
|
|
47209
|
-
for (const handler of listeners.final) {
|
|
47210
|
-
handler({
|
|
47211
|
-
receivedAt,
|
|
47212
|
-
transcript: {
|
|
47213
|
-
id: "telephony-benchmark-final",
|
|
47214
|
-
isFinal: true,
|
|
47215
|
-
text: "hello from twilio"
|
|
47216
|
-
},
|
|
47217
|
-
type: "final"
|
|
47218
|
-
});
|
|
47219
|
-
}
|
|
47220
|
-
for (const handler of listeners.endOfTurn) {
|
|
47221
|
-
handler({
|
|
47222
|
-
receivedAt,
|
|
47223
|
-
reason: "vendor",
|
|
47224
|
-
type: "endOfTurn"
|
|
47225
|
-
});
|
|
47226
|
-
}
|
|
47227
|
-
}
|
|
47228
|
-
};
|
|
47229
|
-
}
|
|
47230
|
-
});
|
|
47231
|
-
var createFakeTTSAdapter = (chunkCount, chunkDelayMs) => ({
|
|
47232
|
-
kind: "tts",
|
|
47233
|
-
open: () => {
|
|
47234
|
-
const listeners = {
|
|
47235
|
-
audio: new Set,
|
|
47236
|
-
close: new Set,
|
|
47237
|
-
error: new Set
|
|
47238
|
-
};
|
|
47239
|
-
return {
|
|
47240
|
-
close: async () => {
|
|
47241
|
-
for (const handler of listeners.close) {
|
|
47242
|
-
handler({ type: "close" });
|
|
47243
|
-
}
|
|
47244
|
-
},
|
|
47245
|
-
on: (event, handler) => {
|
|
47246
|
-
listeners[event].add(handler);
|
|
47247
|
-
return () => {
|
|
47248
|
-
listeners[event].delete(handler);
|
|
47249
|
-
};
|
|
47250
|
-
},
|
|
47251
|
-
send: async () => {
|
|
47252
|
-
for (let index = 0;index < chunkCount; index += 1) {
|
|
47253
|
-
if (chunkDelayMs > 0) {
|
|
47254
|
-
await Bun.sleep(chunkDelayMs);
|
|
47255
|
-
}
|
|
47256
|
-
const chunk = new Uint8Array(320);
|
|
47257
|
-
for (let byteIndex = 0;byteIndex < chunk.length; byteIndex += 2) {
|
|
47258
|
-
chunk[byteIndex] = 255;
|
|
47259
|
-
chunk[byteIndex + 1] = 31;
|
|
47260
|
-
}
|
|
47261
|
-
for (const handler of listeners.audio) {
|
|
47262
|
-
handler({
|
|
47263
|
-
chunk,
|
|
47264
|
-
format: DEFAULT_PCM16_FORMAT,
|
|
47265
|
-
receivedAt: Date.now(),
|
|
47266
|
-
type: "audio"
|
|
47267
|
-
});
|
|
47268
|
-
}
|
|
47269
|
-
}
|
|
47270
|
-
}
|
|
47271
|
-
};
|
|
47272
|
-
}
|
|
47273
|
-
});
|
|
47274
|
-
var defaultOperationsRecordHref = ({
|
|
47275
|
-
sessionId
|
|
47276
|
-
}) => `/voice-operations/${encodeURIComponent(sessionId)}`;
|
|
47277
|
-
var resolveOperationsRecordHref3 = (href, input) => typeof href === "function" ? href(input) : href === undefined ? defaultOperationsRecordHref(input) : href;
|
|
47278
|
-
var runVoiceTelephonyMediaOperationsSmoke = async (options = {}) => {
|
|
47279
|
-
const timeoutMs = options.timeoutMs ?? 5000;
|
|
47280
|
-
const sessionId = options.sessionId ?? `telephony-media-ops-${Date.now()}`;
|
|
47281
|
-
const streamSid = options.streamSid ?? "telephony-media-ops-stream";
|
|
47282
|
-
const callSid = options.callSid ?? "telephony-media-ops-call";
|
|
47283
|
-
const scenarioId = options.scenarioId ?? "telephony-media-operations-smoke";
|
|
47284
|
-
const trace = options.store ?? createVoiceMemoryTraceEventStore();
|
|
47285
|
-
const sentEvents = [];
|
|
47286
|
-
const receivedAudio = [];
|
|
47287
|
-
const bridge = createTwilioMediaStreamBridge({
|
|
47288
|
-
close: () => {},
|
|
47289
|
-
send: (data) => {
|
|
47290
|
-
sentEvents.push(JSON.parse(data));
|
|
47291
|
-
}
|
|
47292
|
-
}, {
|
|
47293
|
-
context: {},
|
|
47294
|
-
onComplete: async () => {},
|
|
47295
|
-
onTurn: async () => ({
|
|
47296
|
-
assistantText: "Confirmed. Two way carrier media is visible."
|
|
47297
|
-
}),
|
|
47298
|
-
session: createVoiceMemoryStore(),
|
|
47299
|
-
stt: createFakeSTTAdapter(receivedAudio, 0),
|
|
47300
|
-
trace,
|
|
47301
|
-
tts: createFakeTTSAdapter(1, 0),
|
|
47302
|
-
turnDetection: {
|
|
47303
|
-
transcriptStabilityMs: 0
|
|
47304
|
-
}
|
|
47305
|
-
});
|
|
47306
|
-
const payload = encodeTwilioMulawBase64(new Int16Array([500, -500, 1500, -1500, 2500, -2500]));
|
|
47307
|
-
await bridge.handleMessage({
|
|
47308
|
-
event: "start",
|
|
47309
|
-
start: {
|
|
47310
|
-
callSid,
|
|
47311
|
-
customParameters: {
|
|
47312
|
-
scenarioId,
|
|
47313
|
-
sessionId
|
|
47314
|
-
},
|
|
47315
|
-
streamSid
|
|
47316
|
-
},
|
|
47317
|
-
streamSid
|
|
47318
|
-
});
|
|
47319
|
-
await bridge.handleMessage({
|
|
47320
|
-
event: "media",
|
|
47321
|
-
media: {
|
|
47322
|
-
payload,
|
|
47323
|
-
track: "inbound"
|
|
47324
|
-
},
|
|
47325
|
-
streamSid
|
|
47326
|
-
});
|
|
47327
|
-
await waitFor(() => sentEvents.some((message) => message.event === "media"), timeoutMs);
|
|
47328
|
-
await bridge.handleMessage({
|
|
47329
|
-
event: "media",
|
|
47330
|
-
media: {
|
|
47331
|
-
payload,
|
|
47332
|
-
track: "inbound"
|
|
47333
|
-
},
|
|
47334
|
-
streamSid
|
|
47335
|
-
});
|
|
47336
|
-
await waitFor(() => sentEvents.some((message) => message.event === "clear"), timeoutMs);
|
|
47337
|
-
await bridge.handleMessage({
|
|
47338
|
-
event: "stop",
|
|
47339
|
-
stop: {
|
|
47340
|
-
callSid
|
|
47341
|
-
},
|
|
47342
|
-
streamSid
|
|
47343
|
-
});
|
|
47344
|
-
await bridge.close("telephony-media-operations-smoke-complete");
|
|
47345
|
-
const operationsRecord = await buildVoiceOperationsRecord({
|
|
47346
|
-
sessionId,
|
|
47347
|
-
store: trace
|
|
47348
|
-
});
|
|
47349
|
-
const media = operationsRecord.telephonyMedia;
|
|
47350
|
-
const issues = [
|
|
47351
|
-
media.starts < 1 ? "Missing telephony media start event." : undefined,
|
|
47352
|
-
media.stops < 1 ? "Missing telephony media stop event." : undefined,
|
|
47353
|
-
media.inbound < 2 ? "Expected at least two inbound telephony media events." : undefined,
|
|
47354
|
-
media.outbound < 2 ? "Expected outbound assistant media/control evidence." : undefined,
|
|
47355
|
-
media.media < 3 ? "Expected inbound and outbound telephony media packet evidence." : undefined,
|
|
47356
|
-
media.clears < 1 ? "Missing outbound clear evidence." : undefined,
|
|
47357
|
-
media.audioBytes <= 0 ? "Missing telephony media audio bytes." : undefined,
|
|
47358
|
-
media.carriers.includes("twilio") ? undefined : "Missing Twilio carrier evidence.",
|
|
47359
|
-
media.streamIds.includes(streamSid) ? undefined : "Missing telephony media stream ID evidence."
|
|
47360
|
-
].filter((issue) => typeof issue === "string");
|
|
47361
|
-
return {
|
|
47362
|
-
issues,
|
|
47363
|
-
ok: issues.length === 0,
|
|
47364
|
-
operationsRecord,
|
|
47365
|
-
operationsRecordHref: resolveOperationsRecordHref3(options.operationsRecordHref, { sessionId, streamSid }),
|
|
47366
|
-
sentEvents: sentEvents.map((message) => message.event).filter((event) => typeof event === "string"),
|
|
47367
|
-
sessionId,
|
|
47368
|
-
streamSid,
|
|
47369
|
-
telephonyMedia: media
|
|
47370
|
-
};
|
|
47371
|
-
};
|
|
47372
|
-
var getDefaultVoiceTelephonyBenchmarkScenarios = () => DEFAULT_SCENARIOS.map((scenario) => ({ ...scenario }));
|
|
47373
|
-
var runVoiceTelephonyBenchmarkScenario = async (scenario, options = {}) => {
|
|
47374
|
-
const timeoutMs = options.timeoutMs ?? 1000;
|
|
47375
|
-
const sentEvents = [];
|
|
47376
|
-
const receivedAudio = [];
|
|
47377
|
-
const bridge = createTwilioMediaStreamBridge({
|
|
47378
|
-
close: () => {},
|
|
47379
|
-
send: (data) => {
|
|
47380
|
-
sentEvents.push({
|
|
47381
|
-
at: Date.now(),
|
|
47382
|
-
event: JSON.parse(data)
|
|
47383
|
-
});
|
|
47384
|
-
}
|
|
47385
|
-
}, {
|
|
47386
|
-
context: {},
|
|
47387
|
-
onComplete: async () => {},
|
|
47388
|
-
onTurn: async () => ({
|
|
47389
|
-
assistantText: "Copy that."
|
|
47390
|
-
}),
|
|
47391
|
-
session: createVoiceMemoryStore(),
|
|
47392
|
-
stt: createFakeSTTAdapter(receivedAudio, scenario.sttDelayMs ?? 0),
|
|
47393
|
-
tts: createFakeTTSAdapter(scenario.ttsChunkCount ?? 2, scenario.ttsChunkDelayMs ?? 0),
|
|
47394
|
-
turnDetection: {
|
|
47395
|
-
transcriptStabilityMs: 0
|
|
47396
|
-
}
|
|
47397
|
-
});
|
|
47398
|
-
const startedAt = Date.now();
|
|
47399
|
-
let secondInboundAt;
|
|
47400
|
-
try {
|
|
47401
|
-
await bridge.handleMessage({
|
|
47402
|
-
event: "start",
|
|
47403
|
-
start: {
|
|
47404
|
-
callSid: "CA-benchmark",
|
|
47405
|
-
customParameters: {
|
|
47406
|
-
scenarioId: scenario.id,
|
|
47407
|
-
sessionId: `phone-${scenario.id}`
|
|
47408
|
-
},
|
|
47409
|
-
streamSid: "MZ-benchmark"
|
|
47410
|
-
},
|
|
47411
|
-
streamSid: "MZ-benchmark"
|
|
47412
|
-
});
|
|
47413
|
-
await bridge.handleMessage({
|
|
47414
|
-
event: "media",
|
|
47415
|
-
media: {
|
|
47416
|
-
payload: encodeTwilioMulawBase64(new Int16Array([500, -500, 1500, -1500, 2500, -2500])),
|
|
47417
|
-
track: "inbound"
|
|
47418
|
-
},
|
|
47419
|
-
streamSid: "MZ-benchmark"
|
|
47420
|
-
});
|
|
47421
|
-
const sawOutboundMedia = await waitFor(() => sentEvents.some((entry) => entry.event.event === "media"), timeoutMs);
|
|
47422
|
-
if (scenario.expectClear) {
|
|
47423
|
-
if (scenario.secondInboundDelayMs) {
|
|
47424
|
-
await Bun.sleep(scenario.secondInboundDelayMs);
|
|
47425
|
-
}
|
|
47426
|
-
secondInboundAt = Date.now();
|
|
47427
|
-
await bridge.handleMessage({
|
|
47428
|
-
event: "media",
|
|
47429
|
-
media: {
|
|
47430
|
-
payload: encodeTwilioMulawBase64(new Int16Array([200, -200, 200, -200])),
|
|
47431
|
-
track: "inbound"
|
|
47432
|
-
},
|
|
47433
|
-
streamSid: "MZ-benchmark"
|
|
47434
|
-
});
|
|
47435
|
-
}
|
|
47436
|
-
await waitFor(() => (!scenario.expectOutboundMedia || sawOutboundMedia) && (!scenario.expectMark || sentEvents.some((entry) => entry.event.event === "mark")) && (!scenario.expectClear || sentEvents.some((entry) => entry.event.event === "clear")), timeoutMs);
|
|
47437
|
-
} finally {
|
|
47438
|
-
await bridge.close("telephony-benchmark");
|
|
47439
|
-
}
|
|
47440
|
-
const outboundMediaEvents = sentEvents.filter((entry) => entry.event.event === "media");
|
|
47441
|
-
const markEvents = sentEvents.filter((entry) => entry.event.event === "mark");
|
|
47442
|
-
const clearEvents = sentEvents.filter((entry) => entry.event.event === "clear");
|
|
47443
|
-
const firstOutboundMediaAt = outboundMediaEvents[0]?.at;
|
|
47444
|
-
const firstMarkAt = markEvents[0]?.at;
|
|
47445
|
-
const firstClearAt = clearEvents[0]?.at;
|
|
47446
|
-
const passes = (!scenario.expectOutboundMedia || outboundMediaEvents.length > 0) && (!scenario.expectMark || markEvents.length > 0) && (!scenario.expectClear || clearEvents.length > 0);
|
|
47447
|
-
return {
|
|
47448
|
-
clearCount: clearEvents.length,
|
|
47449
|
-
clearLatencyMs: secondInboundAt !== undefined && firstClearAt !== undefined ? firstClearAt - secondInboundAt : undefined,
|
|
47450
|
-
elapsedMs: Date.now() - startedAt,
|
|
47451
|
-
expectClear: scenario.expectClear,
|
|
47452
|
-
expectMark: scenario.expectMark,
|
|
47453
|
-
expectOutboundMedia: scenario.expectOutboundMedia,
|
|
47454
|
-
fixtureId: scenario.id,
|
|
47455
|
-
firstOutboundMediaLatencyMs: firstOutboundMediaAt !== undefined ? firstOutboundMediaAt - startedAt : undefined,
|
|
47456
|
-
markCount: markEvents.length,
|
|
47457
|
-
markLatencyMs: firstMarkAt !== undefined ? firstMarkAt - startedAt : undefined,
|
|
47458
|
-
outboundMediaCount: outboundMediaEvents.length,
|
|
47459
|
-
passes,
|
|
47460
|
-
receivedAudioBytes: receivedAudio.reduce((sum, chunk) => sum + chunk.byteLength, 0),
|
|
47461
|
-
title: scenario.title
|
|
47462
|
-
};
|
|
47463
|
-
};
|
|
47464
|
-
var summarizeVoiceTelephonyBenchmark = (fixtures) => {
|
|
47465
|
-
const scenarioCount = fixtures.length;
|
|
47466
|
-
const firstMediaSamples = fixtures.filter((fixture) => typeof fixture.firstOutboundMediaLatencyMs === "number");
|
|
47467
|
-
const markSamples = fixtures.filter((fixture) => typeof fixture.markLatencyMs === "number");
|
|
47468
|
-
const clearSamples = fixtures.filter((fixture) => typeof fixture.clearLatencyMs === "number");
|
|
47469
|
-
const passCount = fixtures.filter((fixture) => fixture.passes).length;
|
|
47470
|
-
return {
|
|
47471
|
-
averageClearLatencyMs: clearSamples.length > 0 ? clearSamples.reduce((sum, fixture) => sum + fixture.clearLatencyMs, 0) / clearSamples.length : undefined,
|
|
47472
|
-
averageElapsedMs: scenarioCount > 0 ? fixtures.reduce((sum, fixture) => sum + fixture.elapsedMs, 0) / scenarioCount : 0,
|
|
47473
|
-
averageFirstOutboundMediaLatencyMs: firstMediaSamples.length > 0 ? firstMediaSamples.reduce((sum, fixture) => sum + fixture.firstOutboundMediaLatencyMs, 0) / firstMediaSamples.length : undefined,
|
|
47474
|
-
averageMarkLatencyMs: markSamples.length > 0 ? markSamples.reduce((sum, fixture) => sum + fixture.markLatencyMs, 0) / markSamples.length : undefined,
|
|
47475
|
-
passCount,
|
|
47476
|
-
passRate: scenarioCount > 0 ? passCount / scenarioCount : 0,
|
|
47477
|
-
scenarioCount,
|
|
47478
|
-
totalOutboundMediaCount: fixtures.reduce((sum, fixture) => sum + fixture.outboundMediaCount, 0)
|
|
47479
|
-
};
|
|
47480
|
-
};
|
|
47481
|
-
var runVoiceTelephonyBenchmark = async (scenarios = getDefaultVoiceTelephonyBenchmarkScenarios(), options = {}) => {
|
|
47482
|
-
const fixtures = [];
|
|
47483
|
-
for (const scenario of scenarios) {
|
|
47484
|
-
fixtures.push(await runVoiceTelephonyBenchmarkScenario(scenario, options));
|
|
47485
|
-
}
|
|
47486
|
-
return {
|
|
47487
|
-
fixtures,
|
|
47488
|
-
generatedAt: Date.now(),
|
|
47489
|
-
summary: summarizeVoiceTelephonyBenchmark(fixtures)
|
|
47490
|
-
};
|
|
47491
|
-
};
|
|
47492
47079
|
// src/telephony/response.ts
|
|
47493
47080
|
var normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
|
|
47494
47081
|
var DEFAULT_MAX_WORDS = 12;
|
|
@@ -49609,10 +49196,18 @@ var createVoiceCallDispositionTagger = (options = {}) => {
|
|
|
49609
49196
|
};
|
|
49610
49197
|
// src/retryPolicy.ts
|
|
49611
49198
|
var DEFAULT_RULES = [
|
|
49612
|
-
{
|
|
49199
|
+
{
|
|
49200
|
+
action: "retry",
|
|
49201
|
+
cooldownMs: 4 * 60 * 60 * 1000,
|
|
49202
|
+
disposition: "voicemail-left"
|
|
49203
|
+
},
|
|
49613
49204
|
{ action: "retry", cooldownMs: 30 * 60 * 1000, disposition: "no-answer" },
|
|
49614
49205
|
{ action: "retry", cooldownMs: 10 * 60 * 1000, disposition: "busy" },
|
|
49615
|
-
{
|
|
49206
|
+
{
|
|
49207
|
+
action: "retry",
|
|
49208
|
+
cooldownMs: 24 * 60 * 60 * 1000,
|
|
49209
|
+
disposition: "callback-requested"
|
|
49210
|
+
},
|
|
49616
49211
|
{ action: "abandon", disposition: "do-not-call" },
|
|
49617
49212
|
{ action: "abandon", disposition: "not-interested" },
|
|
49618
49213
|
{ action: "abandon", disposition: "wrong-number" },
|
|
@@ -49873,7 +49468,10 @@ var createVoiceLiveCoach = (options) => {
|
|
|
49873
49468
|
const now = options.now ?? (() => Date.now());
|
|
49874
49469
|
const generateId = options.generateId ?? (() => `nudge_${Math.random().toString(36).slice(2, 10)}`);
|
|
49875
49470
|
const role = options.injectionRole ?? "system";
|
|
49876
|
-
const templates = {
|
|
49471
|
+
const templates = {
|
|
49472
|
+
...DEFAULT_TEMPLATES,
|
|
49473
|
+
...options.templateForKind ?? {}
|
|
49474
|
+
};
|
|
49877
49475
|
const nudges = [];
|
|
49878
49476
|
const listeners = new Set;
|
|
49879
49477
|
const push = (input) => {
|
|
@@ -50338,7 +49936,10 @@ var createVoiceBookingFlow = (options) => {
|
|
|
50338
49936
|
...options.maxSlotsPerDay !== undefined ? { maxSlots: options.maxSlotsPerDay } : {},
|
|
50339
49937
|
toMs: input.toMs
|
|
50340
49938
|
});
|
|
50341
|
-
setState({
|
|
49939
|
+
setState({
|
|
49940
|
+
proposedSlots: slots,
|
|
49941
|
+
step: slots.length > 0 ? "ask-time" : "ask-date"
|
|
49942
|
+
});
|
|
50342
49943
|
return slots;
|
|
50343
49944
|
};
|
|
50344
49945
|
const chooseSlot = (slotIndex) => {
|
|
@@ -51302,11 +50903,24 @@ var buildPendingActions = (state, slots, pathway, emit2) => {
|
|
|
51302
50903
|
}
|
|
51303
50904
|
if (action.kind === "transfer") {
|
|
51304
50905
|
emit2({ destination: action.destination, type: "transfer" });
|
|
51305
|
-
return {
|
|
50906
|
+
return {
|
|
50907
|
+
actions: pending,
|
|
50908
|
+
awaitingSlotId: null,
|
|
50909
|
+
ended: true,
|
|
50910
|
+
reason: `transfer:${action.destination}`
|
|
50911
|
+
};
|
|
51306
50912
|
}
|
|
51307
50913
|
if (action.kind === "end-call") {
|
|
51308
|
-
emit2({
|
|
51309
|
-
|
|
50914
|
+
emit2({
|
|
50915
|
+
...action.reason !== undefined ? { reason: action.reason } : {},
|
|
50916
|
+
type: "end-call"
|
|
50917
|
+
});
|
|
50918
|
+
return {
|
|
50919
|
+
actions: pending,
|
|
50920
|
+
awaitingSlotId: null,
|
|
50921
|
+
ended: true,
|
|
50922
|
+
...action.reason !== undefined ? { reason: action.reason } : {}
|
|
50923
|
+
};
|
|
51310
50924
|
}
|
|
51311
50925
|
}
|
|
51312
50926
|
return { actions: pending, awaitingSlotId, ended: false };
|
|
@@ -51335,7 +50949,11 @@ var createVoicePathwayRuntime = (options) => {
|
|
|
51335
50949
|
const enter = (stateId) => {
|
|
51336
50950
|
const target = findVoicePathwayState(options.pathway, stateId);
|
|
51337
50951
|
if (!target) {
|
|
51338
|
-
state = {
|
|
50952
|
+
state = {
|
|
50953
|
+
...state,
|
|
50954
|
+
lastError: `Unknown state ${stateId}`,
|
|
50955
|
+
status: "errored"
|
|
50956
|
+
};
|
|
51339
50957
|
emit2({ message: state.lastError, type: "errored" });
|
|
51340
50958
|
return;
|
|
51341
50959
|
}
|
|
@@ -51462,7 +51080,11 @@ var parseNumber = (raw, slot) => {
|
|
|
51462
51080
|
const min = slot.validation?.min ?? Number.NEGATIVE_INFINITY;
|
|
51463
51081
|
const max = slot.validation?.max ?? Number.POSITIVE_INFINITY;
|
|
51464
51082
|
if (value < min || value > max) {
|
|
51465
|
-
return {
|
|
51083
|
+
return {
|
|
51084
|
+
hint: `Expected ${min}\u2013${max}`,
|
|
51085
|
+
ok: false,
|
|
51086
|
+
reason: "out-of-range"
|
|
51087
|
+
};
|
|
51466
51088
|
}
|
|
51467
51089
|
return { normalized: String(value), ok: true, value };
|
|
51468
51090
|
};
|
|
@@ -51524,7 +51146,11 @@ var parseEmail = (raw) => {
|
|
|
51524
51146
|
const ok = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/iu.test(collapsed);
|
|
51525
51147
|
if (!ok)
|
|
51526
51148
|
return { ok: false, reason: "type-mismatch" };
|
|
51527
|
-
return {
|
|
51149
|
+
return {
|
|
51150
|
+
normalized: collapsed.toLowerCase(),
|
|
51151
|
+
ok: true,
|
|
51152
|
+
value: collapsed.toLowerCase()
|
|
51153
|
+
};
|
|
51528
51154
|
};
|
|
51529
51155
|
var parseCurrency = (raw, slot) => {
|
|
51530
51156
|
const trimmed = raw.trim().toLowerCase();
|
|
@@ -51537,7 +51163,11 @@ var parseCurrency = (raw, slot) => {
|
|
|
51537
51163
|
const min = slot.validation?.min ?? 0;
|
|
51538
51164
|
const max = slot.validation?.max ?? Number.POSITIVE_INFINITY;
|
|
51539
51165
|
if (value < min || value > max) {
|
|
51540
|
-
return {
|
|
51166
|
+
return {
|
|
51167
|
+
hint: `Expected ${min}\u2013${max}`,
|
|
51168
|
+
ok: false,
|
|
51169
|
+
reason: "out-of-range"
|
|
51170
|
+
};
|
|
51541
51171
|
}
|
|
51542
51172
|
return { normalized: value.toFixed(2), ok: true, value };
|
|
51543
51173
|
};
|
|
@@ -52152,7 +51782,6 @@ export {
|
|
|
52152
51782
|
summarizeVoiceTraceTimeline,
|
|
52153
51783
|
summarizeVoiceTraceSinkDeliveries,
|
|
52154
51784
|
summarizeVoiceTrace,
|
|
52155
|
-
summarizeVoiceTelephonyBenchmark,
|
|
52156
51785
|
summarizeVoiceSessions,
|
|
52157
51786
|
summarizeVoiceSessionReplay,
|
|
52158
51787
|
summarizeVoiceRoutingSessions,
|
|
@@ -52200,9 +51829,6 @@ export {
|
|
|
52200
51829
|
saveVoiceIncidentBundleArtifact,
|
|
52201
51830
|
runVoiceToolContractSuite,
|
|
52202
51831
|
runVoiceToolContract,
|
|
52203
|
-
runVoiceTelephonyMediaOperationsSmoke,
|
|
52204
|
-
runVoiceTelephonyBenchmarkScenario,
|
|
52205
|
-
runVoiceTelephonyBenchmark,
|
|
52206
51832
|
runVoiceSimulationSuite,
|
|
52207
51833
|
runVoiceSessionEvals,
|
|
52208
51834
|
runVoiceScenarioFixtureEvals,
|
|
@@ -52343,8 +51969,6 @@ export {
|
|
|
52343
51969
|
renderVoiceCompetitiveCoverageHTML,
|
|
52344
51970
|
renderVoiceCampaignsHTML,
|
|
52345
51971
|
renderVoiceCampaignObservabilityHTML,
|
|
52346
|
-
renderVoiceCallReviewMarkdown,
|
|
52347
|
-
renderVoiceCallReviewHTML,
|
|
52348
51972
|
renderVoiceCallDebuggerHTML,
|
|
52349
51973
|
renderVoiceBrowserMediaHTML,
|
|
52350
51974
|
renderVoiceBrowserCallProfileMarkdown,
|
|
@@ -52410,7 +52034,6 @@ export {
|
|
|
52410
52034
|
getVoiceCampaignDialerProofStatus,
|
|
52411
52035
|
getLatestVoiceTelephonyMediaReport,
|
|
52412
52036
|
getLatestVoiceBrowserMediaReport,
|
|
52413
|
-
getDefaultVoiceTelephonyBenchmarkScenarios,
|
|
52414
52037
|
generateVoicePathwayFromPrompt,
|
|
52415
52038
|
generateVoiceCalendarSlots,
|
|
52416
52039
|
fromVapiAssistantConfig,
|
|
@@ -52804,9 +52427,7 @@ export {
|
|
|
52804
52427
|
createVoiceCallingWindow,
|
|
52805
52428
|
createVoiceCallerMemoryNamespace,
|
|
52806
52429
|
createVoiceCallerCRMLinker,
|
|
52807
|
-
createVoiceCallReviewRecorder,
|
|
52808
52430
|
createVoiceCallReviewFromSession,
|
|
52809
|
-
createVoiceCallReviewFromLiveTelephonyReport,
|
|
52810
52431
|
createVoiceCallPlayer,
|
|
52811
52432
|
createVoiceCallDispositionTagger,
|
|
52812
52433
|
createVoiceCallDebuggerRoutes,
|