@absolutejs/voice 0.0.22-beta.91 → 0.0.22-beta.93

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
@@ -5474,7 +5474,7 @@ var voice = (config) => {
5474
5474
  }).use(htmxRoutes());
5475
5475
  };
5476
5476
  // src/appKit.ts
5477
- import { Elysia as Elysia15 } from "elysia";
5477
+ import { Elysia as Elysia16 } from "elysia";
5478
5478
 
5479
5479
  // src/assistantHealth.ts
5480
5480
  import { Elysia as Elysia3 } from "elysia";
@@ -6849,8 +6849,89 @@ var createVoiceAssistantHealthRoutes = (options) => {
6849
6849
  return routes;
6850
6850
  };
6851
6851
 
6852
- // src/diagnosticsRoutes.ts
6852
+ // src/bargeInRoutes.ts
6853
6853
  import { Elysia as Elysia4 } from "elysia";
6854
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
6855
+ var isBargeInPayload = (value) => !!value && typeof value === "object" && typeof value.at === "number" && typeof value.id === "string" && typeof value.reason === "string" && typeof value.status === "string";
6856
+ var toBargeInEvent = (event) => event.type === "client.barge_in" && isBargeInPayload(event.payload) ? event.payload : undefined;
6857
+ var summarizeVoiceBargeIn = (events, options = {}) => {
6858
+ const thresholdMs = options.thresholdMs ?? 250;
6859
+ const bargeInEvents = events.map(toBargeInEvent).filter((event) => !!event).sort((left, right) => left.at - right.at);
6860
+ const stopped = bargeInEvents.filter((event) => event.status === "stopped");
6861
+ const latencies = stopped.map((event) => event.latencyMs).filter((value) => typeof value === "number");
6862
+ const failed = stopped.filter((event) => typeof event.latencyMs === "number" && event.latencyMs > thresholdMs).length;
6863
+ const passed = stopped.length - failed;
6864
+ const grouped = new Map;
6865
+ for (const event of stopped) {
6866
+ const sessionId = event.sessionId ?? "unknown";
6867
+ grouped.set(sessionId, [...grouped.get(sessionId) ?? [], event]);
6868
+ }
6869
+ return {
6870
+ averageLatencyMs: latencies.length > 0 ? Math.round(latencies.reduce((total, value) => total + value, 0) / latencies.length) : undefined,
6871
+ checkedAt: Date.now(),
6872
+ events: bargeInEvents,
6873
+ failed,
6874
+ lastEvent: bargeInEvents.at(-1),
6875
+ passed,
6876
+ sessions: [...grouped.entries()].map(([sessionId, sessionEvents]) => {
6877
+ const sessionLatencies = sessionEvents.map((event) => event.latencyMs).filter((value) => typeof value === "number");
6878
+ const sessionFailed = sessionEvents.filter((event) => typeof event.latencyMs === "number" && event.latencyMs > thresholdMs).length;
6879
+ return {
6880
+ averageLatencyMs: sessionLatencies.length > 0 ? Math.round(sessionLatencies.reduce((total, value) => total + value, 0) / sessionLatencies.length) : undefined,
6881
+ failed: sessionFailed,
6882
+ passed: sessionEvents.length - sessionFailed,
6883
+ sessionId,
6884
+ total: sessionEvents.length
6885
+ };
6886
+ }).sort((left, right) => right.total - left.total),
6887
+ status: bargeInEvents.length === 0 ? "empty" : failed > 0 ? "fail" : stopped.length === 0 ? "warn" : "pass",
6888
+ thresholdMs,
6889
+ total: stopped.length
6890
+ };
6891
+ };
6892
+ var renderVoiceBargeInHTML = (report, options = {}) => {
6893
+ const title = options.title ?? "Voice Barge-In";
6894
+ const sessions = report.sessions.length ? report.sessions.map((session) => `<tr><td>${escapeHtml5(session.sessionId)}</td><td>${String(session.total)}</td><td>${String(session.passed)}</td><td>${String(session.failed)}</td><td>${String(session.averageLatencyMs ?? 0)}ms</td></tr>`).join("") : '<tr><td colspan="5">No barge-in events yet.</td></tr>';
6895
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml5(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn{color:#fbbf24}.fail{color:#fca5a5}.empty{color:#cbd5e1}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}</style></head><body><main><p class="eyebrow">Interruption quality</p><h1>${escapeHtml5(title)}</h1><p class="status ${escapeHtml5(report.status)}">Status: ${escapeHtml5(report.status)}</p><section class="metrics"><article><span>Interruptions</span><strong>${String(report.total)}</strong></article><article><span>Avg latency</span><strong>${String(report.averageLatencyMs ?? 0)}ms</strong></article><article><span>Passed</span><strong>${String(report.passed)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article></section><table><thead><tr><th>Session</th><th>Total</th><th>Passed</th><th>Failed</th><th>Avg latency</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
6896
+ };
6897
+ var createVoiceBargeInRoutes = (options) => {
6898
+ const path = options.path ?? "/api/voice-barge-in";
6899
+ const htmlPath = options.htmlPath ?? "/barge-in";
6900
+ const title = options.title ?? "AbsoluteJS Voice Barge-In";
6901
+ const routes = new Elysia4({
6902
+ name: options.name ?? "absolutejs-voice-barge-in"
6903
+ });
6904
+ routes.get(path, async () => summarizeVoiceBargeIn(await options.store.list(), {
6905
+ thresholdMs: options.thresholdMs
6906
+ }));
6907
+ routes.post(path, async ({ body }) => {
6908
+ if (!isBargeInPayload(body)) {
6909
+ return Response.json({ error: "Invalid barge-in event." }, { status: 400 });
6910
+ }
6911
+ await options.store.append({
6912
+ at: body.at,
6913
+ payload: body,
6914
+ sessionId: body.sessionId ?? "unknown",
6915
+ type: "client.barge_in"
6916
+ });
6917
+ return Response.json({ ok: true });
6918
+ });
6919
+ routes.get(htmlPath, async () => {
6920
+ const report = summarizeVoiceBargeIn(await options.store.list(), {
6921
+ thresholdMs: options.thresholdMs
6922
+ });
6923
+ return new Response(renderVoiceBargeInHTML(report, { title }), {
6924
+ headers: {
6925
+ "Content-Type": "text/html; charset=utf-8",
6926
+ ...options.headers
6927
+ }
6928
+ });
6929
+ });
6930
+ return routes;
6931
+ };
6932
+
6933
+ // src/diagnosticsRoutes.ts
6934
+ import { Elysia as Elysia5 } from "elysia";
6854
6935
 
6855
6936
  // src/trace.ts
6856
6937
  var createVoiceTraceEventId = (event) => [
@@ -7184,7 +7265,7 @@ var exportVoiceTrace = async (input) => {
7184
7265
  };
7185
7266
  };
7186
7267
  var toNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
7187
- var escapeHtml5 = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7268
+ var escapeHtml6 = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7188
7269
  var formatTraceValue = (value) => {
7189
7270
  if (value === undefined || value === null) {
7190
7271
  return "";
@@ -7462,10 +7543,10 @@ var renderVoiceTraceHTML = (events, options = {}) => {
7462
7543
  const offset = summary.startedAt === undefined ? event.at : Math.max(0, event.at - summary.startedAt);
7463
7544
  return [
7464
7545
  "<tr>",
7465
- `<td>${escapeHtml5(String(offset))}</td>`,
7466
- `<td>${escapeHtml5(event.type)}</td>`,
7467
- `<td>${escapeHtml5(event.turnId ?? "")}</td>`,
7468
- `<td><code>${escapeHtml5(JSON.stringify(event.payload))}</code></td>`,
7546
+ `<td>${escapeHtml6(String(offset))}</td>`,
7547
+ `<td>${escapeHtml6(event.type)}</td>`,
7548
+ `<td>${escapeHtml6(event.turnId ?? "")}</td>`,
7549
+ `<td><code>${escapeHtml6(JSON.stringify(event.payload))}</code></td>`,
7469
7550
  "</tr>"
7470
7551
  ].join("");
7471
7552
  }).join(`
@@ -7476,7 +7557,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
7476
7557
  "<head>",
7477
7558
  '<meta charset="utf-8" />',
7478
7559
  '<meta name="viewport" content="width=device-width, initial-scale=1" />',
7479
- `<title>${escapeHtml5(options.title ?? "Voice Trace")}</title>`,
7560
+ `<title>${escapeHtml6(options.title ?? "Voice Trace")}</title>`,
7480
7561
  "<style>",
7481
7562
  "body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}",
7482
7563
  "main{max-width:1100px;margin:auto}",
@@ -7490,7 +7571,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
7490
7571
  "</style>",
7491
7572
  "</head>",
7492
7573
  "<body><main>",
7493
- `<h1>${escapeHtml5(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
7574
+ `<h1>${escapeHtml6(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
7494
7575
  `<p class="${evaluation.pass ? "pass" : "fail"}">QA: ${evaluation.pass ? "pass" : "fail"}</p>`,
7495
7576
  '<section class="summary">',
7496
7577
  `<div class="card"><strong>Events</strong><br>${summary.eventCount}</div>`,
@@ -7504,7 +7585,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
7504
7585
  eventRows,
7505
7586
  "</tbody></table>",
7506
7587
  "<h2>Markdown Export</h2>",
7507
- `<pre>${escapeHtml5(markdown)}</pre>`,
7588
+ `<pre>${escapeHtml6(markdown)}</pre>`,
7508
7589
  "</main></body></html>"
7509
7590
  ].join(`
7510
7591
  `);
@@ -7517,7 +7598,7 @@ var buildVoiceTraceReplay = (events, options = {}) => ({
7517
7598
  });
7518
7599
 
7519
7600
  // src/diagnosticsRoutes.ts
7520
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
7601
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
7521
7602
  var getString3 = (value) => typeof value === "string" && value.trim() ? value : undefined;
7522
7603
  var getNumber2 = (value) => {
7523
7604
  const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
@@ -7583,9 +7664,9 @@ var renderDiagnosticsIndex = (input) => {
7583
7664
  const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
7584
7665
  const summary = summarizeVoiceTrace(events);
7585
7666
  const encoded = encodeURIComponent(sessionId);
7586
- return `<tr><td>${escapeHtml6(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
7667
+ return `<tr><td>${escapeHtml7(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
7587
7668
  }).join("");
7588
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml6(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml6(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
7669
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml7(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml7(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
7589
7670
  };
7590
7671
  var withRedaction = (events, query, defaultRedact) => {
7591
7672
  const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
@@ -7594,7 +7675,7 @@ var withRedaction = (events, query, defaultRedact) => {
7594
7675
  var createVoiceDiagnosticsRoutes = (options) => {
7595
7676
  const path = options.path ?? "/diagnostics";
7596
7677
  const title = options.title ?? "AbsoluteJS Voice Diagnostics";
7597
- const routes = new Elysia4({
7678
+ const routes = new Elysia5({
7598
7679
  name: options.name ?? "absolutejs-voice-diagnostics"
7599
7680
  });
7600
7681
  routes.get(path, async () => {
@@ -7652,16 +7733,16 @@ var createVoiceDiagnosticsRoutes = (options) => {
7652
7733
  };
7653
7734
 
7654
7735
  // src/evalRoutes.ts
7655
- import { Elysia as Elysia7 } from "elysia";
7736
+ import { Elysia as Elysia8 } from "elysia";
7656
7737
  import { mkdir } from "fs/promises";
7657
7738
  import { dirname } from "path";
7658
7739
 
7659
7740
  // src/qualityRoutes.ts
7660
- import { Elysia as Elysia6 } from "elysia";
7741
+ import { Elysia as Elysia7 } from "elysia";
7661
7742
 
7662
7743
  // src/handoffHealth.ts
7663
- import { Elysia as Elysia5 } from "elysia";
7664
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
7744
+ import { Elysia as Elysia6 } from "elysia";
7745
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
7665
7746
  var getString4 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
7666
7747
  var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
7667
7748
  var increment2 = (record, key) => {
@@ -7779,10 +7860,10 @@ var renderActionSummary = (summary) => {
7779
7860
  return [
7780
7861
  '<section class="voice-handoff-health-columns">',
7781
7862
  "<article><h3>Actions</h3>",
7782
- actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml7(action)}: ${String(count)}</li>`).join("")}</ul>`,
7863
+ actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml8(action)}: ${String(count)}</li>`).join("")}</ul>`,
7783
7864
  "</article>",
7784
7865
  "<article><h3>Adapters</h3>",
7785
- adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml7(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
7866
+ adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml8(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
7786
7867
  "</article>",
7787
7868
  "</section>"
7788
7869
  ].join("");
@@ -7796,22 +7877,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
7796
7877
  summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
7797
7878
  '<div class="voice-handoff-health-events">',
7798
7879
  ...summary.events.map((event) => [
7799
- `<article class="${escapeHtml7(event.status)}">`,
7880
+ `<article class="${escapeHtml8(event.status)}">`,
7800
7881
  '<div class="voice-handoff-health-event-header">',
7801
- `<strong>${escapeHtml7(event.action ?? "handoff")}</strong>`,
7802
- `<span>${escapeHtml7(event.status)}</span>`,
7882
+ `<strong>${escapeHtml8(event.action ?? "handoff")}</strong>`,
7883
+ `<span>${escapeHtml8(event.status)}</span>`,
7803
7884
  "</div>",
7804
- `<p><small>${escapeHtml7(event.sessionId)}</small></p>`,
7805
- event.target ? `<p>Target: ${escapeHtml7(event.target)}</p>` : "",
7806
- event.reason ? `<p>Reason: ${escapeHtml7(event.reason)}</p>` : "",
7885
+ `<p><small>${escapeHtml8(event.sessionId)}</small></p>`,
7886
+ event.target ? `<p>Target: ${escapeHtml8(event.target)}</p>` : "",
7887
+ event.reason ? `<p>Reason: ${escapeHtml8(event.reason)}</p>` : "",
7807
7888
  event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
7808
7889
  "<li>",
7809
- `${escapeHtml7(delivery.adapterId)}: ${escapeHtml7(delivery.status)}`,
7810
- delivery.deliveredTo ? ` to ${escapeHtml7(delivery.deliveredTo)}` : "",
7811
- delivery.error ? ` (${escapeHtml7(delivery.error)})` : "",
7890
+ `${escapeHtml8(delivery.adapterId)}: ${escapeHtml8(delivery.status)}`,
7891
+ delivery.deliveredTo ? ` to ${escapeHtml8(delivery.deliveredTo)}` : "",
7892
+ delivery.error ? ` (${escapeHtml8(delivery.error)})` : "",
7812
7893
  "</li>"
7813
7894
  ].join("")).join("")}</ul>` : "",
7814
- event.replayHref ? `<p><a href="${escapeHtml7(event.replayHref)}">Open replay</a></p>` : "",
7895
+ event.replayHref ? `<p><a href="${escapeHtml8(event.replayHref)}">Open replay</a></p>` : "",
7815
7896
  "</article>"
7816
7897
  ].join("")),
7817
7898
  "</div>"
@@ -7843,7 +7924,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
7843
7924
  var createVoiceHandoffHealthRoutes = (options = {}) => {
7844
7925
  const path = options.path ?? "/api/voice-handoffs";
7845
7926
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
7846
- const routes = new Elysia5({
7927
+ const routes = new Elysia6({
7847
7928
  name: options.name ?? "absolutejs-voice-handoff-health"
7848
7929
  }).get(path, createVoiceHandoffHealthJSONHandler(options));
7849
7930
  if (htmlPath) {
@@ -7964,17 +8045,17 @@ var evaluateVoiceQuality = async (input) => {
7964
8045
  thresholds
7965
8046
  };
7966
8047
  };
7967
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8048
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
7968
8049
  var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
7969
8050
  var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
7970
8051
  var renderVoiceQualityHTML = (report, options = {}) => {
7971
- const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml8(metric.label)}</td><td>${escapeHtml8(formatMetricValue(metric))}</td><td>${escapeHtml8(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml8(key)}</code></td></tr>`).join("");
7972
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml8(link.href)}">${escapeHtml8(link.label)}</a>`).join("")}</nav>` : "";
8052
+ const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml9(metric.label)}</td><td>${escapeHtml9(formatMetricValue(metric))}</td><td>${escapeHtml9(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml9(key)}</code></td></tr>`).join("");
8053
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml9(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
7973
8054
  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>`;
7974
8055
  };
7975
8056
  var createVoiceQualityRoutes = (options) => {
7976
8057
  const path = options.path ?? "/quality";
7977
- const routes = new Elysia6({
8058
+ const routes = new Elysia7({
7978
8059
  name: options.name ?? "absolutejs-voice-quality"
7979
8060
  });
7980
8061
  const getReport = () => evaluateVoiceQuality({
@@ -8003,7 +8084,7 @@ var createVoiceQualityRoutes = (options) => {
8003
8084
  };
8004
8085
 
8005
8086
  // src/evalRoutes.ts
8006
- var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8087
+ var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8007
8088
  var rate2 = (count, total) => count / Math.max(1, total);
8008
8089
  var normalizeSearchText = (value) => value.trim().toLowerCase();
8009
8090
  var getString6 = (value) => typeof value === "string" ? value : undefined;
@@ -8312,44 +8393,44 @@ var formatTime = (value) => value === undefined ? "unknown" : new Date(value).to
8312
8393
  var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
8313
8394
  var renderVoiceEvalHTML = (report, options = {}) => {
8314
8395
  const title = options.title ?? "AbsoluteJS Voice Evals";
8315
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml9(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
8316
- const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml9(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>';
8396
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml10(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</nav>` : "";
8397
+ const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml10(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>';
8317
8398
  const sessions = report.sessions.length ? report.sessions.map((session) => {
8318
8399
  const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
8319
- return `<tr class="${session.status}"><td>${escapeHtml9(session.sessionId)}</td><td>${escapeHtml9(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml9(formatTime(session.endedAt))}</td><td>${escapeHtml9(failedMetrics || "none")}</td></tr>`;
8400
+ return `<tr class="${session.status}"><td>${escapeHtml10(session.sessionId)}</td><td>${escapeHtml10(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml10(formatTime(session.endedAt))}</td><td>${escapeHtml10(failedMetrics || "none")}</td></tr>`;
8320
8401
  }).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
8321
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml9(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>${escapeHtml9(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>`;
8402
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml10(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>${escapeHtml10(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>`;
8322
8403
  };
8323
8404
  var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
8324
8405
  const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
8325
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml9(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
8326
- const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml9(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
8327
- const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml9(id)}</li>`).join("") : "<li>none</li>";
8328
- const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml9(id)}</li>`).join("") : "<li>none</li>";
8329
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml9(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>${escapeHtml9(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml9(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml9(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>${escapeHtml9(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>`;
8406
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml10(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</nav>` : "";
8407
+ const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml10(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
8408
+ const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml10(id)}</li>`).join("") : "<li>none</li>";
8409
+ const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml10(id)}</li>`).join("") : "<li>none</li>";
8410
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml10(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>${escapeHtml10(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml10(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml10(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>${escapeHtml10(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>`;
8330
8411
  };
8331
8412
  var renderVoiceScenarioEvalHTML = (report, options = {}) => {
8332
8413
  const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
8333
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml9(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
8414
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml10(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</nav>` : "";
8334
8415
  const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
8335
- const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml9(issue)}</li>`).join("")}</ul>` : "";
8336
- const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml9(session.sessionId)}</td><td>${escapeHtml9(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml9(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
8337
- return `<section class="scenario ${scenario.status}"><h2>${escapeHtml9(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml9(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>`;
8416
+ const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml10(issue)}</li>`).join("")}</ul>` : "";
8417
+ const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml10(session.sessionId)}</td><td>${escapeHtml10(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml10(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
8418
+ return `<section class="scenario ${scenario.status}"><h2>${escapeHtml10(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml10(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>`;
8338
8419
  }).join("") : "<section><p>No scenarios configured.</p></section>";
8339
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml9(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>${escapeHtml9(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>`;
8420
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml10(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>${escapeHtml10(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>`;
8340
8421
  };
8341
8422
  var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
8342
8423
  const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
8343
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml9(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
8424
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml10(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</nav>` : "";
8344
8425
  const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
8345
- const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml9(scenario.label)}</td><td>${escapeHtml9(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml9([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
8346
- return `<section class="${fixture.status}"><h2>${escapeHtml9(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml9(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>`;
8426
+ const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml10(scenario.label)}</td><td>${escapeHtml10(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml10([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
8427
+ return `<section class="${fixture.status}"><h2>${escapeHtml10(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml10(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>`;
8347
8428
  }).join("") : "<section><p>No scenario fixtures configured.</p></section>";
8348
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml9(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>${escapeHtml9(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>`;
8429
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml10(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>${escapeHtml10(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>`;
8349
8430
  };
8350
8431
  var createVoiceEvalRoutes = (options) => {
8351
8432
  const path = options.path ?? "/evals";
8352
- const routes = new Elysia7({
8433
+ const routes = new Elysia8({
8353
8434
  name: options.name ?? "absolutejs-voice-evals"
8354
8435
  });
8355
8436
  const getReport = () => runVoiceSessionEvals({
@@ -8484,11 +8565,11 @@ var createVoiceEvalRoutes = (options) => {
8484
8565
  };
8485
8566
 
8486
8567
  // src/opsConsoleRoutes.ts
8487
- import { Elysia as Elysia10 } from "elysia";
8568
+ import { Elysia as Elysia11 } from "elysia";
8488
8569
 
8489
8570
  // src/resilienceRoutes.ts
8490
- import { Elysia as Elysia8 } from "elysia";
8491
- var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8571
+ import { Elysia as Elysia9 } from "elysia";
8572
+ var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8492
8573
  var getString7 = (value) => typeof value === "string" ? value : undefined;
8493
8574
  var getNumber4 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
8494
8575
  var getBoolean2 = (value) => value === true;
@@ -8635,13 +8716,13 @@ var summarizeRoutingEvents = (events) => {
8635
8716
  };
8636
8717
  var renderProviderCards = (title, providers) => {
8637
8718
  if (providers.length === 0) {
8638
- return `<p class="muted">No ${escapeHtml10(title)} provider health yet.</p>`;
8719
+ return `<p class="muted">No ${escapeHtml11(title)} provider health yet.</p>`;
8639
8720
  }
8640
8721
  return `<div class="provider-grid">${providers.map((provider) => `
8641
- <article class="card provider ${escapeHtml10(provider.status)}">
8722
+ <article class="card provider ${escapeHtml11(provider.status)}">
8642
8723
  <div class="card-header">
8643
- <strong>${escapeHtml10(provider.provider)}</strong>
8644
- <span>${escapeHtml10(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
8724
+ <strong>${escapeHtml11(provider.provider)}</strong>
8725
+ <span>${escapeHtml11(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
8645
8726
  </div>
8646
8727
  <dl>
8647
8728
  <div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
@@ -8650,7 +8731,7 @@ var renderProviderCards = (title, providers) => {
8650
8731
  <div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
8651
8732
  <div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
8652
8733
  </dl>
8653
- ${provider.lastError ? `<p class="muted">${escapeHtml10(provider.lastError)}</p>` : ""}
8734
+ ${provider.lastError ? `<p class="muted">${escapeHtml11(provider.lastError)}</p>` : ""}
8654
8735
  </article>
8655
8736
  `).join("")}</div>`;
8656
8737
  };
@@ -8659,24 +8740,24 @@ var renderTimeline2 = (events) => {
8659
8740
  return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
8660
8741
  }
8661
8742
  return `<div class="timeline">${events.slice(0, 40).map((event) => `
8662
- <article class="card event ${escapeHtml10(event.status ?? "unknown")}">
8743
+ <article class="card event ${escapeHtml11(event.status ?? "unknown")}">
8663
8744
  <div class="card-header">
8664
- <strong>${escapeHtml10(event.kind.toUpperCase())} ${escapeHtml10(event.operation ?? "generate")}</strong>
8745
+ <strong>${escapeHtml11(event.kind.toUpperCase())} ${escapeHtml11(event.operation ?? "generate")}</strong>
8665
8746
  <span>${new Date(event.at).toLocaleString()}</span>
8666
8747
  </div>
8667
8748
  <p>
8668
- <span class="pill">${escapeHtml10(event.status ?? "unknown")}</span>
8669
- <span class="pill">provider: ${escapeHtml10(event.provider ?? "unknown")}</span>
8670
- ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml10(event.fallbackProvider)}</span>` : ""}
8749
+ <span class="pill">${escapeHtml11(event.status ?? "unknown")}</span>
8750
+ <span class="pill">provider: ${escapeHtml11(event.provider ?? "unknown")}</span>
8751
+ ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml11(event.fallbackProvider)}</span>` : ""}
8671
8752
  ${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
8672
8753
  </p>
8673
8754
  <dl>
8674
8755
  <div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
8675
8756
  <div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
8676
8757
  <div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
8677
- <div><dt>Session</dt><dd>${escapeHtml10(event.sessionId)}</dd></div>
8758
+ <div><dt>Session</dt><dd>${escapeHtml11(event.sessionId)}</dd></div>
8678
8759
  </dl>
8679
- ${event.error ? `<p class="muted">${escapeHtml10(event.error)}</p>` : ""}
8760
+ ${event.error ? `<p class="muted">${escapeHtml11(event.error)}</p>` : ""}
8680
8761
  </article>
8681
8762
  `).join("")}</div>`;
8682
8763
  };
@@ -8686,9 +8767,9 @@ var renderSessionKind = (kind, summary) => {
8686
8767
  const status = latest?.status ?? "idle";
8687
8768
  const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
8688
8769
  return `<div>
8689
- <dt>${escapeHtml10(kind.toUpperCase())}</dt>
8690
- <dd>${escapeHtml10(provider)}${escapeHtml10(fallback)}</dd>
8691
- <small>${escapeHtml10(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>
8770
+ <dt>${escapeHtml11(kind.toUpperCase())}</dt>
8771
+ <dd>${escapeHtml11(provider)}${escapeHtml11(fallback)}</dd>
8772
+ <small>${escapeHtml11(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>
8692
8773
  </div>`;
8693
8774
  };
8694
8775
  var renderSessionSummaries = (sessions) => {
@@ -8696,10 +8777,10 @@ var renderSessionSummaries = (sessions) => {
8696
8777
  return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
8697
8778
  }
8698
8779
  return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
8699
- <article class="card session ${escapeHtml10(session.status)}">
8780
+ <article class="card session ${escapeHtml11(session.status)}">
8700
8781
  <div class="card-header">
8701
- <strong>${escapeHtml10(session.sessionId)}</strong>
8702
- <span>${escapeHtml10(session.status)}</span>
8782
+ <strong>${escapeHtml11(session.sessionId)}</strong>
8783
+ <span>${escapeHtml11(session.status)}</span>
8703
8784
  </div>
8704
8785
  <p>
8705
8786
  <span class="pill">${session.eventCount} routing events</span>
@@ -8726,26 +8807,26 @@ var renderSimulationControls = (kind, simulation) => {
8726
8807
  const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
8727
8808
  const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
8728
8809
  const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
8729
- return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml10(pathPrefix)}">
8730
- <p class="muted">${escapeHtml10(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
8810
+ return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml11(pathPrefix)}">
8811
+ <p class="muted">${escapeHtml11(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
8731
8812
  <div class="simulate-actions">
8732
- ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml10(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml10(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
8733
- ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml10(provider.provider)}">Mark ${escapeHtml10(provider.provider)} recovered</button>`).join("")}
8813
+ ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml11(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml11(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
8814
+ ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml11(provider.provider)}">Mark ${escapeHtml11(provider.provider)} recovered</button>`).join("")}
8734
8815
  </div>
8735
- ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml10(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
8816
+ ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml11(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
8736
8817
  <pre class="simulate-output" hidden></pre>
8737
8818
  </div>`;
8738
8819
  };
8739
8820
  var renderVoiceResilienceHTML = (input) => {
8740
8821
  const summary = summarizeRoutingEvents(input.routingEvents);
8741
- const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml10(kind)}: ${String(count)}</span>`).join("");
8742
- const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml10(link.href)}">${escapeHtml10(link.label)}</a>`).join(" \xB7 ") : "";
8822
+ const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml11(kind)}: ${String(count)}</span>`).join("");
8823
+ const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml11(link.href)}">${escapeHtml11(link.label)}</a>`).join(" \xB7 ") : "";
8743
8824
  return `<!doctype html>
8744
8825
  <html lang="en">
8745
8826
  <head>
8746
8827
  <meta charset="utf-8" />
8747
8828
  <meta name="viewport" content="width=device-width, initial-scale=1" />
8748
- <title>${escapeHtml10(input.title ?? "AbsoluteJS Voice Resilience")}</title>
8829
+ <title>${escapeHtml11(input.title ?? "AbsoluteJS Voice Resilience")}</title>
8749
8830
  <style>
8750
8831
  :root { color-scheme: dark; }
8751
8832
  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; }
@@ -8888,7 +8969,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
8888
8969
  };
8889
8970
  var createVoiceResilienceRoutes = (options) => {
8890
8971
  const path = options.path ?? "/resilience";
8891
- const routes = new Elysia8({
8972
+ const routes = new Elysia9({
8892
8973
  name: options.name ?? "absolutejs-voice-resilience"
8893
8974
  }).get(path, async () => {
8894
8975
  const events = await options.store.list();
@@ -8929,9 +9010,9 @@ var createVoiceResilienceRoutes = (options) => {
8929
9010
  };
8930
9011
 
8931
9012
  // src/sessionReplay.ts
8932
- import { Elysia as Elysia9 } from "elysia";
9013
+ import { Elysia as Elysia10 } from "elysia";
8933
9014
  var getString8 = (value) => typeof value === "string" ? value : undefined;
8934
- var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9015
+ var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8935
9016
  var increment3 = (record, key) => {
8936
9017
  record[key] = (record[key] ?? 0) + 1;
8937
9018
  };
@@ -9090,10 +9171,10 @@ var summarizeVoiceSessions = async (options = {}) => {
9090
9171
  var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
9091
9172
  '<div class="voice-sessions-list">',
9092
9173
  ...sessions.map((session) => [
9093
- `<article class="voice-session-card ${escapeHtml11(session.status)}">`,
9174
+ `<article class="voice-session-card ${escapeHtml12(session.status)}">`,
9094
9175
  '<div class="voice-session-card-header">',
9095
- `<strong>${escapeHtml11(session.sessionId)}</strong>`,
9096
- `<span>${escapeHtml11(session.status)}</span>`,
9176
+ `<strong>${escapeHtml12(session.sessionId)}</strong>`,
9177
+ `<span>${escapeHtml12(session.status)}</span>`,
9097
9178
  "</div>",
9098
9179
  "<dl>",
9099
9180
  `<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
@@ -9101,9 +9182,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
9101
9182
  `<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
9102
9183
  `<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
9103
9184
  "</dl>",
9104
- session.latestOutcome ? `<p>Outcome: ${escapeHtml11(session.latestOutcome)}</p>` : "",
9105
- session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml11).join(", ")}</p>` : "",
9106
- session.replayHref ? `<p><a href="${escapeHtml11(session.replayHref)}">Open replay</a></p>` : "",
9185
+ session.latestOutcome ? `<p>Outcome: ${escapeHtml12(session.latestOutcome)}</p>` : "",
9186
+ session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml12).join(", ")}</p>` : "",
9187
+ session.replayHref ? `<p><a href="${escapeHtml12(session.replayHref)}">Open replay</a></p>` : "",
9107
9188
  "</article>"
9108
9189
  ].join("")),
9109
9190
  "</div>"
@@ -9134,7 +9215,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
9134
9215
  var createVoiceSessionListRoutes = (options = {}) => {
9135
9216
  const path = options.path ?? "/api/voice-sessions";
9136
9217
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
9137
- const routes = new Elysia9({
9218
+ const routes = new Elysia10({
9138
9219
  name: options.name ?? "absolutejs-voice-session-list"
9139
9220
  }).get(path, createVoiceSessionsJSONHandler(options));
9140
9221
  if (htmlPath) {
@@ -9162,7 +9243,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
9162
9243
  var createVoiceSessionReplayRoutes = (options) => {
9163
9244
  const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
9164
9245
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
9165
- const routes = new Elysia9({
9246
+ const routes = new Elysia10({
9166
9247
  name: options.name ?? "absolutejs-voice-session-replay"
9167
9248
  }).get(path, createVoiceSessionReplayJSONHandler(options));
9168
9249
  if (htmlPath) {
@@ -9206,7 +9287,7 @@ var DEFAULT_LINKS = [
9206
9287
  label: "Handoffs"
9207
9288
  }
9208
9289
  ];
9209
- var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9290
+ var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9210
9291
  var countProviderStatuses = (providers) => {
9211
9292
  const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
9212
9293
  const healthy = providers.filter((provider) => provider.status === "healthy").length;
@@ -9262,20 +9343,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
9262
9343
  trace
9263
9344
  };
9264
9345
  };
9265
- var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml12(input.label)}</span><strong>${escapeHtml12(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml12(input.status)}">${escapeHtml12(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml12(input.href)}">Open</a>` : ""}</article>`;
9346
+ var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml13(input.label)}</span><strong>${escapeHtml13(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml13(input.status)}">${escapeHtml13(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml13(input.href)}">Open</a>` : ""}</article>`;
9266
9347
  var renderVoiceOpsConsoleHTML = (report, options = {}) => {
9267
9348
  const links = report.links.map((link) => `<article class="surface">
9268
- <div><h2>${escapeHtml12(link.label)}</h2>${link.description ? `<p>${escapeHtml12(link.description)}</p>` : ""}</div>
9269
- <p><a href="${escapeHtml12(link.href)}">Open ${escapeHtml12(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml12(link.statusHref)}">Status</a>` : ""}</p>
9349
+ <div><h2>${escapeHtml13(link.label)}</h2>${link.description ? `<p>${escapeHtml13(link.description)}</p>` : ""}</div>
9350
+ <p><a href="${escapeHtml13(link.href)}">Open ${escapeHtml13(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml13(link.statusHref)}">Status</a>` : ""}</p>
9270
9351
  </article>`).join("");
9271
- const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml12(session.sessionId)}</td><td>${escapeHtml12(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml12(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
9272
- const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml12(event.kind)}</td><td>${escapeHtml12(event.provider ?? "unknown")}</td><td>${escapeHtml12(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml12(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
9352
+ const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml13(session.sessionId)}</td><td>${escapeHtml13(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml13(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
9353
+ const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml13(event.kind)}</td><td>${escapeHtml13(event.provider ?? "unknown")}</td><td>${escapeHtml13(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml13(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
9273
9354
  const title = options.title ?? "AbsoluteJS Voice Ops Console";
9274
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml12(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>${escapeHtml12(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 ${escapeHtml12(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>`;
9355
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml13(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>${escapeHtml13(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 ${escapeHtml13(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>`;
9275
9356
  };
9276
9357
  var createVoiceOpsConsoleRoutes = (options) => {
9277
9358
  const path = options.path ?? "/ops-console";
9278
- const routes = new Elysia10({
9359
+ const routes = new Elysia11({
9279
9360
  name: options.name ?? "absolutejs-voice-ops-console"
9280
9361
  });
9281
9362
  const getReport = () => buildVoiceOpsConsoleReport(options);
@@ -9293,8 +9374,8 @@ var createVoiceOpsConsoleRoutes = (options) => {
9293
9374
  };
9294
9375
 
9295
9376
  // src/providerCapabilities.ts
9296
- import { Elysia as Elysia11 } from "elysia";
9297
- var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9377
+ import { Elysia as Elysia12 } from "elysia";
9378
+ var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9298
9379
  var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
9299
9380
  configured: true,
9300
9381
  features: options.features?.[provider],
@@ -9357,27 +9438,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
9357
9438
  var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
9358
9439
  const title = options.title ?? "Voice Provider Capabilities";
9359
9440
  const cards = report.capabilities.map((capability) => {
9360
- const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml13(feature)}</span>`).join("");
9361
- return `<article class="card ${escapeHtml13(capability.status)}">
9441
+ const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml14(feature)}</span>`).join("");
9442
+ return `<article class="card ${escapeHtml14(capability.status)}">
9362
9443
  <div class="card-header">
9363
9444
  <div>
9364
- <p class="eyebrow">${escapeHtml13(capability.kind)}</p>
9365
- <h2>${escapeHtml13(capability.label ?? capability.provider)}</h2>
9445
+ <p class="eyebrow">${escapeHtml14(capability.kind)}</p>
9446
+ <h2>${escapeHtml14(capability.label ?? capability.provider)}</h2>
9366
9447
  </div>
9367
- <strong>${escapeHtml13(capability.status)}</strong>
9448
+ <strong>${escapeHtml14(capability.status)}</strong>
9368
9449
  </div>
9369
- ${capability.description ? `<p>${escapeHtml13(capability.description)}</p>` : ""}
9450
+ ${capability.description ? `<p>${escapeHtml14(capability.description)}</p>` : ""}
9370
9451
  <dl>
9371
9452
  <div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
9372
9453
  <div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
9373
- <div><dt>Model</dt><dd>${escapeHtml13(capability.model ?? "default")}</dd></div>
9454
+ <div><dt>Model</dt><dd>${escapeHtml14(capability.model ?? "default")}</dd></div>
9374
9455
  <div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
9375
9456
  <div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
9376
9457
  </dl>
9377
9458
  ${features ? `<div class="features">${features}</div>` : ""}
9378
9459
  </article>`;
9379
9460
  }).join("");
9380
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml13(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>${escapeHtml13(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>`;
9461
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml14(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>${escapeHtml14(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>`;
9381
9462
  };
9382
9463
  var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
9383
9464
  var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
@@ -9394,7 +9475,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
9394
9475
  var createVoiceProviderCapabilityRoutes = (options) => {
9395
9476
  const path = options.path ?? "/api/provider-capabilities";
9396
9477
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
9397
- const routes = new Elysia11({
9478
+ const routes = new Elysia12({
9398
9479
  name: options.name ?? "absolutejs-voice-provider-capabilities"
9399
9480
  }).get(path, createVoiceProviderCapabilityJSONHandler(options));
9400
9481
  if (htmlPath) {
@@ -9404,10 +9485,10 @@ var createVoiceProviderCapabilityRoutes = (options) => {
9404
9485
  };
9405
9486
 
9406
9487
  // src/productionReadiness.ts
9407
- import { Elysia as Elysia13 } from "elysia";
9488
+ import { Elysia as Elysia14 } from "elysia";
9408
9489
 
9409
9490
  // src/telephony/matrix.ts
9410
- import { Elysia as Elysia12 } from "elysia";
9491
+ import { Elysia as Elysia13 } from "elysia";
9411
9492
 
9412
9493
  // src/telephony/contract.ts
9413
9494
  var DEFAULT_REQUIREMENTS = [
@@ -9490,7 +9571,7 @@ var evaluateVoiceTelephonyContract = (input) => {
9490
9571
  };
9491
9572
 
9492
9573
  // src/telephony/matrix.ts
9493
- var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
9574
+ var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
9494
9575
  var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
9495
9576
  var resolveEntryStatus = (contract, setup, smoke) => {
9496
9577
  if (!contract.pass || !setup.ready || smoke?.pass === false) {
@@ -9551,13 +9632,13 @@ var badgeStyles = {
9551
9632
  };
9552
9633
  var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
9553
9634
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
9554
- <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml14(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
9635
+ <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml15(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
9555
9636
  <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>
9556
9637
  <section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
9557
9638
  ${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);">
9558
9639
  <div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
9559
- <h2 style="margin:0; font-size:20px;">${escapeHtml14(entry.name)}</h2>
9560
- <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml14(entry.status.toUpperCase())}</span>
9640
+ <h2 style="margin:0; font-size:20px;">${escapeHtml15(entry.name)}</h2>
9641
+ <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml15(entry.status.toUpperCase())}</span>
9561
9642
  </div>
9562
9643
  <dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
9563
9644
  <dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
@@ -9565,15 +9646,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
9565
9646
  <dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
9566
9647
  <dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
9567
9648
  </dl>
9568
- <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml14(entry.setup.urls.stream || "missing")}</code></p>
9569
- <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml14(entry.setup.urls.webhook || "missing")}</code></p>
9570
- ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml14(issue.severity)}: ${escapeHtml14(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
9649
+ <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml15(entry.setup.urls.stream || "missing")}</code></p>
9650
+ <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml15(entry.setup.urls.webhook || "missing")}</code></p>
9651
+ ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml15(issue.severity)}: ${escapeHtml15(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
9571
9652
  </article>`).join("")}
9572
9653
  </section>
9573
9654
  </main>`;
9574
9655
  var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
9575
9656
  const path = options.path ?? "/api/voice/telephony/carriers";
9576
- return new Elysia12({
9657
+ return new Elysia13({
9577
9658
  name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
9578
9659
  }).get(path, async ({ query, request }) => {
9579
9660
  const providers = await options.load({ query, request });
@@ -9595,7 +9676,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
9595
9676
  };
9596
9677
 
9597
9678
  // src/productionReadiness.ts
9598
- var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9679
+ var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9599
9680
  var rollupStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
9600
9681
  var carrierStatus = (matrix) => matrix.summary.failing > 0 ? "fail" : matrix.summary.warnings > 0 || matrix.summary.ready < matrix.summary.providers ? "warn" : "pass";
9601
9682
  var resolveCarriers = async (options, input) => {
@@ -9782,24 +9863,24 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
9782
9863
  var renderVoiceProductionReadinessHTML = (report, options = {}) => {
9783
9864
  const title = options.title ?? "AbsoluteJS Voice Production Readiness";
9784
9865
  const checks = report.checks.map((check, index) => {
9785
- const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml15(action.href)}">${escapeHtml15(action.label)}</button>` : `<a href="${escapeHtml15(action.href)}">${escapeHtml15(action.label)}</a>`).join("");
9786
- return `<article class="check ${escapeHtml15(check.status)}">
9866
+ const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml16(action.href)}">${escapeHtml16(action.label)}</button>` : `<a href="${escapeHtml16(action.href)}">${escapeHtml16(action.label)}</a>`).join("");
9867
+ return `<article class="check ${escapeHtml16(check.status)}">
9787
9868
  <div>
9788
- <span>${escapeHtml15(check.status.toUpperCase())}</span>
9789
- <h2>${escapeHtml15(check.label)}</h2>
9790
- ${check.detail ? `<p>${escapeHtml15(check.detail)}</p>` : ""}
9869
+ <span>${escapeHtml16(check.status.toUpperCase())}</span>
9870
+ <h2>${escapeHtml16(check.label)}</h2>
9871
+ ${check.detail ? `<p>${escapeHtml16(check.detail)}</p>` : ""}
9791
9872
  ${actions ? `<p class="actions">${actions}</p>` : ""}
9792
9873
  </div>
9793
- <strong>${escapeHtml15(String(check.value ?? check.status))}</strong>
9794
- ${check.href ? `<a href="${escapeHtml15(check.href)}">Open surface</a>` : ""}
9874
+ <strong>${escapeHtml16(String(check.value ?? check.status))}</strong>
9875
+ ${check.href ? `<a href="${escapeHtml16(check.href)}">Open surface</a>` : ""}
9795
9876
  </article>`;
9796
9877
  }).join("");
9797
- 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:#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 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>${escapeHtml15(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 ${escapeHtml15(report.status)}">Overall: ${escapeHtml15(report.status.toUpperCase())}</p><p>Checked ${escapeHtml15(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>`;
9878
+ 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:#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 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>${escapeHtml16(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 ${escapeHtml16(report.status)}">Overall: ${escapeHtml16(report.status.toUpperCase())}</p><p>Checked ${escapeHtml16(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>`;
9798
9879
  };
9799
9880
  var createVoiceProductionReadinessRoutes = (options) => {
9800
9881
  const path = options.path ?? "/api/production-readiness";
9801
9882
  const htmlPath = options.htmlPath ?? "/production-readiness";
9802
- const routes = new Elysia13({
9883
+ const routes = new Elysia14({
9803
9884
  name: options.name ?? "absolutejs-voice-production-readiness"
9804
9885
  });
9805
9886
  routes.get(path, async ({ query, request }) => buildVoiceProductionReadinessReport(options, { query, request }));
@@ -9822,8 +9903,8 @@ var createVoiceProductionReadinessRoutes = (options) => {
9822
9903
  };
9823
9904
 
9824
9905
  // src/traceTimeline.ts
9825
- import { Elysia as Elysia14 } from "elysia";
9826
- var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9906
+ import { Elysia as Elysia15 } from "elysia";
9907
+ var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9827
9908
  var getString9 = (value) => typeof value === "string" && value.trim() ? value : undefined;
9828
9909
  var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
9829
9910
  var firstString = (payload, keys) => {
@@ -9987,20 +10068,20 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
9987
10068
  };
9988
10069
  };
9989
10070
  var formatMs = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
9990
- 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>${escapeHtml16(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
10071
+ 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>${escapeHtml17(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
9991
10072
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
9992
- const events = session.events.map((event) => `<tr class="${escapeHtml16(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml16(event.type)}</td><td>${escapeHtml16(event.label)}</td><td>${escapeHtml16(event.provider ?? "")}</td><td>${escapeHtml16(event.status ?? "")}</td><td>${formatMs(event.elapsedMs)}</td></tr>`).join("");
9993
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml16(issue.severity)}">${escapeHtml16(issue.code)}: ${escapeHtml16(issue.message)}</li>`).join("") : "<li>none</li>";
9994
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(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>${escapeHtml16(session.sessionId)}</h1><p class="status ${escapeHtml16(session.status)}">${escapeHtml16(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>${formatMs(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>`;
10073
+ const events = session.events.map((event) => `<tr class="${escapeHtml17(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml17(event.type)}</td><td>${escapeHtml17(event.label)}</td><td>${escapeHtml17(event.provider ?? "")}</td><td>${escapeHtml17(event.status ?? "")}</td><td>${formatMs(event.elapsedMs)}</td></tr>`).join("");
10074
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml17(issue.severity)}">${escapeHtml17(issue.code)}: ${escapeHtml17(issue.message)}</li>`).join("") : "<li>none</li>";
10075
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(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>${escapeHtml17(session.sessionId)}</h1><p class="status ${escapeHtml17(session.status)}">${escapeHtml17(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>${formatMs(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>`;
9995
10076
  };
9996
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml16(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml16(session.sessionId)}</a></td><td>${escapeHtml16(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml16(provider.provider)).join(", ")}</td></tr>`).join("");
10077
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml17(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml17(session.sessionId)}</a></td><td>${escapeHtml17(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml17(provider.provider)).join(", ")}</td></tr>`).join("");
9997
10078
  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}}";
9998
- 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>${escapeHtml16(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml16(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>`;
10079
+ 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>${escapeHtml17(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml17(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>`;
9999
10080
  var createVoiceTraceTimelineRoutes = (options) => {
10000
10081
  const path = options.path ?? "/api/voice-traces";
10001
10082
  const htmlPath = options.htmlPath ?? "/traces";
10002
10083
  const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
10003
- const routes = new Elysia14({
10084
+ const routes = new Elysia15({
10004
10085
  name: options.name ?? "absolutejs-voice-trace-timelines"
10005
10086
  });
10006
10087
  const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
@@ -10209,7 +10290,7 @@ var summarizeVoiceAppKitStatus = async (options) => {
10209
10290
  };
10210
10291
  };
10211
10292
  var createVoiceAppKitRoutes = (options) => {
10212
- const routes = new Elysia15({
10293
+ const routes = new Elysia16({
10213
10294
  name: options.name ?? "absolutejs-voice-app-kit"
10214
10295
  });
10215
10296
  const links = resolveLinks(options.links);
@@ -10304,6 +10385,16 @@ var createVoiceAppKitRoutes = (options) => {
10304
10385
  ...options.diagnostics
10305
10386
  }));
10306
10387
  }
10388
+ if (options.bargeIn !== false) {
10389
+ surfaces.push("bargeIn");
10390
+ routes.use(createVoiceBargeInRoutes({
10391
+ ...common,
10392
+ htmlPath: "/barge-in",
10393
+ path: "/api/voice-barge-in",
10394
+ title: options.title ? `${options.title} Barge-In` : undefined,
10395
+ ...options.bargeIn
10396
+ }));
10397
+ }
10307
10398
  if (options.traceTimeline !== false) {
10308
10399
  surfaces.push("traceTimeline");
10309
10400
  routes.use(createVoiceTraceTimelineRoutes({
@@ -10854,7 +10945,7 @@ var createVoiceToolIdempotencyKey = (input) => {
10854
10945
  ].join(":");
10855
10946
  };
10856
10947
  // src/toolContract.ts
10857
- import { Elysia as Elysia16 } from "elysia";
10948
+ import { Elysia as Elysia17 } from "elysia";
10858
10949
  var createDefaultSession = (contractId, caseId) => createVoiceSessionRecord(`tool-contract-${contractId}-${caseId}`);
10859
10950
  var createDefaultTurn = (caseId) => ({
10860
10951
  committedAt: Date.now(),
@@ -10864,7 +10955,7 @@ var createDefaultTurn = (caseId) => ({
10864
10955
  });
10865
10956
  var defaultApi = {};
10866
10957
  var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
10867
- var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10958
+ var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10868
10959
  var evaluateExpectation = (input) => {
10869
10960
  const issues = [];
10870
10961
  const expect = input.expect;
@@ -11030,19 +11121,19 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
11030
11121
  const title = options.title ?? "Voice Tool Contracts";
11031
11122
  const contracts = report.contracts.map((contract) => {
11032
11123
  const cases = contract.cases.map((testCase) => `<tr>
11033
- <td>${escapeHtml17(testCase.label ?? testCase.caseId)}</td>
11124
+ <td>${escapeHtml18(testCase.label ?? testCase.caseId)}</td>
11034
11125
  <td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
11035
- <td>${escapeHtml17(testCase.status)}</td>
11126
+ <td>${escapeHtml18(testCase.status)}</td>
11036
11127
  <td>${String(testCase.attempts)}</td>
11037
11128
  <td>${String(testCase.elapsedMs)}ms</td>
11038
11129
  <td>${testCase.timedOut ? "yes" : "no"}</td>
11039
- <td>${escapeHtml17(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
11130
+ <td>${escapeHtml18(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
11040
11131
  </tr>`).join("");
11041
11132
  return `<section class="contract ${contract.pass ? "pass" : "fail"}">
11042
11133
  <div class="contract-header">
11043
11134
  <div>
11044
- <p class="eyebrow">${escapeHtml17(contract.toolName)}</p>
11045
- <h2>${escapeHtml17(contract.label ?? contract.contractId)}</h2>
11135
+ <p class="eyebrow">${escapeHtml18(contract.toolName)}</p>
11136
+ <h2>${escapeHtml18(contract.label ?? contract.contractId)}</h2>
11046
11137
  </div>
11047
11138
  <strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
11048
11139
  </div>
@@ -11052,7 +11143,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
11052
11143
  </table>
11053
11144
  </section>`;
11054
11145
  }).join("");
11055
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(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>${escapeHtml17(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml17(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>`;
11146
+ 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{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>${escapeHtml18(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml18(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>`;
11056
11147
  };
11057
11148
  var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
11058
11149
  var createVoiceToolContractHTMLHandler = (options) => async () => {
@@ -11069,7 +11160,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
11069
11160
  var createVoiceToolContractRoutes = (options) => {
11070
11161
  const path = options.path ?? "/api/tool-contracts";
11071
11162
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
11072
- const routes = new Elysia16({
11163
+ const routes = new Elysia17({
11073
11164
  name: options.name ?? "absolutejs-voice-tool-contracts"
11074
11165
  }).get(path, createVoiceToolContractJSONHandler(options));
11075
11166
  if (htmlPath) {
@@ -11078,9 +11169,9 @@ var createVoiceToolContractRoutes = (options) => {
11078
11169
  return routes;
11079
11170
  };
11080
11171
  // src/turnQuality.ts
11081
- import { Elysia as Elysia17 } from "elysia";
11172
+ import { Elysia as Elysia18 } from "elysia";
11082
11173
  var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
11083
- var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11174
+ var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11084
11175
  var getTurnLatencyMs = (turn) => {
11085
11176
  const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
11086
11177
  if (firstTranscriptAt === undefined) {
@@ -11151,24 +11242,24 @@ var summarizeVoiceTurnQuality = async (options) => {
11151
11242
  };
11152
11243
  var renderVoiceTurnQualityHTML = (report, options = {}) => {
11153
11244
  const title = options.title ?? "Voice Turn Quality";
11154
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml18(turn.status)}">
11245
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml19(turn.status)}">
11155
11246
  <div class="turn-header">
11156
11247
  <div>
11157
- <p class="eyebrow">${escapeHtml18(turn.sessionId)} \xB7 ${escapeHtml18(turn.turnId)}</p>
11158
- <h2>${escapeHtml18(turn.text || "Empty turn")}</h2>
11248
+ <p class="eyebrow">${escapeHtml19(turn.sessionId)} \xB7 ${escapeHtml19(turn.turnId)}</p>
11249
+ <h2>${escapeHtml19(turn.text || "Empty turn")}</h2>
11159
11250
  </div>
11160
- <strong>${escapeHtml18(turn.status)}</strong>
11251
+ <strong>${escapeHtml19(turn.status)}</strong>
11161
11252
  </div>
11162
11253
  <dl>
11163
- <div><dt>Source</dt><dd>${escapeHtml18(turn.source ?? "unknown")}</dd></div>
11254
+ <div><dt>Source</dt><dd>${escapeHtml19(turn.source ?? "unknown")}</dd></div>
11164
11255
  <div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
11165
- <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml18(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
11166
- <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml18(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
11256
+ <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml19(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
11257
+ <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml19(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
11167
11258
  <div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
11168
11259
  <div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
11169
11260
  </dl>
11170
11261
  </article>`).join("");
11171
- 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{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>${escapeHtml18(title)}</h1><div class="summary"><span class="pill ${escapeHtml18(report.status)}">${escapeHtml18(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>`;
11262
+ 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,.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>${escapeHtml19(title)}</h1><div class="summary"><span class="pill ${escapeHtml19(report.status)}">${escapeHtml19(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>`;
11172
11263
  };
11173
11264
  var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
11174
11265
  var createVoiceTurnQualityHTMLHandler = (options) => async () => {
@@ -11185,7 +11276,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
11185
11276
  var createVoiceTurnQualityRoutes = (options) => {
11186
11277
  const path = options.path ?? "/api/turn-quality";
11187
11278
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
11188
- const routes = new Elysia17({
11279
+ const routes = new Elysia18({
11189
11280
  name: options.name ?? "absolutejs-voice-turn-quality"
11190
11281
  }).get(path, createVoiceTurnQualityJSONHandler(options));
11191
11282
  if (htmlPath) {
@@ -11194,8 +11285,8 @@ var createVoiceTurnQualityRoutes = (options) => {
11194
11285
  return routes;
11195
11286
  };
11196
11287
  // src/outcomeContract.ts
11197
- import { Elysia as Elysia18 } from "elysia";
11198
- var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11288
+ import { Elysia as Elysia19 } from "elysia";
11289
+ var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11199
11290
  var getPayloadString = (event, key) => typeof event.payload[key] === "string" ? event.payload[key] : undefined;
11200
11291
  var toList = async (input) => Array.isArray(input) ? input : await input?.list() ?? [];
11201
11292
  var hydrateSessions = async (input) => {
@@ -11303,9 +11394,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
11303
11394
  const contracts = report.contracts.map((contract) => `<section class="contract ${contract.pass ? "pass" : "fail"}">
11304
11395
  <div class="contract-header">
11305
11396
  <div>
11306
- <p class="eyebrow">${escapeHtml19(contract.contractId)}</p>
11307
- <h2>${escapeHtml19(contract.label ?? contract.contractId)}</h2>
11308
- ${contract.description ? `<p>${escapeHtml19(contract.description)}</p>` : ""}
11397
+ <p class="eyebrow">${escapeHtml20(contract.contractId)}</p>
11398
+ <h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
11399
+ ${contract.description ? `<p>${escapeHtml20(contract.description)}</p>` : ""}
11309
11400
  </div>
11310
11401
  <strong>${contract.pass ? "pass" : "fail"}</strong>
11311
11402
  </div>
@@ -11316,9 +11407,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
11316
11407
  <span>handoffs ${String(contract.matched.handoffs)}</span>
11317
11408
  <span>events ${String(contract.matched.integrationEvents)}</span>
11318
11409
  </div>
11319
- ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml19(issue.message)}</li>`).join("")}</ul>` : ""}
11410
+ ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml20(issue.message)}</li>`).join("")}</ul>` : ""}
11320
11411
  </section>`).join("");
11321
- 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>`;
11412
+ 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>`;
11322
11413
  };
11323
11414
  var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
11324
11415
  var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
@@ -11334,7 +11425,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
11334
11425
  var createVoiceOutcomeContractRoutes = (options) => {
11335
11426
  const path = options.path ?? "/api/outcome-contracts";
11336
11427
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
11337
- const routes = new Elysia18({
11428
+ const routes = new Elysia19({
11338
11429
  name: options.name ?? "absolutejs-voice-outcome-contracts"
11339
11430
  }).get(path, createVoiceOutcomeContractJSONHandler(options));
11340
11431
  if (htmlPath) {
@@ -11343,7 +11434,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
11343
11434
  return routes;
11344
11435
  };
11345
11436
  // src/telephonyOutcome.ts
11346
- import { Elysia as Elysia19 } from "elysia";
11437
+ import { Elysia as Elysia20 } from "elysia";
11347
11438
  var DEFAULT_COMPLETED_STATUSES = [
11348
11439
  "answered",
11349
11440
  "completed",
@@ -11990,7 +12081,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
11990
12081
  var createVoiceTelephonyWebhookRoutes = (options = {}) => {
11991
12082
  const path = options.path ?? "/api/voice/telephony/webhook";
11992
12083
  const handler = createVoiceTelephonyWebhookHandler(options);
11993
- return new Elysia19({
12084
+ return new Elysia20({
11994
12085
  name: options.name ?? "absolutejs-voice-telephony-webhooks"
11995
12086
  }).post(path, async ({ query, request }) => {
11996
12087
  try {
@@ -14258,7 +14349,7 @@ var createVoiceMemoryStore = () => {
14258
14349
  return { get, getOrCreate, list, remove, set };
14259
14350
  };
14260
14351
  // src/opsWebhook.ts
14261
- import { Elysia as Elysia20 } from "elysia";
14352
+ import { Elysia as Elysia21 } from "elysia";
14262
14353
  var toHex5 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
14263
14354
  var signVoiceOpsWebhookBody = async (input) => {
14264
14355
  const encoder = new TextEncoder;
@@ -14388,7 +14479,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
14388
14479
  };
14389
14480
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
14390
14481
  const path = options.path ?? "/api/voice-ops/webhook";
14391
- return new Elysia20().post(path, async ({ body, request, set }) => {
14482
+ return new Elysia21().post(path, async ({ body, request, set }) => {
14392
14483
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
14393
14484
  if (options.signingSecret) {
14394
14485
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -16117,7 +16208,7 @@ var createVoiceSTTRoutingCorrectionHandler = (mode = "generic") => {
16117
16208
  };
16118
16209
  // src/telephony/twilio.ts
16119
16210
  import { Buffer as Buffer3 } from "buffer";
16120
- import { Elysia as Elysia21 } from "elysia";
16211
+ import { Elysia as Elysia22 } from "elysia";
16121
16212
  var TWILIO_MULAW_SAMPLE_RATE = 8000;
16122
16213
  var VOICE_PCM_SAMPLE_RATE = 16000;
16123
16214
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
@@ -16147,7 +16238,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
16147
16238
  return parameters;
16148
16239
  };
16149
16240
  var joinUrlPath = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16150
- var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16241
+ var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16151
16242
  var getWebhookVerificationUrl = (webhook, input) => {
16152
16243
  if (!webhook?.verificationUrl) {
16153
16244
  return;
@@ -16190,23 +16281,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
16190
16281
  };
16191
16282
  var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16192
16283
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
16193
- <h1>${escapeHtml20(title)}</h1>
16284
+ <h1>${escapeHtml21(title)}</h1>
16194
16285
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
16195
16286
  <section>
16196
16287
  <h2>URLs</h2>
16197
16288
  <ul>
16198
- <li><strong>TwiML:</strong> <code>${escapeHtml20(status.urls.twiml)}</code></li>
16199
- <li><strong>Media stream:</strong> <code>${escapeHtml20(status.urls.stream)}</code></li>
16200
- <li><strong>Status webhook:</strong> <code>${escapeHtml20(status.urls.webhook)}</code></li>
16289
+ <li><strong>TwiML:</strong> <code>${escapeHtml21(status.urls.twiml)}</code></li>
16290
+ <li><strong>Media stream:</strong> <code>${escapeHtml21(status.urls.stream)}</code></li>
16291
+ <li><strong>Status webhook:</strong> <code>${escapeHtml21(status.urls.webhook)}</code></li>
16201
16292
  </ul>
16202
16293
  </section>
16203
16294
  <section>
16204
16295
  <h2>Signing</h2>
16205
16296
  <p>Mode: <code>${status.signing.mode}</code></p>
16206
- ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml20(status.signing.verificationUrl)}</code></p>` : ""}
16297
+ ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml21(status.signing.verificationUrl)}</code></p>` : ""}
16207
16298
  </section>
16208
- ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml20(name)}</code></li>`).join("")}</ul></section>` : ""}
16209
- ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml20(warning)}</li>`).join("")}</ul></section>` : ""}
16299
+ ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml21(name)}</code></li>`).join("")}</ul></section>` : ""}
16300
+ ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml21(warning)}</li>`).join("")}</ul></section>` : ""}
16210
16301
  </main>`;
16211
16302
  var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&amp;", "&");
16212
16303
  var createSmokeCheck = (name, status, message, details) => ({
@@ -16217,20 +16308,20 @@ var createSmokeCheck = (name, status, message, details) => ({
16217
16308
  });
16218
16309
  var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16219
16310
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
16220
- <h1>${escapeHtml20(title)}</h1>
16311
+ <h1>${escapeHtml21(title)}</h1>
16221
16312
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
16222
16313
  <section>
16223
16314
  <h2>Checks</h2>
16224
16315
  <ul>
16225
- ${report.checks.map((check) => `<li><strong>${escapeHtml20(check.name)}</strong>: ${escapeHtml20(check.status)}${check.message ? ` - ${escapeHtml20(check.message)}` : ""}</li>`).join("")}
16316
+ ${report.checks.map((check) => `<li><strong>${escapeHtml21(check.name)}</strong>: ${escapeHtml21(check.status)}${check.message ? ` - ${escapeHtml21(check.message)}` : ""}</li>`).join("")}
16226
16317
  </ul>
16227
16318
  </section>
16228
16319
  <section>
16229
16320
  <h2>Observed URLs</h2>
16230
16321
  <ul>
16231
- <li><strong>TwiML:</strong> <code>${escapeHtml20(report.setup.urls.twiml)}</code></li>
16232
- <li><strong>Stream:</strong> <code>${escapeHtml20(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
16233
- <li><strong>Webhook:</strong> <code>${escapeHtml20(report.setup.urls.webhook)}</code></li>
16322
+ <li><strong>TwiML:</strong> <code>${escapeHtml21(report.setup.urls.twiml)}</code></li>
16323
+ <li><strong>Stream:</strong> <code>${escapeHtml21(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
16324
+ <li><strong>Webhook:</strong> <code>${escapeHtml21(report.setup.urls.webhook)}</code></li>
16234
16325
  </ul>
16235
16326
  </section>
16236
16327
  </main>`;
@@ -16690,7 +16781,7 @@ var createTwilioVoiceRoutes = (options) => {
16690
16781
  const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
16691
16782
  const bridges = new WeakMap;
16692
16783
  const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
16693
- const app = new Elysia21({
16784
+ const app = new Elysia22({
16694
16785
  name: options.name ?? "absolutejs-voice-twilio"
16695
16786
  }).get(twimlPath, async ({ query, request }) => {
16696
16787
  const streamUrl = await resolveTwilioStreamUrl(options, {
@@ -16826,9 +16917,9 @@ var createTwilioVoiceRoutes = (options) => {
16826
16917
  };
16827
16918
  // src/telephony/telnyx.ts
16828
16919
  import { Buffer as Buffer4 } from "buffer";
16829
- import { Elysia as Elysia22 } from "elysia";
16920
+ import { Elysia as Elysia23 } from "elysia";
16830
16921
  var escapeXml3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16831
- var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16922
+ var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16832
16923
  var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16833
16924
  var resolveRequestOrigin2 = (request) => {
16834
16925
  const url = new URL(request.url);
@@ -17029,21 +17120,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
17029
17120
  };
17030
17121
  var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
17031
17122
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
17032
- <h1>${escapeHtml21(title)}</h1>
17123
+ <h1>${escapeHtml22(title)}</h1>
17033
17124
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
17034
17125
  <ul>
17035
- <li><strong>TeXML:</strong> <code>${escapeHtml21(status.urls.texml)}</code></li>
17036
- <li><strong>Media stream:</strong> <code>${escapeHtml21(status.urls.stream)}</code></li>
17037
- <li><strong>Status webhook:</strong> <code>${escapeHtml21(status.urls.webhook)}</code></li>
17126
+ <li><strong>TeXML:</strong> <code>${escapeHtml22(status.urls.texml)}</code></li>
17127
+ <li><strong>Media stream:</strong> <code>${escapeHtml22(status.urls.stream)}</code></li>
17128
+ <li><strong>Status webhook:</strong> <code>${escapeHtml22(status.urls.webhook)}</code></li>
17038
17129
  </ul>
17039
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml21(name)}</code></li>`).join("")}</ul>` : ""}
17040
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml21(warning)}</li>`).join("")}</ul>` : ""}
17130
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml22(name)}</code></li>`).join("")}</ul>` : ""}
17131
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml22(warning)}</li>`).join("")}</ul>` : ""}
17041
17132
  </main>`;
17042
17133
  var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
17043
17134
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
17044
- <h1>${escapeHtml21(title)}</h1>
17135
+ <h1>${escapeHtml22(title)}</h1>
17045
17136
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
17046
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml21(check.name)}</strong>: ${escapeHtml21(check.status)}${check.message ? ` - ${escapeHtml21(check.message)}` : ""}</li>`).join("")}</ul>
17137
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml22(check.name)}</strong>: ${escapeHtml22(check.status)}${check.message ? ` - ${escapeHtml22(check.message)}` : ""}</li>`).join("")}</ul>
17047
17138
  </main>`;
17048
17139
  var runTelnyxSmokeTest = async (input) => {
17049
17140
  const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
@@ -17137,7 +17228,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
17137
17228
  publicKey: options.webhook?.publicKey,
17138
17229
  toleranceSeconds: options.webhook?.toleranceSeconds
17139
17230
  }) : undefined);
17140
- const app = new Elysia22({
17231
+ const app = new Elysia23({
17141
17232
  name: options.name ?? "absolutejs-voice-telnyx"
17142
17233
  }).get(texmlPath, async ({ query, request }) => {
17143
17234
  const streamUrl = await resolveTelnyxStreamUrl(options, {
@@ -17247,9 +17338,9 @@ var createTelnyxVoiceRoutes = (options = {}) => {
17247
17338
  };
17248
17339
  // src/telephony/plivo.ts
17249
17340
  import { Buffer as Buffer5 } from "buffer";
17250
- import { Elysia as Elysia23 } from "elysia";
17341
+ import { Elysia as Elysia24 } from "elysia";
17251
17342
  var escapeXml4 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17252
- var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17343
+ var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17253
17344
  var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
17254
17345
  var resolveRequestOrigin3 = (request) => {
17255
17346
  const url = new URL(request.url);
@@ -17500,21 +17591,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
17500
17591
  };
17501
17592
  var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
17502
17593
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
17503
- <h1>${escapeHtml22(title)}</h1>
17594
+ <h1>${escapeHtml23(title)}</h1>
17504
17595
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
17505
17596
  <ul>
17506
- <li><strong>Answer XML:</strong> <code>${escapeHtml22(status.urls.answer)}</code></li>
17507
- <li><strong>Audio stream:</strong> <code>${escapeHtml22(status.urls.stream)}</code></li>
17508
- <li><strong>Status webhook:</strong> <code>${escapeHtml22(status.urls.webhook)}</code></li>
17597
+ <li><strong>Answer XML:</strong> <code>${escapeHtml23(status.urls.answer)}</code></li>
17598
+ <li><strong>Audio stream:</strong> <code>${escapeHtml23(status.urls.stream)}</code></li>
17599
+ <li><strong>Status webhook:</strong> <code>${escapeHtml23(status.urls.webhook)}</code></li>
17509
17600
  </ul>
17510
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml22(name)}</code></li>`).join("")}</ul>` : ""}
17511
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml22(warning)}</li>`).join("")}</ul>` : ""}
17601
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml23(name)}</code></li>`).join("")}</ul>` : ""}
17602
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml23(warning)}</li>`).join("")}</ul>` : ""}
17512
17603
  </main>`;
17513
17604
  var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
17514
17605
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
17515
- <h1>${escapeHtml22(title)}</h1>
17606
+ <h1>${escapeHtml23(title)}</h1>
17516
17607
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
17517
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml22(check.name)}</strong>: ${escapeHtml22(check.status)}${check.message ? ` - ${escapeHtml22(check.message)}` : ""}</li>`).join("")}</ul>
17608
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml23(check.name)}</strong>: ${escapeHtml23(check.status)}${check.message ? ` - ${escapeHtml23(check.message)}` : ""}</li>`).join("")}</ul>
17518
17609
  </main>`;
17519
17610
  var runPlivoSmokeTest = async (input) => {
17520
17611
  const setup = await buildPlivoVoiceSetupStatus(input.options, input);
@@ -17609,7 +17700,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
17609
17700
  request: input.request
17610
17701
  }) : verificationUrl ?? input.request.url
17611
17702
  }) : undefined);
17612
- const app = new Elysia23({
17703
+ const app = new Elysia24({
17613
17704
  name: options.name ?? "absolutejs-voice-plivo"
17614
17705
  }).get(answerPath, async ({ query, request }) => {
17615
17706
  const streamUrl = await resolvePlivoStreamUrl(options, {
@@ -17797,6 +17888,7 @@ export {
17797
17888
  summarizeVoiceIntegrationEvents,
17798
17889
  summarizeVoiceHandoffHealth,
17799
17890
  summarizeVoiceHandoffDeliveries,
17891
+ summarizeVoiceBargeIn,
17800
17892
  summarizeVoiceAssistantRuns,
17801
17893
  summarizeVoiceAssistantHealth,
17802
17894
  summarizeVoiceAppKitStatus,
@@ -17849,6 +17941,7 @@ export {
17849
17941
  renderVoiceEvalBaselineHTML,
17850
17942
  renderVoiceCallReviewMarkdown,
17851
17943
  renderVoiceCallReviewHTML,
17944
+ renderVoiceBargeInHTML,
17852
17945
  renderVoiceAssistantHealthHTML,
17853
17946
  redactVoiceTraceText,
17854
17947
  redactVoiceTraceEvents,
@@ -18015,6 +18108,7 @@ export {
18015
18108
  createVoiceCallReviewFromLiveTelephonyReport,
18016
18109
  createVoiceCallCompletedEvent,
18017
18110
  createVoiceCRMActivitySink,
18111
+ createVoiceBargeInRoutes,
18018
18112
  createVoiceAssistantMemoryRecord,
18019
18113
  createVoiceAssistantMemoryHandle,
18020
18114
  createVoiceAssistantHealthRoutes,