@absolutejs/voice 0.0.22-beta.155 → 0.0.22-beta.157

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11638,7 +11638,9 @@ var recordVoiceOpsActionAudit = async (record, options) => {
11638
11638
  };
11639
11639
  var createVoiceOpsActionAuditRoutes = (options) => {
11640
11640
  const path = options.path ?? "/api/voice/ops-actions/audit";
11641
- return new Elysia12({
11641
+ const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
11642
+ const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
11643
+ const routes = new Elysia12({
11642
11644
  name: options.name ?? "absolutejs-voice-ops-action-audit"
11643
11645
  }).post(path, async ({ request, set }) => {
11644
11646
  try {
@@ -11652,17 +11654,57 @@ var createVoiceOpsActionAuditRoutes = (options) => {
11652
11654
  };
11653
11655
  }
11654
11656
  });
11657
+ if (historyPath !== false) {
11658
+ routes.get(historyPath, async () => buildVoiceOpsActionHistoryReport(options));
11659
+ }
11660
+ if (historyHtmlPath !== false) {
11661
+ routes.get(historyHtmlPath, async () => new Response(renderVoiceOpsActionHistoryHTML(await buildVoiceOpsActionHistoryReport(options)), {
11662
+ headers: {
11663
+ "Content-Type": "text/html; charset=utf-8"
11664
+ }
11665
+ }));
11666
+ }
11667
+ return routes;
11668
+ };
11669
+ var toHistoryEntry = (event) => ({
11670
+ actionId: event.action,
11671
+ at: event.at,
11672
+ error: event.payload && typeof event.payload === "object" && "error" in event.payload && typeof event.payload.error === "string" ? event.payload.error : undefined,
11673
+ eventId: event.id,
11674
+ ok: event.outcome !== "error",
11675
+ status: event.payload && typeof event.payload === "object" && "status" in event.payload && typeof event.payload.status === "number" ? event.payload.status : undefined,
11676
+ traceId: event.traceId
11677
+ });
11678
+ var buildVoiceOpsActionHistoryReport = async (options) => {
11679
+ const events = options.audit ? await options.audit.list({
11680
+ limit: 25,
11681
+ resourceType: "voice.ops.action",
11682
+ type: "operator.action"
11683
+ }) : [];
11684
+ const entries = events.map(toHistoryEntry).sort((left, right) => right.at - left.at);
11685
+ return {
11686
+ checkedAt: Date.now(),
11687
+ entries,
11688
+ failed: entries.filter((entry) => !entry.ok).length,
11689
+ passed: entries.filter((entry) => entry.ok).length,
11690
+ total: entries.length
11691
+ };
11692
+ };
11693
+ var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11694
+ var renderVoiceOpsActionHistoryHTML = (report) => {
11695
+ const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml15(entry.ok ? "success" : "error")}</span><strong>${escapeHtml15(entry.actionId)}</strong><p>${escapeHtml15(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml15(entry.error)}</p>` : ""}</article>`).join("");
11696
+ 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>`;
11655
11697
  };
11656
11698
  // src/deliveryRuntime.ts
11657
11699
  import { Elysia as Elysia13 } from "elysia";
11658
11700
  import { mkdir } from "fs/promises";
11659
11701
  import { dirname, join } from "path";
11660
- var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11702
+ var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11661
11703
  var renderSummaryCard = (label, summary) => {
11662
11704
  if (!summary) {
11663
- return `<article><span>${escapeHtml15(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
11705
+ return `<article><span>${escapeHtml16(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
11664
11706
  }
11665
- return `<article><span>${escapeHtml15(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending &middot; ${String(summary.failed)} failed &middot; ${String(summary.deadLettered)} dead-lettered</p></article>`;
11707
+ return `<article><span>${escapeHtml16(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending &middot; ${String(summary.failed)} failed &middot; ${String(summary.deadLettered)} dead-lettered</p></article>`;
11666
11708
  };
11667
11709
  var resolvePresetLeases = (leases) => ("claim" in leases) ? {
11668
11710
  audit: leases,
@@ -11873,9 +11915,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
11873
11915
  });
11874
11916
  var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
11875
11917
  const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
11876
- const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml15(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
11877
- const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml15(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
11878
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(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}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}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml15(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 ${escapeHtml15(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"><h2>Runtime shape</h2><pre>const runtime = createVoiceDeliveryRuntime({ audit, trace })
11918
+ const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml16(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
11919
+ const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml16(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
11920
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(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}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}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml16(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 ${escapeHtml16(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"><h2>Runtime shape</h2><pre>const runtime = createVoiceDeliveryRuntime({ audit, trace })
11879
11921
 
11880
11922
  await runtime.tick()
11881
11923
  await runtime.requeueDeadLetters()
@@ -12133,7 +12175,7 @@ import { Elysia as Elysia15 } from "elysia";
12133
12175
 
12134
12176
  // src/handoffHealth.ts
12135
12177
  import { Elysia as Elysia14 } from "elysia";
12136
- var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12178
+ var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12137
12179
  var getString6 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
12138
12180
  var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
12139
12181
  var increment3 = (record, key) => {
@@ -12251,10 +12293,10 @@ var renderActionSummary = (summary) => {
12251
12293
  return [
12252
12294
  '<section class="voice-handoff-health-columns">',
12253
12295
  "<article><h3>Actions</h3>",
12254
- actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml16(action)}: ${String(count)}</li>`).join("")}</ul>`,
12296
+ actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml17(action)}: ${String(count)}</li>`).join("")}</ul>`,
12255
12297
  "</article>",
12256
12298
  "<article><h3>Adapters</h3>",
12257
- adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml16(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
12299
+ adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml17(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
12258
12300
  "</article>",
12259
12301
  "</section>"
12260
12302
  ].join("");
@@ -12268,22 +12310,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
12268
12310
  summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
12269
12311
  '<div class="voice-handoff-health-events">',
12270
12312
  ...summary.events.map((event) => [
12271
- `<article class="${escapeHtml16(event.status)}">`,
12313
+ `<article class="${escapeHtml17(event.status)}">`,
12272
12314
  '<div class="voice-handoff-health-event-header">',
12273
- `<strong>${escapeHtml16(event.action ?? "handoff")}</strong>`,
12274
- `<span>${escapeHtml16(event.status)}</span>`,
12315
+ `<strong>${escapeHtml17(event.action ?? "handoff")}</strong>`,
12316
+ `<span>${escapeHtml17(event.status)}</span>`,
12275
12317
  "</div>",
12276
- `<p><small>${escapeHtml16(event.sessionId)}</small></p>`,
12277
- event.target ? `<p>Target: ${escapeHtml16(event.target)}</p>` : "",
12278
- event.reason ? `<p>Reason: ${escapeHtml16(event.reason)}</p>` : "",
12318
+ `<p><small>${escapeHtml17(event.sessionId)}</small></p>`,
12319
+ event.target ? `<p>Target: ${escapeHtml17(event.target)}</p>` : "",
12320
+ event.reason ? `<p>Reason: ${escapeHtml17(event.reason)}</p>` : "",
12279
12321
  event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
12280
12322
  "<li>",
12281
- `${escapeHtml16(delivery.adapterId)}: ${escapeHtml16(delivery.status)}`,
12282
- delivery.deliveredTo ? ` to ${escapeHtml16(delivery.deliveredTo)}` : "",
12283
- delivery.error ? ` (${escapeHtml16(delivery.error)})` : "",
12323
+ `${escapeHtml17(delivery.adapterId)}: ${escapeHtml17(delivery.status)}`,
12324
+ delivery.deliveredTo ? ` to ${escapeHtml17(delivery.deliveredTo)}` : "",
12325
+ delivery.error ? ` (${escapeHtml17(delivery.error)})` : "",
12284
12326
  "</li>"
12285
12327
  ].join("")).join("")}</ul>` : "",
12286
- event.replayHref ? `<p><a href="${escapeHtml16(event.replayHref)}">Open replay</a></p>` : "",
12328
+ event.replayHref ? `<p><a href="${escapeHtml17(event.replayHref)}">Open replay</a></p>` : "",
12287
12329
  "</article>"
12288
12330
  ].join("")),
12289
12331
  "</div>"
@@ -12436,12 +12478,12 @@ var evaluateVoiceQuality = async (input) => {
12436
12478
  thresholds
12437
12479
  };
12438
12480
  };
12439
- var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12481
+ var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12440
12482
  var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
12441
12483
  var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
12442
12484
  var renderVoiceQualityHTML = (report, options = {}) => {
12443
- const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml17(metric.label)}</td><td>${escapeHtml17(formatMetricValue(metric))}</td><td>${escapeHtml17(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml17(key)}</code></td></tr>`).join("");
12444
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml17(link.href)}">${escapeHtml17(link.label)}</a>`).join("")}</nav>` : "";
12485
+ const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml18(metric.label)}</td><td>${escapeHtml18(formatMetricValue(metric))}</td><td>${escapeHtml18(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml18(key)}</code></td></tr>`).join("");
12486
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12445
12487
  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>`;
12446
12488
  };
12447
12489
  var createVoiceQualityRoutes = (options) => {
@@ -12475,7 +12517,7 @@ var createVoiceQualityRoutes = (options) => {
12475
12517
  };
12476
12518
 
12477
12519
  // src/evalRoutes.ts
12478
- var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12520
+ var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12479
12521
  var rate2 = (count, total) => count / Math.max(1, total);
12480
12522
  var normalizeSearchText = (value) => value.trim().toLowerCase();
12481
12523
  var getString8 = (value) => typeof value === "string" ? value : undefined;
@@ -12784,40 +12826,40 @@ var formatTime = (value) => value === undefined ? "unknown" : new Date(value).to
12784
12826
  var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
12785
12827
  var renderVoiceEvalHTML = (report, options = {}) => {
12786
12828
  const title = options.title ?? "AbsoluteJS Voice Evals";
12787
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12788
- const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml18(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>';
12829
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12830
+ const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml19(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>';
12789
12831
  const sessions = report.sessions.length ? report.sessions.map((session) => {
12790
12832
  const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
12791
- return `<tr class="${session.status}"><td>${escapeHtml18(session.sessionId)}</td><td>${escapeHtml18(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml18(formatTime(session.endedAt))}</td><td>${escapeHtml18(failedMetrics || "none")}</td></tr>`;
12833
+ return `<tr class="${session.status}"><td>${escapeHtml19(session.sessionId)}</td><td>${escapeHtml19(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml19(formatTime(session.endedAt))}</td><td>${escapeHtml19(failedMetrics || "none")}</td></tr>`;
12792
12834
  }).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
12793
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(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}.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{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.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>${escapeHtml18(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><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>`;
12835
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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}.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{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.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>${escapeHtml19(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><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>`;
12794
12836
  };
12795
12837
  var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
12796
12838
  const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
12797
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12798
- const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml18(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
12799
- const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml18(id)}</li>`).join("") : "<li>none</li>";
12800
- const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml18(id)}</li>`).join("") : "<li>none</li>";
12801
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(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>${escapeHtml18(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml18(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml18(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>${escapeHtml18(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>`;
12839
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12840
+ const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml19(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
12841
+ const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml19(id)}</li>`).join("") : "<li>none</li>";
12842
+ const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml19(id)}</li>`).join("") : "<li>none</li>";
12843
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml19(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml19(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>${escapeHtml19(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>`;
12802
12844
  };
12803
12845
  var renderVoiceScenarioEvalHTML = (report, options = {}) => {
12804
12846
  const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
12805
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12847
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12806
12848
  const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
12807
- const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml18(issue)}</li>`).join("")}</ul>` : "";
12808
- const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml18(session.sessionId)}</td><td>${escapeHtml18(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml18(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
12809
- return `<section class="scenario ${scenario.status}"><h2>${escapeHtml18(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml18(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>`;
12849
+ const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml19(issue)}</li>`).join("")}</ul>` : "";
12850
+ const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml19(session.sessionId)}</td><td>${escapeHtml19(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml19(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
12851
+ return `<section class="scenario ${scenario.status}"><h2>${escapeHtml19(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml19(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>`;
12810
12852
  }).join("") : "<section><p>No scenarios configured.</p></section>";
12811
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(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}.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}.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>${escapeHtml18(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>${scenarios}</main></body></html>`;
12853
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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}.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}.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>${escapeHtml19(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>${scenarios}</main></body></html>`;
12812
12854
  };
12813
12855
  var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
12814
12856
  const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
12815
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12857
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12816
12858
  const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
12817
- const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml18(scenario.label)}</td><td>${escapeHtml18(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml18([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
12818
- return `<section class="${fixture.status}"><h2>${escapeHtml18(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml18(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>`;
12859
+ const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml19(scenario.label)}</td><td>${escapeHtml19(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml19([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
12860
+ return `<section class="${fixture.status}"><h2>${escapeHtml19(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml19(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>`;
12819
12861
  }).join("") : "<section><p>No scenario fixtures configured.</p></section>";
12820
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(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}.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}.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>${escapeHtml18(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>${fixtures}</main></body></html>`;
12862
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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}.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}.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>${escapeHtml19(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>${fixtures}</main></body></html>`;
12821
12863
  };
12822
12864
  var createVoiceEvalRoutes = (options) => {
12823
12865
  const path = options.path ?? "/evals";
@@ -12959,7 +13001,7 @@ import { Elysia as Elysia19 } from "elysia";
12959
13001
 
12960
13002
  // src/outcomeContract.ts
12961
13003
  import { Elysia as Elysia17 } from "elysia";
12962
- var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13004
+ var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12963
13005
  var getPayloadString = (event, key) => typeof event.payload[key] === "string" ? event.payload[key] : undefined;
12964
13006
  var toList = async (input) => Array.isArray(input) ? input : await input?.list() ?? [];
12965
13007
  var hydrateSessions = async (input) => {
@@ -13067,9 +13109,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
13067
13109
  const contracts = report.contracts.map((contract) => `<section class="contract ${contract.pass ? "pass" : "fail"}">
13068
13110
  <div class="contract-header">
13069
13111
  <div>
13070
- <p class="eyebrow">${escapeHtml19(contract.contractId)}</p>
13071
- <h2>${escapeHtml19(contract.label ?? contract.contractId)}</h2>
13072
- ${contract.description ? `<p>${escapeHtml19(contract.description)}</p>` : ""}
13112
+ <p class="eyebrow">${escapeHtml20(contract.contractId)}</p>
13113
+ <h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
13114
+ ${contract.description ? `<p>${escapeHtml20(contract.description)}</p>` : ""}
13073
13115
  </div>
13074
13116
  <strong>${contract.pass ? "pass" : "fail"}</strong>
13075
13117
  </div>
@@ -13080,9 +13122,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
13080
13122
  <span>handoffs ${String(contract.matched.handoffs)}</span>
13081
13123
  <span>events ${String(contract.matched.integrationEvents)}</span>
13082
13124
  </div>
13083
- ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml19(issue.message)}</li>`).join("")}</ul>` : ""}
13125
+ ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml20(issue.message)}</li>`).join("")}</ul>` : ""}
13084
13126
  </section>`).join("");
13085
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(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>`;
13127
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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>${escapeHtml20(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>`;
13086
13128
  };
13087
13129
  var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
13088
13130
  var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
@@ -13317,7 +13359,7 @@ var createDefaultTurn = (caseId) => ({
13317
13359
  });
13318
13360
  var defaultApi = {};
13319
13361
  var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
13320
- var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13362
+ var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13321
13363
  var evaluateExpectation = (input) => {
13322
13364
  const issues = [];
13323
13365
  const expect = input.expect;
@@ -13483,19 +13525,19 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
13483
13525
  const title = options.title ?? "Voice Tool Contracts";
13484
13526
  const contracts = report.contracts.map((contract) => {
13485
13527
  const cases = contract.cases.map((testCase) => `<tr>
13486
- <td>${escapeHtml20(testCase.label ?? testCase.caseId)}</td>
13528
+ <td>${escapeHtml21(testCase.label ?? testCase.caseId)}</td>
13487
13529
  <td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
13488
- <td>${escapeHtml20(testCase.status)}</td>
13530
+ <td>${escapeHtml21(testCase.status)}</td>
13489
13531
  <td>${String(testCase.attempts)}</td>
13490
13532
  <td>${String(testCase.elapsedMs)}ms</td>
13491
13533
  <td>${testCase.timedOut ? "yes" : "no"}</td>
13492
- <td>${escapeHtml20(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
13534
+ <td>${escapeHtml21(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
13493
13535
  </tr>`).join("");
13494
13536
  return `<section class="contract ${contract.pass ? "pass" : "fail"}">
13495
13537
  <div class="contract-header">
13496
13538
  <div>
13497
- <p class="eyebrow">${escapeHtml20(contract.toolName)}</p>
13498
- <h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
13539
+ <p class="eyebrow">${escapeHtml21(contract.toolName)}</p>
13540
+ <h2>${escapeHtml21(contract.label ?? contract.contractId)}</h2>
13499
13541
  </div>
13500
13542
  <strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
13501
13543
  </div>
@@ -13505,7 +13547,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
13505
13547
  </table>
13506
13548
  </section>`;
13507
13549
  }).join("");
13508
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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(245,158,11,.12))}.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)}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>${escapeHtml20(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml20(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 tool contracts configured.</p></section>'}</main></body></html>`;
13550
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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(245,158,11,.12))}.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)}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>${escapeHtml21(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml21(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 tool contracts configured.</p></section>'}</main></body></html>`;
13509
13551
  };
13510
13552
  var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
13511
13553
  var createVoiceToolContractHTMLHandler = (options) => async () => {
@@ -13532,7 +13574,7 @@ var createVoiceToolContractRoutes = (options) => {
13532
13574
  };
13533
13575
 
13534
13576
  // src/simulationSuite.ts
13535
- var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13577
+ var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13536
13578
  var summarizeSection = (report) => ({
13537
13579
  failed: report.failed,
13538
13580
  passed: report.passed,
@@ -13668,15 +13710,15 @@ var renderSection = (label, summary) => {
13668
13710
  if (!summary) {
13669
13711
  return "";
13670
13712
  }
13671
- return `<article class="${escapeHtml21(summary.status)}"><span>${escapeHtml21(label)}</span><strong>${escapeHtml21(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
13713
+ return `<article class="${escapeHtml22(summary.status)}"><span>${escapeHtml22(label)}</span><strong>${escapeHtml22(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
13672
13714
  };
13673
13715
  var renderAction = (action) => {
13674
- const content = `<strong>${escapeHtml21(action.label)}</strong><p>${escapeHtml21(action.description)}</p><span>${escapeHtml21(action.section)} / ${escapeHtml21(action.severity)}</span>`;
13675
- return action.href ? `<a class="action" href="${escapeHtml21(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
13716
+ const content = `<strong>${escapeHtml22(action.label)}</strong><p>${escapeHtml22(action.description)}</p><span>${escapeHtml22(action.section)} / ${escapeHtml22(action.severity)}</span>`;
13717
+ return action.href ? `<a class="action" href="${escapeHtml22(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
13676
13718
  };
13677
13719
  var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
13678
13720
  const title = options.title ?? "Voice Simulation Suite";
13679
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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{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}.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{color:#d8dee6;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml21(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml21(report.status)}">Status: ${escapeHtml21(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><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>${escapeHtml21(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
13721
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(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{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}.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{color:#d8dee6;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml22(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml22(report.status)}">Status: ${escapeHtml22(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><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>${escapeHtml22(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
13680
13722
  };
13681
13723
  var createVoiceSimulationSuiteRoutes = (options) => {
13682
13724
  const path = options.path ?? "/api/voice/simulations";
@@ -13995,7 +14037,7 @@ var createVoiceWorkflowContractHandler = (input) => {
13995
14037
  // src/sessionReplay.ts
13996
14038
  import { Elysia as Elysia20 } from "elysia";
13997
14039
  var getString9 = (value) => typeof value === "string" ? value : undefined;
13998
- var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14040
+ var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13999
14041
  var increment4 = (record, key) => {
14000
14042
  record[key] = (record[key] ?? 0) + 1;
14001
14043
  };
@@ -14175,10 +14217,10 @@ var summarizeVoiceSessions = async (options = {}) => {
14175
14217
  var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
14176
14218
  '<div class="voice-sessions-list">',
14177
14219
  ...sessions.map((session) => [
14178
- `<article class="voice-session-card ${escapeHtml22(session.status)}">`,
14220
+ `<article class="voice-session-card ${escapeHtml23(session.status)}">`,
14179
14221
  '<div class="voice-session-card-header">',
14180
- `<strong>${escapeHtml22(session.sessionId)}</strong>`,
14181
- `<span>${escapeHtml22(session.status)}</span>`,
14222
+ `<strong>${escapeHtml23(session.sessionId)}</strong>`,
14223
+ `<span>${escapeHtml23(session.status)}</span>`,
14182
14224
  "</div>",
14183
14225
  "<dl>",
14184
14226
  `<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
@@ -14186,9 +14228,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
14186
14228
  `<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
14187
14229
  `<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
14188
14230
  "</dl>",
14189
- session.latestOutcome ? `<p>Outcome: ${escapeHtml22(session.latestOutcome)}</p>` : "",
14190
- session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml22).join(", ")}</p>` : "",
14191
- session.replayHref ? `<p><a href="${escapeHtml22(session.replayHref)}">Open replay</a></p>` : "",
14231
+ session.latestOutcome ? `<p>Outcome: ${escapeHtml23(session.latestOutcome)}</p>` : "",
14232
+ session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml23).join(", ")}</p>` : "",
14233
+ session.replayHref ? `<p><a href="${escapeHtml23(session.replayHref)}">Open replay</a></p>` : "",
14192
14234
  "</article>"
14193
14235
  ].join("")),
14194
14236
  "</div>"
@@ -14417,7 +14459,7 @@ var assertVoiceAgentSquadContract = async (options) => {
14417
14459
  import { Elysia as Elysia21 } from "elysia";
14418
14460
  var DEFAULT_WARN_AFTER_MS = 1800;
14419
14461
  var DEFAULT_FAIL_AFTER_MS = 3200;
14420
- var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14462
+ var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14421
14463
  var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
14422
14464
  var getString10 = (value) => typeof value === "string" && value.trim() ? value : undefined;
14423
14465
  var createTraceStageIndex = (events) => {
@@ -14531,11 +14573,11 @@ var summarizeVoiceTurnLatency = async (options) => {
14531
14573
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
14532
14574
  var renderVoiceTurnLatencyHTML = (report, options = {}) => {
14533
14575
  const title = options.title ?? "Voice Turn Latency";
14534
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml23(turn.status)}">
14535
- <header><div><p class="eyebrow">${escapeHtml23(turn.sessionId)} \xB7 ${escapeHtml23(turn.turnId)}</p><h2>${escapeHtml23(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml23(turn.status)}</strong></header>
14536
- <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml23(stage.label)}</dt><dd>${escapeHtml23(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
14576
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml24(turn.status)}">
14577
+ <header><div><p class="eyebrow">${escapeHtml24(turn.sessionId)} \xB7 ${escapeHtml24(turn.turnId)}</p><h2>${escapeHtml24(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml24(turn.status)}</strong></header>
14578
+ <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml24(stage.label)}</dt><dd>${escapeHtml24(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
14537
14579
  </article>`).join("");
14538
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml23(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(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}.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>${escapeHtml23(title)}</h1><div class="summary"><span class="pill ${escapeHtml23(report.status)}">${escapeHtml23(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml23(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
14580
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(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(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}.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>${escapeHtml24(title)}</h1><div class="summary"><span class="pill ${escapeHtml24(report.status)}">${escapeHtml24(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml24(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
14539
14581
  };
14540
14582
  var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
14541
14583
  var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
@@ -14562,7 +14604,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
14562
14604
  };
14563
14605
  // src/liveLatency.ts
14564
14606
  import { Elysia as Elysia22 } from "elysia";
14565
- var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14607
+ var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14566
14608
  var percentile = (values, percentileValue) => {
14567
14609
  if (values.length === 0) {
14568
14610
  return;
@@ -14610,8 +14652,8 @@ var summarizeVoiceLiveLatency = async (options) => {
14610
14652
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
14611
14653
  var renderVoiceLiveLatencyHTML = (report, options = {}) => {
14612
14654
  const title = options.title ?? "Voice Live Latency";
14613
- const rows = report.recent.map((sample) => `<tr><td>${escapeHtml24(sample.sessionId)}</td><td>${escapeHtml24(formatMs2(sample.latencyMs))}</td><td>${escapeHtml24(sample.status ?? "unknown")}</td><td>${escapeHtml24(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
14614
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(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{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}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>${escapeHtml24(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml24(report.status)}">Status: ${escapeHtml24(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml24(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml24(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml24(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></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>`;
14655
+ const rows = report.recent.map((sample) => `<tr><td>${escapeHtml25(sample.sessionId)}</td><td>${escapeHtml25(formatMs2(sample.latencyMs))}</td><td>${escapeHtml25(sample.status ?? "unknown")}</td><td>${escapeHtml25(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
14656
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(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{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}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>${escapeHtml25(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml25(report.status)}">Status: ${escapeHtml25(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml25(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml25(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml25(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></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>`;
14615
14657
  };
14616
14658
  var createVoiceLiveLatencyRoutes = (options) => {
14617
14659
  const path = options.path ?? "/api/live-latency";
@@ -14635,7 +14677,7 @@ var createVoiceLiveLatencyRoutes = (options) => {
14635
14677
  // src/turnQuality.ts
14636
14678
  import { Elysia as Elysia23 } from "elysia";
14637
14679
  var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
14638
- var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14680
+ var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14639
14681
  var getTurnLatencyMs = (turn) => {
14640
14682
  const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
14641
14683
  if (firstTranscriptAt === undefined) {
@@ -14706,24 +14748,24 @@ var summarizeVoiceTurnQuality = async (options) => {
14706
14748
  };
14707
14749
  var renderVoiceTurnQualityHTML = (report, options = {}) => {
14708
14750
  const title = options.title ?? "Voice Turn Quality";
14709
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml25(turn.status)}">
14751
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml26(turn.status)}">
14710
14752
  <div class="turn-header">
14711
14753
  <div>
14712
- <p class="eyebrow">${escapeHtml25(turn.sessionId)} \xB7 ${escapeHtml25(turn.turnId)}</p>
14713
- <h2>${escapeHtml25(turn.text || "Empty turn")}</h2>
14754
+ <p class="eyebrow">${escapeHtml26(turn.sessionId)} \xB7 ${escapeHtml26(turn.turnId)}</p>
14755
+ <h2>${escapeHtml26(turn.text || "Empty turn")}</h2>
14714
14756
  </div>
14715
- <strong>${escapeHtml25(turn.status)}</strong>
14757
+ <strong>${escapeHtml26(turn.status)}</strong>
14716
14758
  </div>
14717
14759
  <dl>
14718
- <div><dt>Source</dt><dd>${escapeHtml25(turn.source ?? "unknown")}</dd></div>
14760
+ <div><dt>Source</dt><dd>${escapeHtml26(turn.source ?? "unknown")}</dd></div>
14719
14761
  <div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
14720
- <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml25(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
14721
- <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml25(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
14762
+ <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml26(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
14763
+ <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml26(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
14722
14764
  <div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
14723
14765
  <div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
14724
14766
  </dl>
14725
14767
  </article>`).join("");
14726
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(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>${escapeHtml25(title)}</h1><div class="summary"><span class="pill ${escapeHtml25(report.status)}">${escapeHtml25(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>`;
14768
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(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>${escapeHtml26(title)}</h1><div class="summary"><span class="pill ${escapeHtml26(report.status)}">${escapeHtml26(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>`;
14727
14769
  };
14728
14770
  var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
14729
14771
  var createVoiceTurnQualityHTMLHandler = (options) => async () => {
@@ -15538,7 +15580,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
15538
15580
  return parameters;
15539
15581
  };
15540
15582
  var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
15541
- var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15583
+ var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15542
15584
  var getWebhookVerificationUrl = (webhook, input) => {
15543
15585
  if (!webhook?.verificationUrl) {
15544
15586
  return;
@@ -15581,23 +15623,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
15581
15623
  };
15582
15624
  var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
15583
15625
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
15584
- <h1>${escapeHtml26(title)}</h1>
15626
+ <h1>${escapeHtml27(title)}</h1>
15585
15627
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
15586
15628
  <section>
15587
15629
  <h2>URLs</h2>
15588
15630
  <ul>
15589
- <li><strong>TwiML:</strong> <code>${escapeHtml26(status.urls.twiml)}</code></li>
15590
- <li><strong>Media stream:</strong> <code>${escapeHtml26(status.urls.stream)}</code></li>
15591
- <li><strong>Status webhook:</strong> <code>${escapeHtml26(status.urls.webhook)}</code></li>
15631
+ <li><strong>TwiML:</strong> <code>${escapeHtml27(status.urls.twiml)}</code></li>
15632
+ <li><strong>Media stream:</strong> <code>${escapeHtml27(status.urls.stream)}</code></li>
15633
+ <li><strong>Status webhook:</strong> <code>${escapeHtml27(status.urls.webhook)}</code></li>
15592
15634
  </ul>
15593
15635
  </section>
15594
15636
  <section>
15595
15637
  <h2>Signing</h2>
15596
15638
  <p>Mode: <code>${status.signing.mode}</code></p>
15597
- ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml26(status.signing.verificationUrl)}</code></p>` : ""}
15639
+ ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml27(status.signing.verificationUrl)}</code></p>` : ""}
15598
15640
  </section>
15599
- ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml26(name)}</code></li>`).join("")}</ul></section>` : ""}
15600
- ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml26(warning)}</li>`).join("")}</ul></section>` : ""}
15641
+ ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml27(name)}</code></li>`).join("")}</ul></section>` : ""}
15642
+ ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml27(warning)}</li>`).join("")}</ul></section>` : ""}
15601
15643
  </main>`;
15602
15644
  var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&amp;", "&");
15603
15645
  var createSmokeCheck = (name, status, message, details) => ({
@@ -15608,20 +15650,20 @@ var createSmokeCheck = (name, status, message, details) => ({
15608
15650
  });
15609
15651
  var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
15610
15652
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
15611
- <h1>${escapeHtml26(title)}</h1>
15653
+ <h1>${escapeHtml27(title)}</h1>
15612
15654
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
15613
15655
  <section>
15614
15656
  <h2>Checks</h2>
15615
15657
  <ul>
15616
- ${report.checks.map((check) => `<li><strong>${escapeHtml26(check.name)}</strong>: ${escapeHtml26(check.status)}${check.message ? ` - ${escapeHtml26(check.message)}` : ""}</li>`).join("")}
15658
+ ${report.checks.map((check) => `<li><strong>${escapeHtml27(check.name)}</strong>: ${escapeHtml27(check.status)}${check.message ? ` - ${escapeHtml27(check.message)}` : ""}</li>`).join("")}
15617
15659
  </ul>
15618
15660
  </section>
15619
15661
  <section>
15620
15662
  <h2>Observed URLs</h2>
15621
15663
  <ul>
15622
- <li><strong>TwiML:</strong> <code>${escapeHtml26(report.setup.urls.twiml)}</code></li>
15623
- <li><strong>Stream:</strong> <code>${escapeHtml26(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
15624
- <li><strong>Webhook:</strong> <code>${escapeHtml26(report.setup.urls.webhook)}</code></li>
15664
+ <li><strong>TwiML:</strong> <code>${escapeHtml27(report.setup.urls.twiml)}</code></li>
15665
+ <li><strong>Stream:</strong> <code>${escapeHtml27(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
15666
+ <li><strong>Webhook:</strong> <code>${escapeHtml27(report.setup.urls.webhook)}</code></li>
15625
15667
  </ul>
15626
15668
  </section>
15627
15669
  </main>`;
@@ -16218,7 +16260,7 @@ var createTwilioVoiceRoutes = (options) => {
16218
16260
 
16219
16261
  // src/telephony/plivo.ts
16220
16262
  var escapeXml3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16221
- var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16263
+ var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16222
16264
  var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16223
16265
  var resolveRequestOrigin2 = (request) => {
16224
16266
  const url = new URL(request.url);
@@ -16469,21 +16511,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
16469
16511
  };
16470
16512
  var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16471
16513
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
16472
- <h1>${escapeHtml27(title)}</h1>
16514
+ <h1>${escapeHtml28(title)}</h1>
16473
16515
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
16474
16516
  <ul>
16475
- <li><strong>Answer XML:</strong> <code>${escapeHtml27(status.urls.answer)}</code></li>
16476
- <li><strong>Audio stream:</strong> <code>${escapeHtml27(status.urls.stream)}</code></li>
16477
- <li><strong>Status webhook:</strong> <code>${escapeHtml27(status.urls.webhook)}</code></li>
16517
+ <li><strong>Answer XML:</strong> <code>${escapeHtml28(status.urls.answer)}</code></li>
16518
+ <li><strong>Audio stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
16519
+ <li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
16478
16520
  </ul>
16479
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml27(name)}</code></li>`).join("")}</ul>` : ""}
16480
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml27(warning)}</li>`).join("")}</ul>` : ""}
16521
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul>` : ""}
16522
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul>` : ""}
16481
16523
  </main>`;
16482
16524
  var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16483
16525
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
16484
- <h1>${escapeHtml27(title)}</h1>
16526
+ <h1>${escapeHtml28(title)}</h1>
16485
16527
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
16486
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml27(check.name)}</strong>: ${escapeHtml27(check.status)}${check.message ? ` - ${escapeHtml27(check.message)}` : ""}</li>`).join("")}</ul>
16528
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}</ul>
16487
16529
  </main>`;
16488
16530
  var runPlivoSmokeTest = async (input) => {
16489
16531
  const setup = await buildPlivoVoiceSetupStatus(input.options, input);
@@ -16691,7 +16733,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
16691
16733
  import { Buffer as Buffer6 } from "buffer";
16692
16734
  import { Elysia as Elysia27 } from "elysia";
16693
16735
  var escapeXml4 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16694
- var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16736
+ var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16695
16737
  var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16696
16738
  var resolveRequestOrigin3 = (request) => {
16697
16739
  const url = new URL(request.url);
@@ -16892,21 +16934,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
16892
16934
  };
16893
16935
  var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16894
16936
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
16895
- <h1>${escapeHtml28(title)}</h1>
16937
+ <h1>${escapeHtml29(title)}</h1>
16896
16938
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
16897
16939
  <ul>
16898
- <li><strong>TeXML:</strong> <code>${escapeHtml28(status.urls.texml)}</code></li>
16899
- <li><strong>Media stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
16900
- <li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
16940
+ <li><strong>TeXML:</strong> <code>${escapeHtml29(status.urls.texml)}</code></li>
16941
+ <li><strong>Media stream:</strong> <code>${escapeHtml29(status.urls.stream)}</code></li>
16942
+ <li><strong>Status webhook:</strong> <code>${escapeHtml29(status.urls.webhook)}</code></li>
16901
16943
  </ul>
16902
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul>` : ""}
16903
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul>` : ""}
16944
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml29(name)}</code></li>`).join("")}</ul>` : ""}
16945
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml29(warning)}</li>`).join("")}</ul>` : ""}
16904
16946
  </main>`;
16905
16947
  var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16906
16948
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
16907
- <h1>${escapeHtml28(title)}</h1>
16949
+ <h1>${escapeHtml29(title)}</h1>
16908
16950
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
16909
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}</ul>
16951
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml29(check.name)}</strong>: ${escapeHtml29(check.status)}${check.message ? ` - ${escapeHtml29(check.message)}` : ""}</li>`).join("")}</ul>
16910
16952
  </main>`;
16911
16953
  var runTelnyxSmokeTest = async (input) => {
16912
16954
  const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
@@ -17111,7 +17153,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
17111
17153
 
17112
17154
  // src/telephony/matrix.ts
17113
17155
  import { Elysia as Elysia28 } from "elysia";
17114
- var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17156
+ var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17115
17157
  var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
17116
17158
  var resolveEntryStatus = (contract, setup, smoke) => {
17117
17159
  if (!contract.pass || !setup.ready || smoke?.pass === false) {
@@ -17172,13 +17214,13 @@ var badgeStyles = {
17172
17214
  };
17173
17215
  var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
17174
17216
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
17175
- <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml29(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
17217
+ <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml30(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
17176
17218
  <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>
17177
17219
  <section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
17178
17220
  ${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);">
17179
17221
  <div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
17180
- <h2 style="margin:0; font-size:20px;">${escapeHtml29(entry.name)}</h2>
17181
- <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml29(entry.status.toUpperCase())}</span>
17222
+ <h2 style="margin:0; font-size:20px;">${escapeHtml30(entry.name)}</h2>
17223
+ <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml30(entry.status.toUpperCase())}</span>
17182
17224
  </div>
17183
17225
  <dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
17184
17226
  <dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
@@ -17186,9 +17228,9 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
17186
17228
  <dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
17187
17229
  <dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
17188
17230
  </dl>
17189
- <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml29(entry.setup.urls.stream || "missing")}</code></p>
17190
- <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml29(entry.setup.urls.webhook || "missing")}</code></p>
17191
- ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml29(issue.severity)}: ${escapeHtml29(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
17231
+ <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml30(entry.setup.urls.stream || "missing")}</code></p>
17232
+ <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml30(entry.setup.urls.webhook || "missing")}</code></p>
17233
+ ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml30(issue.severity)}: ${escapeHtml30(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
17192
17234
  </article>`).join("")}
17193
17235
  </section>
17194
17236
  </main>`;
@@ -17224,7 +17266,7 @@ var defaultRequirements = [
17224
17266
  "lifecycle-outcome",
17225
17267
  "no-session-error"
17226
17268
  ];
17227
- var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17269
+ var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17228
17270
  var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
17229
17271
  var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
17230
17272
  const value = event.payload[key];
@@ -17333,10 +17375,10 @@ var resolveHandlerOptions = async (options, input) => ({
17333
17375
  });
17334
17376
  var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
17335
17377
  const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
17336
- const issues = report.issues.map((issue) => `<li><strong>${escapeHtml30(issue.requirement)}</strong>: ${escapeHtml30(issue.message)}</li>`).join("");
17337
- const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml30(outcome)}</span>`).join("");
17338
- const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml30(requirement)}</span>`).join("");
17339
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(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>${escapeHtml30(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml30(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml30(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml30(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>`;
17378
+ const issues = report.issues.map((issue) => `<li><strong>${escapeHtml31(issue.requirement)}</strong>: ${escapeHtml31(issue.message)}</li>`).join("");
17379
+ const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml31(outcome)}</span>`).join("");
17380
+ const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml31(requirement)}</span>`).join("");
17381
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(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>${escapeHtml31(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml31(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml31(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml31(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>`;
17340
17382
  };
17341
17383
  var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
17342
17384
  query,
@@ -17402,7 +17444,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
17402
17444
  "completed",
17403
17445
  "failed"
17404
17446
  ];
17405
- var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17447
+ var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17406
17448
  var loadRouteJson = async (input) => {
17407
17449
  const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
17408
17450
  headers: {
@@ -17462,18 +17504,18 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
17462
17504
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
17463
17505
  const urls = entry?.setup.urls;
17464
17506
  const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
17465
- return `<tr><td>${escapeHtml31(carrier.name ?? carrier.provider)}</td><td>${escapeHtml31(carrier.provider)}</td><td><code>${escapeHtml31(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml31(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml31(entry.status)}">${escapeHtml31(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml31(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml31(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml31(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
17507
+ return `<tr><td>${escapeHtml32(carrier.name ?? carrier.provider)}</td><td>${escapeHtml32(carrier.provider)}</td><td><code>${escapeHtml32(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml32(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml32(entry.status)}">${escapeHtml32(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml32(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml32(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml32(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
17466
17508
  }).join("");
17467
- const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml31(stage)}</code></li>`).join("");
17509
+ const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml32(stage)}</code></li>`).join("");
17468
17510
  const checklist = report.carriers.map((carrier) => {
17469
17511
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
17470
17512
  const urls = entry?.setup.urls;
17471
17513
  const answerLabel = carrier.provider === "telnyx" ? "TeXML URL" : carrier.provider === "plivo" ? "Answer URL" : "TwiML URL";
17472
17514
  const answerUrl = urls?.twiml;
17473
- const issueList = entry?.issues.map((issue) => `<li>${escapeHtml31(issue.severity)}: ${escapeHtml31(issue.message)}</li>`).join("") ?? "";
17474
- return `<article><h3>${escapeHtml31(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml31(answerLabel)} to <code>${escapeHtml31(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml31(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml31(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml31(carrier.setupPath)}?format=html">${escapeHtml31(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml31(carrier.smokePath)}?format=html">${escapeHtml31(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml31(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml31(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
17515
+ const issueList = entry?.issues.map((issue) => `<li>${escapeHtml32(issue.severity)}: ${escapeHtml32(issue.message)}</li>`).join("") ?? "";
17516
+ return `<article><h3>${escapeHtml32(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml32(answerLabel)} to <code>${escapeHtml32(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml32(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml32(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml32(carrier.setupPath)}?format=html">${escapeHtml32(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml32(carrier.smokePath)}?format=html">${escapeHtml32(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml32(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml32(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
17475
17517
  }).join("");
17476
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(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{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.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}.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>${escapeHtml31(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="${escapeHtml31(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</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>`;
17518
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(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{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.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}.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>${escapeHtml32(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="${escapeHtml32(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</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>`;
17477
17519
  };
17478
17520
  var createVoicePhoneAgent = (options) => {
17479
17521
  const carrierSummaries = options.carriers.map((carrier) => ({
@@ -19495,7 +19537,7 @@ var createOpenAIVoiceTTS = (options) => {
19495
19537
  };
19496
19538
  // src/providerCapabilities.ts
19497
19539
  import { Elysia as Elysia31 } from "elysia";
19498
- var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19540
+ var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19499
19541
  var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
19500
19542
  configured: true,
19501
19543
  features: options.features?.[provider],
@@ -19558,27 +19600,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
19558
19600
  var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
19559
19601
  const title = options.title ?? "Voice Provider Capabilities";
19560
19602
  const cards = report.capabilities.map((capability) => {
19561
- const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml32(feature)}</span>`).join("");
19562
- return `<article class="card ${escapeHtml32(capability.status)}">
19603
+ const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml33(feature)}</span>`).join("");
19604
+ return `<article class="card ${escapeHtml33(capability.status)}">
19563
19605
  <div class="card-header">
19564
19606
  <div>
19565
- <p class="eyebrow">${escapeHtml32(capability.kind)}</p>
19566
- <h2>${escapeHtml32(capability.label ?? capability.provider)}</h2>
19607
+ <p class="eyebrow">${escapeHtml33(capability.kind)}</p>
19608
+ <h2>${escapeHtml33(capability.label ?? capability.provider)}</h2>
19567
19609
  </div>
19568
- <strong>${escapeHtml32(capability.status)}</strong>
19610
+ <strong>${escapeHtml33(capability.status)}</strong>
19569
19611
  </div>
19570
- ${capability.description ? `<p>${escapeHtml32(capability.description)}</p>` : ""}
19612
+ ${capability.description ? `<p>${escapeHtml33(capability.description)}</p>` : ""}
19571
19613
  <dl>
19572
19614
  <div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
19573
19615
  <div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
19574
- <div><dt>Model</dt><dd>${escapeHtml32(capability.model ?? "default")}</dd></div>
19616
+ <div><dt>Model</dt><dd>${escapeHtml33(capability.model ?? "default")}</dd></div>
19575
19617
  <div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
19576
19618
  <div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
19577
19619
  </dl>
19578
19620
  ${features ? `<div class="features">${features}</div>` : ""}
19579
19621
  </article>`;
19580
19622
  }).join("");
19581
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(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>${escapeHtml32(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>`;
19623
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(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>${escapeHtml33(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>`;
19582
19624
  };
19583
19625
  var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
19584
19626
  var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
@@ -19605,7 +19647,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
19605
19647
  };
19606
19648
  // src/resilienceRoutes.ts
19607
19649
  import { Elysia as Elysia32 } from "elysia";
19608
- var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19650
+ var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19609
19651
  var getString11 = (value) => typeof value === "string" ? value : undefined;
19610
19652
  var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
19611
19653
  var getBoolean2 = (value) => value === true;
@@ -19752,13 +19794,13 @@ var summarizeRoutingEvents = (events) => {
19752
19794
  };
19753
19795
  var renderProviderCards = (title, providers) => {
19754
19796
  if (providers.length === 0) {
19755
- return `<p class="muted">No ${escapeHtml33(title)} provider health yet.</p>`;
19797
+ return `<p class="muted">No ${escapeHtml34(title)} provider health yet.</p>`;
19756
19798
  }
19757
19799
  return `<div class="provider-grid">${providers.map((provider) => `
19758
- <article class="card provider ${escapeHtml33(provider.status)}">
19800
+ <article class="card provider ${escapeHtml34(provider.status)}">
19759
19801
  <div class="card-header">
19760
- <strong>${escapeHtml33(provider.provider)}</strong>
19761
- <span>${escapeHtml33(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
19802
+ <strong>${escapeHtml34(provider.provider)}</strong>
19803
+ <span>${escapeHtml34(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
19762
19804
  </div>
19763
19805
  <dl>
19764
19806
  <div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
@@ -19767,7 +19809,7 @@ var renderProviderCards = (title, providers) => {
19767
19809
  <div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
19768
19810
  <div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
19769
19811
  </dl>
19770
- ${provider.lastError ? `<p class="muted">${escapeHtml33(provider.lastError)}</p>` : ""}
19812
+ ${provider.lastError ? `<p class="muted">${escapeHtml34(provider.lastError)}</p>` : ""}
19771
19813
  </article>
19772
19814
  `).join("")}</div>`;
19773
19815
  };
@@ -19776,24 +19818,24 @@ var renderTimeline2 = (events) => {
19776
19818
  return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
19777
19819
  }
19778
19820
  return `<div class="timeline">${events.slice(0, 40).map((event) => `
19779
- <article class="card event ${escapeHtml33(event.status ?? "unknown")}">
19821
+ <article class="card event ${escapeHtml34(event.status ?? "unknown")}">
19780
19822
  <div class="card-header">
19781
- <strong>${escapeHtml33(event.kind.toUpperCase())} ${escapeHtml33(event.operation ?? "generate")}</strong>
19823
+ <strong>${escapeHtml34(event.kind.toUpperCase())} ${escapeHtml34(event.operation ?? "generate")}</strong>
19782
19824
  <span>${new Date(event.at).toLocaleString()}</span>
19783
19825
  </div>
19784
19826
  <p>
19785
- <span class="pill">${escapeHtml33(event.status ?? "unknown")}</span>
19786
- <span class="pill">provider: ${escapeHtml33(event.provider ?? "unknown")}</span>
19787
- ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml33(event.fallbackProvider)}</span>` : ""}
19827
+ <span class="pill">${escapeHtml34(event.status ?? "unknown")}</span>
19828
+ <span class="pill">provider: ${escapeHtml34(event.provider ?? "unknown")}</span>
19829
+ ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml34(event.fallbackProvider)}</span>` : ""}
19788
19830
  ${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
19789
19831
  </p>
19790
19832
  <dl>
19791
19833
  <div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
19792
19834
  <div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
19793
19835
  <div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
19794
- <div><dt>Session</dt><dd>${escapeHtml33(event.sessionId)}</dd></div>
19836
+ <div><dt>Session</dt><dd>${escapeHtml34(event.sessionId)}</dd></div>
19795
19837
  </dl>
19796
- ${event.error ? `<p class="muted">${escapeHtml33(event.error)}</p>` : ""}
19838
+ ${event.error ? `<p class="muted">${escapeHtml34(event.error)}</p>` : ""}
19797
19839
  </article>
19798
19840
  `).join("")}</div>`;
19799
19841
  };
@@ -19803,9 +19845,9 @@ var renderSessionKind = (kind, summary) => {
19803
19845
  const status = latest?.status ?? "idle";
19804
19846
  const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
19805
19847
  return `<div>
19806
- <dt>${escapeHtml33(kind.toUpperCase())}</dt>
19807
- <dd>${escapeHtml33(provider)}${escapeHtml33(fallback)}</dd>
19808
- <small>${escapeHtml33(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>
19848
+ <dt>${escapeHtml34(kind.toUpperCase())}</dt>
19849
+ <dd>${escapeHtml34(provider)}${escapeHtml34(fallback)}</dd>
19850
+ <small>${escapeHtml34(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>
19809
19851
  </div>`;
19810
19852
  };
19811
19853
  var renderSessionSummaries = (sessions) => {
@@ -19813,10 +19855,10 @@ var renderSessionSummaries = (sessions) => {
19813
19855
  return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
19814
19856
  }
19815
19857
  return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
19816
- <article class="card session ${escapeHtml33(session.status)}">
19858
+ <article class="card session ${escapeHtml34(session.status)}">
19817
19859
  <div class="card-header">
19818
- <strong>${escapeHtml33(session.sessionId)}</strong>
19819
- <span>${escapeHtml33(session.status)}</span>
19860
+ <strong>${escapeHtml34(session.sessionId)}</strong>
19861
+ <span>${escapeHtml34(session.status)}</span>
19820
19862
  </div>
19821
19863
  <p>
19822
19864
  <span class="pill">${session.eventCount} routing events</span>
@@ -19843,26 +19885,26 @@ var renderSimulationControls = (kind, simulation) => {
19843
19885
  const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
19844
19886
  const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
19845
19887
  const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
19846
- return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml33(pathPrefix)}">
19847
- <p class="muted">${escapeHtml33(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
19888
+ return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml34(pathPrefix)}">
19889
+ <p class="muted">${escapeHtml34(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
19848
19890
  <div class="simulate-actions">
19849
- ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml33(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml33(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
19850
- ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml33(provider.provider)}">Mark ${escapeHtml33(provider.provider)} recovered</button>`).join("")}
19891
+ ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml34(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml34(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
19892
+ ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml34(provider.provider)}">Mark ${escapeHtml34(provider.provider)} recovered</button>`).join("")}
19851
19893
  </div>
19852
- ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml33(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
19894
+ ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml34(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
19853
19895
  <pre class="simulate-output" hidden></pre>
19854
19896
  </div>`;
19855
19897
  };
19856
19898
  var renderVoiceResilienceHTML = (input) => {
19857
19899
  const summary = summarizeRoutingEvents(input.routingEvents);
19858
- const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml33(kind)}: ${String(count)}</span>`).join("");
19859
- const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml33(link.href)}">${escapeHtml33(link.label)}</a>`).join(" \xB7 ") : "";
19900
+ const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml34(kind)}: ${String(count)}</span>`).join("");
19901
+ const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml34(link.href)}">${escapeHtml34(link.label)}</a>`).join(" \xB7 ") : "";
19860
19902
  return `<!doctype html>
19861
19903
  <html lang="en">
19862
19904
  <head>
19863
19905
  <meta charset="utf-8" />
19864
19906
  <meta name="viewport" content="width=device-width, initial-scale=1" />
19865
- <title>${escapeHtml33(input.title ?? "AbsoluteJS Voice Resilience")}</title>
19907
+ <title>${escapeHtml34(input.title ?? "AbsoluteJS Voice Resilience")}</title>
19866
19908
  <style>
19867
19909
  :root { color-scheme: dark; }
19868
19910
  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; }
@@ -20084,7 +20126,7 @@ var assertVoiceProviderRoutingContract = async (options) => {
20084
20126
  };
20085
20127
  // src/productionReadiness.ts
20086
20128
  import { Elysia as Elysia33 } from "elysia";
20087
- var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20129
+ var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20088
20130
  var rollupStatus2 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
20089
20131
  var carrierStatus = (matrix) => matrix.summary.failing > 0 ? "fail" : matrix.summary.warnings > 0 || matrix.summary.ready < matrix.summary.providers ? "warn" : "pass";
20090
20132
  var resolveCarriers = async (options, input) => {
@@ -20232,6 +20274,31 @@ var summarizeAuditDeliveries = async (options) => {
20232
20274
  warnPendingAfterMs
20233
20275
  };
20234
20276
  };
20277
+ var summarizeOpsActionHistory = async (options) => {
20278
+ if (!options.opsActionHistory) {
20279
+ return;
20280
+ }
20281
+ const opsActionHistory = "list" in options.opsActionHistory ? {
20282
+ failOnFailedActions: true,
20283
+ store: options.opsActionHistory,
20284
+ warnWhenEmpty: false
20285
+ } : {
20286
+ failOnFailedActions: options.opsActionHistory.failOnFailedActions ?? true,
20287
+ store: options.opsActionHistory.store,
20288
+ warnWhenEmpty: options.opsActionHistory.warnWhenEmpty ?? false
20289
+ };
20290
+ const report = await buildVoiceOpsActionHistoryReport({
20291
+ audit: opsActionHistory.store
20292
+ });
20293
+ const status = report.failed > 0 ? opsActionHistory.failOnFailedActions ? "fail" : "warn" : report.total === 0 && opsActionHistory.warnWhenEmpty ? "warn" : "pass";
20294
+ return {
20295
+ failed: report.failed,
20296
+ passed: report.passed,
20297
+ status,
20298
+ total: report.total,
20299
+ warnWhenEmpty: opsActionHistory.warnWhenEmpty
20300
+ };
20301
+ };
20235
20302
  var summarizeTraceDeliveries = async (options) => {
20236
20303
  if (!options.traceDeliveries) {
20237
20304
  return;
@@ -20336,6 +20403,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20336
20403
  handoffs,
20337
20404
  audit,
20338
20405
  auditDeliveries,
20406
+ opsActionHistory,
20339
20407
  traceDeliveries,
20340
20408
  deliveryRuntimeSummary,
20341
20409
  carriers,
@@ -20365,6 +20433,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20365
20433
  summarizeVoiceHandoffHealth({ events }),
20366
20434
  summarizeAuditEvidence(options),
20367
20435
  summarizeAuditDeliveries(options),
20436
+ summarizeOpsActionHistory(options),
20368
20437
  summarizeTraceDeliveries(options),
20369
20438
  resolveDeliveryRuntime(options, { query, request }),
20370
20439
  resolveCarriers(options, { query, request }),
@@ -20647,6 +20716,23 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20647
20716
  ]
20648
20717
  });
20649
20718
  }
20719
+ if (opsActionHistory) {
20720
+ checks.push({
20721
+ detail: opsActionHistory.status === "pass" ? opsActionHistory.total > 0 ? `${opsActionHistory.passed} operator action(s) completed successfully.` : "No operator action failures are recorded." : opsActionHistory.failed > 0 ? `${opsActionHistory.failed} operator action(s) failed and need review.` : "No operator action history is recorded yet.",
20722
+ href: options.links?.opsActions ?? "/voice/ops-actions",
20723
+ label: "Operator action history",
20724
+ proofSource: proofSource("opsActions", "operatorActions"),
20725
+ status: opsActionHistory.status,
20726
+ value: `${opsActionHistory.passed}/${opsActionHistory.total}`,
20727
+ actions: opsActionHistory.status === "pass" ? [] : [
20728
+ {
20729
+ description: "Open operator action history and inspect failed control-plane actions.",
20730
+ href: options.links?.opsActions ?? "/voice/ops-actions",
20731
+ label: "Open action history"
20732
+ }
20733
+ ]
20734
+ });
20735
+ }
20650
20736
  if (traceDeliveries) {
20651
20737
  checks.push({
20652
20738
  detail: traceDeliveries.status === "pass" ? "Trace sink deliveries are clear." : traceDeliveries.staleFailing > 0 ? `${traceDeliveries.staleFailing} trace delivery item(s) are stale past ${Math.round(traceDeliveries.failPendingAfterMs / 1000)}s.` : traceDeliveries.failed > 0 || traceDeliveries.deadLettered > 0 ? `${traceDeliveries.failed} failed and ${traceDeliveries.deadLettered} dead-lettered trace delivery item(s).` : `${traceDeliveries.pending} trace delivery item(s) are pending.`,
@@ -20710,6 +20796,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20710
20796
  handoffs: "/handoffs",
20711
20797
  handoffRetry: "/api/voice-handoffs/retry",
20712
20798
  liveLatency: "/traces",
20799
+ opsActions: "/voice/ops-actions",
20713
20800
  phoneAgentSmoke: "/sessions",
20714
20801
  providerRoutingContracts: "/resilience",
20715
20802
  quality: "/quality",
@@ -20733,6 +20820,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20733
20820
  total: handoffs.total
20734
20821
  },
20735
20822
  liveLatency,
20823
+ opsActionHistory,
20736
20824
  providers: {
20737
20825
  degraded: degradedProviders,
20738
20826
  total: providers.length
@@ -20759,20 +20847,20 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20759
20847
  var renderVoiceProductionReadinessHTML = (report, options = {}) => {
20760
20848
  const title = options.title ?? "AbsoluteJS Voice Production Readiness";
20761
20849
  const checks = report.checks.map((check, index) => {
20762
- const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml34(action.href)}">${escapeHtml34(action.label)}</button>` : `<a href="${escapeHtml34(action.href)}">${escapeHtml34(action.label)}</a>`).join("");
20763
- return `<article class="check ${escapeHtml34(check.status)}">
20850
+ const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml35(action.href)}">${escapeHtml35(action.label)}</button>` : `<a href="${escapeHtml35(action.href)}">${escapeHtml35(action.label)}</a>`).join("");
20851
+ return `<article class="check ${escapeHtml35(check.status)}">
20764
20852
  <div>
20765
- <span>${escapeHtml34(check.status.toUpperCase())}</span>
20766
- <h2>${escapeHtml34(check.label)}</h2>
20767
- ${check.detail ? `<p>${escapeHtml34(check.detail)}</p>` : ""}
20768
- ${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml34(check.proofSource.href)}">${escapeHtml34(check.proofSource.sourceLabel)}</a>` : escapeHtml34(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml34(check.proofSource.detail)}` : ""}</p>` : ""}
20853
+ <span>${escapeHtml35(check.status.toUpperCase())}</span>
20854
+ <h2>${escapeHtml35(check.label)}</h2>
20855
+ ${check.detail ? `<p>${escapeHtml35(check.detail)}</p>` : ""}
20856
+ ${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml35(check.proofSource.href)}">${escapeHtml35(check.proofSource.sourceLabel)}</a>` : escapeHtml35(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml35(check.proofSource.detail)}` : ""}</p>` : ""}
20769
20857
  ${actions ? `<p class="actions">${actions}</p>` : ""}
20770
20858
  </div>
20771
- <strong>${escapeHtml34(String(check.value ?? check.status))}</strong>
20772
- ${check.href ? `<a href="${escapeHtml34(check.href)}">Open surface</a>` : ""}
20859
+ <strong>${escapeHtml35(String(check.value ?? check.status))}</strong>
20860
+ ${check.href ? `<a href="${escapeHtml35(check.href)}">Open surface</a>` : ""}
20773
20861
  </article>`;
20774
20862
  }).join("");
20775
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml34(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(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.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}.status.pass,.check.pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.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{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check strong{font-size:1.5rem}.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>${escapeHtml34(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 ${escapeHtml34(report.status)}">Overall: ${escapeHtml34(report.status.toUpperCase())}</p><p>Checked ${escapeHtml34(new Date(report.checkedAt).toLocaleString())}</p></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>`;
20863
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(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(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.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}.status.pass,.check.pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.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{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check strong{font-size:1.5rem}.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>${escapeHtml35(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 ${escapeHtml35(report.status)}">Overall: ${escapeHtml35(report.status.toUpperCase())}</p><p>Checked ${escapeHtml35(new Date(report.checkedAt).toLocaleString())}</p></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>`;
20776
20864
  };
20777
20865
  var createVoiceProductionReadinessRoutes = (options) => {
20778
20866
  const path = options.path ?? "/api/production-readiness";
@@ -20834,7 +20922,7 @@ var DEFAULT_LINKS = [
20834
20922
  label: "Handoffs"
20835
20923
  }
20836
20924
  ];
20837
- var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20925
+ var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20838
20926
  var countProviderStatuses = (providers) => {
20839
20927
  const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
20840
20928
  const healthy = providers.filter((provider) => provider.status === "healthy").length;
@@ -20903,16 +20991,16 @@ var buildVoiceOpsConsoleReport = async (options) => {
20903
20991
  trace
20904
20992
  };
20905
20993
  };
20906
- var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml35(input.label)}</span><strong>${escapeHtml35(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml35(input.status)}">${escapeHtml35(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml35(input.href)}">Open</a>` : ""}</article>`;
20994
+ var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml36(input.label)}</span><strong>${escapeHtml36(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml36(input.status)}">${escapeHtml36(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml36(input.href)}">Open</a>` : ""}</article>`;
20907
20995
  var renderVoiceOpsConsoleHTML = (report, options = {}) => {
20908
20996
  const links = report.links.map((link) => `<article class="surface">
20909
- <div><h2>${escapeHtml35(link.label)}</h2>${link.description ? `<p>${escapeHtml35(link.description)}</p>` : ""}</div>
20910
- <p><a href="${escapeHtml35(link.href)}">Open ${escapeHtml35(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml35(link.statusHref)}">Status</a>` : ""}</p>
20997
+ <div><h2>${escapeHtml36(link.label)}</h2>${link.description ? `<p>${escapeHtml36(link.description)}</p>` : ""}</div>
20998
+ <p><a href="${escapeHtml36(link.href)}">Open ${escapeHtml36(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml36(link.statusHref)}">Status</a>` : ""}</p>
20911
20999
  </article>`).join("");
20912
- const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml35(session.sessionId)}</td><td>${escapeHtml35(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml35(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
20913
- const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml35(event.kind)}</td><td>${escapeHtml35(event.provider ?? "unknown")}</td><td>${escapeHtml35(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml35(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
21000
+ const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml36(session.sessionId)}</td><td>${escapeHtml36(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml36(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
21001
+ const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml36(event.kind)}</td><td>${escapeHtml36(event.provider ?? "unknown")}</td><td>${escapeHtml36(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml36(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
20914
21002
  const title = options.title ?? "AbsoluteJS Voice Ops Console";
20915
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(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>${escapeHtml35(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 ${escapeHtml35(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>`;
21003
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(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>${escapeHtml36(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 ${escapeHtml36(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>`;
20916
21004
  };
20917
21005
  var createVoiceOpsConsoleRoutes = (options) => {
20918
21006
  const path = options.path ?? "/ops-console";
@@ -21105,14 +21193,14 @@ var summarizeVoiceOpsStatus = async (options) => {
21105
21193
  };
21106
21194
  // src/opsStatusRoutes.ts
21107
21195
  import { Elysia as Elysia35 } from "elysia";
21108
- var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21196
+ var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21109
21197
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
21110
21198
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
21111
21199
  const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
21112
21200
  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;
21113
- return `<article class="surface ${escapeHtml36(surface.status)}"><span>${escapeHtml36(surface.status.toUpperCase())}</span><h2>${escapeHtml36(key)}</h2><strong>${escapeHtml36(value)}</strong></article>`;
21201
+ return `<article class="surface ${escapeHtml37(surface.status)}"><span>${escapeHtml37(surface.status.toUpperCase())}</span><h2>${escapeHtml37(key)}</h2><strong>${escapeHtml37(value)}</strong></article>`;
21114
21202
  }).join("");
21115
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(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>${escapeHtml36(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml36(report.status)}">Overall: ${escapeHtml36(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>`;
21203
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(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>${escapeHtml37(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml37(report.status)}">Overall: ${escapeHtml37(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>`;
21116
21204
  };
21117
21205
  var createVoiceOpsStatusRoutes = (options) => {
21118
21206
  const path = options.path ?? "/api/voice/ops-status";
@@ -21550,7 +21638,7 @@ var createVoiceTTSProviderRouter = (options) => {
21550
21638
  };
21551
21639
  // src/traceDeliveryRoutes.ts
21552
21640
  import { Elysia as Elysia36 } from "elysia";
21553
- var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21641
+ var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21554
21642
  var getString12 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
21555
21643
  var getNumber7 = (value) => {
21556
21644
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -21631,14 +21719,14 @@ var renderSinkResults2 = (delivery) => {
21631
21719
  if (entries.length === 0) {
21632
21720
  return "<p>No sink delivery attempts recorded yet.</p>";
21633
21721
  }
21634
- return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml37(sinkId)}</strong>: ${escapeHtml37(result.status)}${result.deliveredTo ? ` to ${escapeHtml37(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml37(result.error)})` : ""}</li>`).join("")}</ul>`;
21722
+ return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml38(sinkId)}</strong>: ${escapeHtml38(result.status)}${result.deliveredTo ? ` to ${escapeHtml38(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml38(result.error)})` : ""}</li>`).join("")}</ul>`;
21635
21723
  };
21636
- var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml37(event.type)} <small>${escapeHtml37(event.id)}</small>${event.sessionId ? ` session=${escapeHtml37(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
21724
+ var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml38(event.type)} <small>${escapeHtml38(event.id)}</small>${event.sessionId ? ` session=${escapeHtml38(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
21637
21725
  var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
21638
21726
  const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
21639
- const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml37(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
21640
- const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml37(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml37(delivery.deliveryStatus)}</span><h2>${escapeHtml37(delivery.id)}</h2><p>${escapeHtml37(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml37(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml37(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
21641
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(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>${escapeHtml37(title)}</h1><p>Checked ${escapeHtml37(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>`;
21727
+ const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml38(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
21728
+ const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml38(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml38(delivery.deliveryStatus)}</span><h2>${escapeHtml38(delivery.id)}</h2><p>${escapeHtml38(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml38(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml38(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
21729
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(title)}</h1><p>Checked ${escapeHtml38(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>`;
21642
21730
  };
21643
21731
  var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
21644
21732
  var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
@@ -21677,7 +21765,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
21677
21765
  };
21678
21766
  // src/traceTimeline.ts
21679
21767
  import { Elysia as Elysia37 } from "elysia";
21680
- var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21768
+ var escapeHtml39 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21681
21769
  var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
21682
21770
  var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
21683
21771
  var firstString3 = (payload, keys) => {
@@ -21845,15 +21933,15 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
21845
21933
  };
21846
21934
  };
21847
21935
  var formatMs3 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
21848
- var renderProviderCards2 = (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>${escapeHtml38(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(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>`;
21936
+ var renderProviderCards2 = (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>${escapeHtml39(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(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>`;
21849
21937
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
21850
- const events = session.events.map((event) => `<tr class="${escapeHtml38(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml38(event.type)}</td><td>${escapeHtml38(event.label)}</td><td>${escapeHtml38(event.provider ?? "")}</td><td>${escapeHtml38(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
21851
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml38(issue.severity)}">${escapeHtml38(issue.code)}: ${escapeHtml38(issue.message)}</li>`).join("") : "<li>none</li>";
21852
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(session.sessionId)}</h1><p class="status ${escapeHtml38(session.status)}">${escapeHtml38(session.status)}</p></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>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(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>`;
21938
+ const events = session.events.map((event) => `<tr class="${escapeHtml39(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml39(event.type)}</td><td>${escapeHtml39(event.label)}</td><td>${escapeHtml39(event.provider ?? "")}</td><td>${escapeHtml39(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
21939
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml39(issue.severity)}">${escapeHtml39(issue.code)}: ${escapeHtml39(issue.message)}</li>`).join("") : "<li>none</li>";
21940
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml39(session.sessionId)}</h1><p class="status ${escapeHtml39(session.status)}">${escapeHtml39(session.status)}</p></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>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(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>`;
21853
21941
  };
21854
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml38(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml38(session.sessionId)}</a></td><td>${escapeHtml38(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml38(provider.provider)).join(", ")}</td></tr>`).join("");
21942
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml39(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml39(session.sessionId)}</a></td><td>${escapeHtml39(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml39(provider.provider)).join(", ")}</td></tr>`).join("");
21855
21943
  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}}";
21856
- var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml38(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><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>`;
21944
+ var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml39(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><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>`;
21857
21945
  var createVoiceTraceTimelineRoutes = (options) => {
21858
21946
  const path = options.path ?? "/api/voice-traces";
21859
21947
  const htmlPath = options.htmlPath ?? "/traces";
@@ -23580,6 +23668,7 @@ export {
23580
23668
  renderVoiceOutcomeContractHTML,
23581
23669
  renderVoiceOpsStatusHTML,
23582
23670
  renderVoiceOpsConsoleHTML,
23671
+ renderVoiceOpsActionHistoryHTML,
23583
23672
  renderVoiceLiveLatencyHTML,
23584
23673
  renderVoiceHandoffHealthHTML,
23585
23674
  renderVoiceEvalHTML,
@@ -23881,6 +23970,7 @@ export {
23881
23970
  buildVoiceOpsTaskFromSLABreach,
23882
23971
  buildVoiceOpsTaskFromReview,
23883
23972
  buildVoiceOpsConsoleReport,
23973
+ buildVoiceOpsActionHistoryReport,
23884
23974
  buildVoiceDiagnosticsMarkdown,
23885
23975
  buildVoiceDemoReadyReport,
23886
23976
  buildVoiceDeliverySinkReport,