@absolutejs/voice 0.0.22-beta.527 → 0.0.22-beta.529

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/angular/index.js +3 -1
  2. package/dist/client/htmxBootstrap.js +3 -1
  3. package/dist/client/index.js +290 -304
  4. package/dist/embed/index.js +3 -1
  5. package/dist/embed/voice-widget.js +7 -7
  6. package/dist/index.d.ts +4 -6
  7. package/dist/index.js +525 -905
  8. package/dist/internal/html.d.ts +6 -0
  9. package/dist/internal/status.d.ts +9 -0
  10. package/dist/react/index.js +287 -300
  11. package/dist/svelte/index.js +181 -198
  12. package/dist/testing/index.js +69 -69
  13. package/dist/vue/index.d.ts +1 -1
  14. package/dist/vue/index.js +231 -239
  15. package/package.json +2 -3
  16. package/dist/generated/htmxBootstrapBundle.d.ts +0 -1
  17. package/fixtures/README.md +0 -57
  18. package/fixtures/manifest.json +0 -358
  19. package/fixtures/pcm/dialogue-three-clean.pcm +0 -0
  20. package/fixtures/pcm/dialogue-three-mixed.pcm +0 -0
  21. package/fixtures/pcm/dialogue-two-clean.pcm +0 -0
  22. package/fixtures/pcm/dialogue-two-noisy.pcm +0 -0
  23. package/fixtures/pcm/multiturn-three-mixed.pcm +0 -0
  24. package/fixtures/pcm/multiturn-two-clean.pcm +0 -0
  25. package/fixtures/pcm/quietly-alone-clean.pcm +0 -0
  26. package/fixtures/pcm/rainstorms-noisy.pcm +0 -0
  27. package/fixtures/pcm/stella-bulgaria-bulgarian20.pcm +0 -0
  28. package/fixtures/pcm/stella-ghana-english507.pcm +0 -0
  29. package/fixtures/pcm/stella-india-english37.pcm +0 -0
  30. package/fixtures/pcm/stella-jamaica-jamaican-creole-english1.pcm +0 -0
  31. package/fixtures/pcm/stella-liberia-liberian-pidgin-english2.pcm +0 -0
  32. package/fixtures/pcm/stella-pakistan-english519.pcm +0 -0
  33. package/fixtures/pcm/stella-sierra-leone-krio5.pcm +0 -0
  34. package/fixtures/pcm/stella-singapore-english655.pcm +0 -0
  35. package/fixtures/pcm/traveled-back-route-clean.pcm +0 -0
@@ -3557,22 +3557,27 @@ var DEFAULT_AUDIO_FORMAT = {
3557
3557
  };
3558
3558
  var DEFAULT_TELEPHONY_SAMPLE_RATE_HZ = 8000;
3559
3559
  var DEFAULT_MULTI_SPEAKER_SILENCE_MS = 350;
3560
- var FIXTURE_DIR_CANDIDATES = [
3561
- resolve(import.meta.dir, "..", "..", "fixtures"),
3562
- resolve(import.meta.dir, "..", "..", "..", "fixtures"),
3563
- resolve(import.meta.dir, "..", "..", "..", "..", "fixtures")
3564
- ];
3565
3560
  var EXTERNAL_FIXTURE_ENV_KEYS = [
3566
3561
  "VOICE_FIXTURE_DIR",
3567
3562
  "VOICE_FIXTURE_DIRS"
3568
3563
  ];
3564
+ var resolveDefaultFixtureCandidates = () => {
3565
+ const envDirs = EXTERNAL_FIXTURE_ENV_KEYS.flatMap((key) => (process.env[key] ?? "").split(/[\n,]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0));
3566
+ return [
3567
+ ...envDirs.map((dir) => resolve(dir)),
3568
+ resolve(process.cwd(), "fixtures"),
3569
+ resolve(process.cwd(), "test", "fixtures", "audio"),
3570
+ resolve(import.meta.dir, "..", "..", "test", "fixtures", "audio"),
3571
+ resolve(import.meta.dir, "..", "..", "..", "test", "fixtures", "audio")
3572
+ ];
3573
+ };
3569
3574
  var resolveFixtureDirectory = async () => {
3570
- for (const candidate of FIXTURE_DIR_CANDIDATES) {
3575
+ for (const candidate of resolveDefaultFixtureCandidates()) {
3571
3576
  if (await Bun.file(resolve(candidate, "manifest.json")).exists()) {
3572
3577
  return candidate;
3573
3578
  }
3574
3579
  }
3575
- throw new Error("Unable to locate the bundled voice test fixtures. Expected fixtures/manifest.json next to the package root.");
3580
+ throw new Error("Unable to locate voice test fixtures. Set VOICE_FIXTURE_DIR/VOICE_FIXTURE_DIRS, or provide a fixtures/ directory (with manifest.json) in the working directory.");
3576
3581
  };
3577
3582
  var getVoiceFixtureDirectory = async () => resolveFixtureDirectory();
3578
3583
  var toUniqueDirectories = (directories) => directories.filter((directory, index, list) => directory.trim().length > 0 && list.indexOf(directory) === index);
@@ -7862,6 +7867,9 @@ var runVoiceResilienceBenchmark = async () => {
7862
7867
  }
7863
7868
  };
7864
7869
  };
7870
+ // src/internal/html.ts
7871
+ var escapeHtml = (value) => String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
7872
+
7865
7873
  // src/testing/review.ts
7866
7874
  var roundMetric4 = (value) => typeof value === "number" ? Math.round(value * 100) / 100 : undefined;
7867
7875
  var formatMetric = (label, value, unit = "ms") => typeof value === "number" ? `${label}: ${roundMetric4(value)}${unit}` : undefined;
@@ -8307,7 +8315,6 @@ var renderVoiceCallReviewMarkdown = (artifact) => {
8307
8315
  ].filter((value) => typeof value === "string").join(`
8308
8316
  `);
8309
8317
  };
8310
- var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
8311
8318
  var renderVoiceCallReviewHTML = (artifact) => {
8312
8319
  const notes = artifact.notes.map((note) => `<li>${escapeHtml(note)}</li>`).join("");
8313
8320
  const latency = artifact.latencyBreakdown.map((entry) => `<li><strong>${escapeHtml(entry.label)}:</strong> ${roundMetric4(entry.valueMs)}ms</li>`).join("");
@@ -9511,7 +9518,6 @@ var exportVoiceTrace = async (input) => {
9511
9518
  };
9512
9519
  };
9513
9520
  var toNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
9514
- var escapeHtml2 = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
9515
9521
  var formatTraceValue = (value) => {
9516
9522
  if (value === undefined || value === null) {
9517
9523
  return "";
@@ -9795,10 +9801,10 @@ var renderVoiceTraceHTML = (events, options = {}) => {
9795
9801
  const offset = summary.startedAt === undefined ? event.at : Math.max(0, event.at - summary.startedAt);
9796
9802
  return [
9797
9803
  "<tr>",
9798
- `<td>${escapeHtml2(String(offset))}</td>`,
9799
- `<td>${escapeHtml2(event.type)}</td>`,
9800
- `<td>${escapeHtml2(event.turnId ?? "")}</td>`,
9801
- `<td><code>${escapeHtml2(JSON.stringify(event.payload))}</code></td>`,
9804
+ `<td>${escapeHtml(String(offset))}</td>`,
9805
+ `<td>${escapeHtml(event.type)}</td>`,
9806
+ `<td>${escapeHtml(event.turnId ?? "")}</td>`,
9807
+ `<td><code>${escapeHtml(JSON.stringify(event.payload))}</code></td>`,
9802
9808
  "</tr>"
9803
9809
  ].join("");
9804
9810
  }).join(`
@@ -9809,7 +9815,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
9809
9815
  "<head>",
9810
9816
  '<meta charset="utf-8" />',
9811
9817
  '<meta name="viewport" content="width=device-width, initial-scale=1" />',
9812
- `<title>${escapeHtml2(options.title ?? "Voice Trace")}</title>`,
9818
+ `<title>${escapeHtml(options.title ?? "Voice Trace")}</title>`,
9813
9819
  "<style>",
9814
9820
  "body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}",
9815
9821
  "main{max-width:1100px;margin:auto}",
@@ -9823,7 +9829,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
9823
9829
  "</style>",
9824
9830
  "</head>",
9825
9831
  "<body><main>",
9826
- `<h1>${escapeHtml2(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
9832
+ `<h1>${escapeHtml(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
9827
9833
  `<p class="${evaluation.pass ? "pass" : "fail"}">QA: ${evaluation.pass ? "pass" : "fail"}</p>`,
9828
9834
  '<section class="summary">',
9829
9835
  `<div class="card"><strong>Events</strong><br>${summary.eventCount}</div>`,
@@ -9837,7 +9843,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
9837
9843
  eventRows,
9838
9844
  "</tbody></table>",
9839
9845
  "<h2>Markdown Export</h2>",
9840
- `<pre>${escapeHtml2(markdown)}</pre>`,
9846
+ `<pre>${escapeHtml(markdown)}</pre>`,
9841
9847
  "</main></body></html>"
9842
9848
  ].join(`
9843
9849
  `);
@@ -9851,7 +9857,6 @@ var buildVoiceTraceReplay = (events, options = {}) => ({
9851
9857
 
9852
9858
  // src/auditRoutes.ts
9853
9859
  import { Elysia } from "elysia";
9854
- var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
9855
9860
  var getString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
9856
9861
  var getNumber = (value) => {
9857
9862
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -9949,14 +9954,14 @@ var buildVoiceAuditTrailReport = async (options) => {
9949
9954
  };
9950
9955
  var renderVoiceAuditTrailHTML = (report, options = {}) => {
9951
9956
  const title = options.title ?? "AbsoluteJS Voice Audit Trail";
9952
- const chips = report.summary.byType.map(([type, count]) => `<span>${escapeHtml3(type)} <strong>${count}</strong></span>`).join("");
9957
+ const chips = report.summary.byType.map(([type, count]) => `<span>${escapeHtml(type)} <strong>${count}</strong></span>`).join("");
9953
9958
  const rows = report.events.map((event) => {
9954
9959
  const actor = event.actor ? `${event.actor.kind}:${event.actor.id}` : "unknown";
9955
9960
  const resource = event.resource ? `${event.resource.type}${event.resource.id ? `:${event.resource.id}` : ""}` : "";
9956
9961
  const payload = event.payload ? JSON.stringify(event.payload, null, 2) : "";
9957
- return `<article class="event ${escapeHtml3(event.outcome ?? "unknown")}"><div><span>${escapeHtml3(event.type)}</span><h2>${escapeHtml3(event.action)}</h2><p>${escapeHtml3(new Date(event.at).toLocaleString())}</p><p>Actor: ${escapeHtml3(actor)}${resource ? ` \xB7 Resource: ${escapeHtml3(resource)}` : ""}</p>${event.sessionId ? `<p>Session: ${escapeHtml3(event.sessionId)}</p>` : ""}</div><strong>${escapeHtml3(event.outcome ?? "recorded")}</strong>${payload ? `<pre>${escapeHtml3(payload)}</pre>` : ""}</article>`;
9962
+ return `<article class="event ${escapeHtml(event.outcome ?? "unknown")}"><div><span>${escapeHtml(event.type)}</span><h2>${escapeHtml(event.action)}</h2><p>${escapeHtml(new Date(event.at).toLocaleString())}</p><p>Actor: ${escapeHtml(actor)}${resource ? ` \xB7 Resource: ${escapeHtml(resource)}` : ""}</p>${event.sessionId ? `<p>Session: ${escapeHtml(event.sessionId)}</p>` : ""}</div><strong>${escapeHtml(event.outcome ?? "recorded")}</strong>${payload ? `<pre>${escapeHtml(payload)}</pre>` : ""}</article>`;
9958
9963
  }).join("");
9959
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml3(title)}</title><style>body{background:#11140f;color:#f7f1df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(245,158,11,.12));border:1px solid #2c3327;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#facc15;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.chips{display:flex;flex-wrap:wrap;gap:10px}.chips span{border:1px solid #46513b;border-radius:999px;padding:8px 12px}.events{display:grid;gap:14px}.event{background:#181d15;border:1px solid #2c3327;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto;padding:18px}.event.error{border-color:rgba(239,68,68,.75)}.event.skipped{border-color:rgba(245,158,11,.7)}.event.success{border-color:rgba(34,197,94,.55)}.event span{color:#facc15;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.event h2{margin:.2rem 0}.event p{color:#c8ccb8;margin:.2rem 0}.event strong{text-transform:uppercase}pre{background:#0c0f0a;border-radius:14px;grid-column:1/-1;overflow:auto;padding:14px;white-space:pre-wrap}@media(max-width:760px){main{padding:20px}.event{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted evidence</p><h1>${escapeHtml3(title)}</h1><p>${report.summary.total} event(s), ${report.summary.errors} error(s). Latest ${report.summary.latestAt ? escapeHtml3(new Date(report.summary.latestAt).toLocaleString()) : "never"}.</p><div class="chips">${chips}</div></section><section class="events">${rows || "<p>No audit events match this filter.</p>"}</section></main></body></html>`;
9964
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#11140f;color:#f7f1df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(245,158,11,.12));border:1px solid #2c3327;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#facc15;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.chips{display:flex;flex-wrap:wrap;gap:10px}.chips span{border:1px solid #46513b;border-radius:999px;padding:8px 12px}.events{display:grid;gap:14px}.event{background:#181d15;border:1px solid #2c3327;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto;padding:18px}.event.error{border-color:rgba(239,68,68,.75)}.event.skipped{border-color:rgba(245,158,11,.7)}.event.success{border-color:rgba(34,197,94,.55)}.event span{color:#facc15;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.event h2{margin:.2rem 0}.event p{color:#c8ccb8;margin:.2rem 0}.event strong{text-transform:uppercase}pre{background:#0c0f0a;border-radius:14px;grid-column:1/-1;overflow:auto;padding:14px;white-space:pre-wrap}@media(max-width:760px){main{padding:20px}.event{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted evidence</p><h1>${escapeHtml(title)}</h1><p>${report.summary.total} event(s), ${report.summary.errors} error(s). Latest ${report.summary.latestAt ? escapeHtml(new Date(report.summary.latestAt).toLocaleString()) : "never"}.</p><div class="chips">${chips}</div></section><section class="events">${rows || "<p>No audit events match this filter.</p>"}</section></main></body></html>`;
9960
9965
  };
9961
9966
  var createVoiceAuditTrailRoutes = (options) => {
9962
9967
  const path = options.path ?? "/api/voice-audit";
@@ -10048,7 +10053,6 @@ var createVoiceAuditTrailRoutes = (options) => {
10048
10053
  };
10049
10054
 
10050
10055
  // src/auditExport.ts
10051
- var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10052
10056
  var normalizeRedactionKey2 = (key) => key.trim().toLowerCase().replace(/[^a-z0-9]/g, "");
10053
10057
  var resolveReplacement2 = (input) => typeof input.options.replacement === "function" ? input.options.replacement({
10054
10058
  key: input.key,
@@ -10166,8 +10170,8 @@ var renderVoiceAuditHTML = (events, options = {}) => {
10166
10170
  const markdown = renderVoiceAuditMarkdown(events, options);
10167
10171
  const renderEvents = options.redact ? redactVoiceAuditEvents(events, options.redact) : events;
10168
10172
  const summary = summarizeVoiceAuditTrail(renderEvents);
10169
- const rows = renderEvents.map((event) => `<tr><td>${escapeHtml4(new Date(event.at).toISOString())}</td><td>${escapeHtml4(event.type)}</td><td>${escapeHtml4(event.action)}</td><td>${escapeHtml4(event.outcome ?? "")}</td><td><code>${escapeHtml4(JSON.stringify(event.payload ?? {}))}</code></td></tr>`).join("");
10170
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml4(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;margin:1rem 0}.card{background:white;border:1px solid #ded9cc;border-radius:12px;padding:1rem}table{border-collapse:collapse;width:100%;background:white;border:1px solid #ded9cc}th,td{border-bottom:1px solid #eee8dc;padding:.65rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}pre{background:#181713;color:#f8f7f2;padding:1rem;border-radius:12px;overflow:auto}</style></head><body><main><h1>${escapeHtml4(title)}</h1><section class="summary"><div class="card"><strong>Events</strong><br>${summary.total}</div><div class="card"><strong>Errors</strong><br>${summary.errors}</div><div class="card"><strong>Latest</strong><br>${summary.latestAt ? escapeHtml4(new Date(summary.latestAt).toLocaleString()) : "never"}</div></section><table><thead><tr><th>At</th><th>Type</th><th>Action</th><th>Outcome</th><th>Payload</th></tr></thead><tbody>${rows}</tbody></table><h2>Markdown Export</h2><pre>${escapeHtml4(markdown)}</pre></main></body></html>`;
10173
+ const rows = renderEvents.map((event) => `<tr><td>${escapeHtml(new Date(event.at).toISOString())}</td><td>${escapeHtml(event.type)}</td><td>${escapeHtml(event.action)}</td><td>${escapeHtml(event.outcome ?? "")}</td><td><code>${escapeHtml(JSON.stringify(event.payload ?? {}))}</code></td></tr>`).join("");
10174
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;margin:1rem 0}.card{background:white;border:1px solid #ded9cc;border-radius:12px;padding:1rem}table{border-collapse:collapse;width:100%;background:white;border:1px solid #ded9cc}th,td{border-bottom:1px solid #eee8dc;padding:.65rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}pre{background:#181713;color:#f8f7f2;padding:1rem;border-radius:12px;overflow:auto}</style></head><body><main><h1>${escapeHtml(title)}</h1><section class="summary"><div class="card"><strong>Events</strong><br>${summary.total}</div><div class="card"><strong>Errors</strong><br>${summary.errors}</div><div class="card"><strong>Latest</strong><br>${summary.latestAt ? escapeHtml(new Date(summary.latestAt).toLocaleString()) : "never"}</div></section><table><thead><tr><th>At</th><th>Type</th><th>Action</th><th>Outcome</th><th>Payload</th></tr></thead><tbody>${rows}</tbody></table><h2>Markdown Export</h2><pre>${escapeHtml(markdown)}</pre></main></body></html>`;
10171
10175
  };
10172
10176
  var buildVoiceAuditExport = (events, options = {}) => {
10173
10177
  const exportEvents = options.redact ? redactVoiceAuditEvents(events, options.redact) : events;
@@ -10182,7 +10186,6 @@ var buildVoiceAuditExport = (events, options = {}) => {
10182
10186
  // src/sessionReplay.ts
10183
10187
  import { Elysia as Elysia2 } from "elysia";
10184
10188
  var getString2 = (value) => typeof value === "string" ? value : undefined;
10185
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10186
10189
  var increment2 = (record, key) => {
10187
10190
  record[key] = (record[key] ?? 0) + 1;
10188
10191
  };
@@ -10379,10 +10382,10 @@ var summarizeVoiceSessions = async (options = {}) => {
10379
10382
  var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
10380
10383
  '<div class="voice-sessions-list">',
10381
10384
  ...sessions.map((session) => [
10382
- `<article class="voice-session-card ${escapeHtml5(session.status)}">`,
10385
+ `<article class="voice-session-card ${escapeHtml(session.status)}">`,
10383
10386
  '<div class="voice-session-card-header">',
10384
- `<strong>${escapeHtml5(session.sessionId)}</strong>`,
10385
- `<span>${escapeHtml5(session.status)}</span>`,
10387
+ `<strong>${escapeHtml(session.sessionId)}</strong>`,
10388
+ `<span>${escapeHtml(session.status)}</span>`,
10386
10389
  "</div>",
10387
10390
  "<dl>",
10388
10391
  `<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
@@ -10390,9 +10393,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
10390
10393
  `<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
10391
10394
  `<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
10392
10395
  "</dl>",
10393
- session.latestOutcome ? `<p>Outcome: ${escapeHtml5(session.latestOutcome)}</p>` : "",
10394
- session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml5).join(", ")}</p>` : "",
10395
- session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml5(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml5(session.replayHref)}">Open replay</a></p>` : "",
10396
+ session.latestOutcome ? `<p>Outcome: ${escapeHtml(session.latestOutcome)}</p>` : "",
10397
+ session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml).join(", ")}</p>` : "",
10398
+ session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml(session.replayHref)}">Open replay</a></p>` : "",
10396
10399
  "</article>"
10397
10400
  ].join("")),
10398
10401
  "</div>"
@@ -10462,7 +10465,6 @@ var createVoiceSessionReplayRoutes = (options) => {
10462
10465
 
10463
10466
  // src/traceTimeline.ts
10464
10467
  import { Elysia as Elysia3 } from "elysia";
10465
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10466
10468
  var getString3 = (value) => typeof value === "string" && value.trim() ? value : undefined;
10467
10469
  var getNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
10468
10470
  var firstString = (payload, keys) => {
@@ -10648,17 +10650,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
10648
10650
  };
10649
10651
  };
10650
10652
  var formatMs = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
10651
- var renderProviderCards = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml6(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>`;
10653
+ var renderProviderCards = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
10652
10654
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
10653
- const events = session.events.map((event) => `<tr class="${escapeHtml6(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml6(event.type)}</td><td>${escapeHtml6(event.label)}</td><td>${escapeHtml6(event.provider ?? "")}</td><td>${escapeHtml6(event.status ?? "")}</td><td>${formatMs(event.elapsedMs)}</td></tr>`).join("");
10654
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml6(issue.severity)}">${escapeHtml6(issue.code)}: ${escapeHtml6(issue.message)}</li>`).join("") : "<li>none</li>";
10655
- const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml6(session.operationsRecordHref)}">Open operations record</a></p>` : "";
10656
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml6(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>${escapeHtml6(session.sessionId)}</h1><p class="status ${escapeHtml6(session.status)}">${escapeHtml6(session.status)}</p>${supportLinks}</header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
10655
+ const events = session.events.map((event) => `<tr class="${escapeHtml(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml(event.type)}</td><td>${escapeHtml(event.label)}</td><td>${escapeHtml(event.provider ?? "")}</td><td>${escapeHtml(event.status ?? "")}</td><td>${formatMs(event.elapsedMs)}</td></tr>`).join("");
10656
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml(issue.severity)}">${escapeHtml(issue.code)}: ${escapeHtml(issue.message)}</li>`).join("") : "<li>none</li>";
10657
+ const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml(session.operationsRecordHref)}">Open operations record</a></p>` : "";
10658
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml(session.sessionId)}</h1><p class="status ${escapeHtml(session.status)}">${escapeHtml(session.status)}</p>${supportLinks}</header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
10657
10659
  };
10658
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml6(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml6(session.operationsRecordHref)}">${escapeHtml6(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml6(session.sessionId)}</a>`}</td><td>${escapeHtml6(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) => escapeHtml6(provider.provider)).join(", ")}</td></tr>`).join("");
10660
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">${escapeHtml(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml(session.sessionId)}</a>`}</td><td>${escapeHtml(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml(provider.provider)).join(", ")}</td></tr>`).join("");
10659
10661
  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}}";
10660
10662
  var renderVoiceTraceTimelineHTML = (report, options = {}) => {
10661
- const snippet = escapeHtml6(`const traceStore = createVoiceTraceSinkStore({
10663
+ const snippet = escapeHtml(`const traceStore = createVoiceTraceSinkStore({
10662
10664
  store: runtimeStorage.traces,
10663
10665
  sinks: [
10664
10666
  createVoiceTraceHTTPSink({
@@ -10684,7 +10686,7 @@ app.use(
10684
10686
  traceDeliveries: runtimeStorage.traceDeliveries
10685
10687
  })
10686
10688
  );`);
10687
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml6(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml6(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
10689
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
10688
10690
  };
10689
10691
  var createVoiceTraceTimelineRoutes = (options) => {
10690
10692
  const path = options.path ?? "/api/voice-traces";
@@ -11354,7 +11356,6 @@ var renderVoiceFailureReplayMarkdown = (report) => {
11354
11356
  ].join(`
11355
11357
  `);
11356
11358
  };
11357
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11358
11359
  var formatMs2 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
11359
11360
  var outcomeLabels = (outcome) => [
11360
11361
  outcome.complete ? "complete" : undefined,
@@ -11480,18 +11481,18 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
11480
11481
  `);
11481
11482
  };
11482
11483
  var renderVoiceOperationsRecordHTML = (record, options = {}) => {
11483
- const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml7(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs2(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
11484
- const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml7(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml7(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml7(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml7(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
11485
- const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml7(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml7(decision.status ?? decision.type)}</span> ${formatMs2(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml7(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml7(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml7(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml7(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml7(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml7(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
11484
+ const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs2(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
11485
+ const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
11486
+ const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml(decision.status ?? decision.type)}</span> ${formatMs2(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
11486
11487
  const providerDecisionSummary = record.providerDecisionSummary;
11487
- const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml7(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml7(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml7(handoff.status ?? "")}</span><p>${escapeHtml7(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
11488
- const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml7(tool.toolName ?? "tool")}</strong> <span>${escapeHtml7(tool.status ?? "")}</span> ${formatMs2(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml7(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
11489
- const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml7(review.title)}</strong> <span>${escapeHtml7(review.summary.outcome ?? "")}</span><p>${escapeHtml7(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
11490
- const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml7(task.title)}</strong> <span>${escapeHtml7(task.status)}</span><p>${escapeHtml7(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
11491
- const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml7(event.type)}</strong> <span>${escapeHtml7(event.deliveryStatus ?? "local")}</span><p>${escapeHtml7(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
11488
+ const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml(handoff.status ?? "")}</span><p>${escapeHtml(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
11489
+ const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml(tool.toolName ?? "tool")}</strong> <span>${escapeHtml(tool.status ?? "")}</span> ${formatMs2(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
11490
+ const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml(review.title)}</strong> <span>${escapeHtml(review.summary.outcome ?? "")}</span><p>${escapeHtml(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
11491
+ const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml(task.title)}</strong> <span>${escapeHtml(task.status)}</span><p>${escapeHtml(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
11492
+ const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml(event.type)}</strong> <span>${escapeHtml(event.deliveryStatus ?? "local")}</span><p>${escapeHtml(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
11492
11493
  const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
11493
11494
  const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
11494
- return `<li><strong>assistant.guardrail ${escapeHtml7(decision.stage ?? "unknown")}</strong> <span>${escapeHtml7(decision.status ?? "")}</span><p>Allowed: ${escapeHtml7(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml7(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml7(decision.turnId)}` : ""}</p><p>${escapeHtml7(findings)}</p></li>`;
11495
+ return `<li><strong>assistant.guardrail ${escapeHtml(decision.stage ?? "unknown")}</strong> <span>${escapeHtml(decision.status ?? "")}</span><p>Allowed: ${escapeHtml(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml(decision.turnId)}` : ""}</p><p>${escapeHtml(findings)}</p></li>`;
11495
11496
  }).join("") : "<li>No assistant.guardrail events recorded.</li>";
11496
11497
  const telephonyMedia = record.telephonyMedia.events.length ? record.telephonyMedia.events.slice(0, 50).map((event) => {
11497
11498
  const details = [
@@ -11502,12 +11503,12 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
11502
11503
  event.sequenceNumber ? `Seq: ${event.sequenceNumber}` : undefined,
11503
11504
  `Audio bytes: ${String(event.audioBytes)}`
11504
11505
  ].filter((detail) => typeof detail === "string");
11505
- return `<li><strong>${escapeHtml7(event.event)}</strong> <span>${escapeHtml7(new Date(event.at).toLocaleString())}</span><p>${escapeHtml7(details.join(" \xB7 "))}</p></li>`;
11506
+ return `<li><strong>${escapeHtml(event.event)}</strong> <span>${escapeHtml(new Date(event.at).toLocaleString())}</span><p>${escapeHtml(details.join(" \xB7 "))}</p></li>`;
11506
11507
  }).join("") : "<li>No telephony media trace events recorded.</li>";
11507
- const mediaPipelineSection = record.mediaPipeline ? `<section id="media-pipeline"><h2>Media Pipeline</h2><p class="muted">Surface: ${escapeHtml7(record.mediaPipeline.surface)} \xB7 Status: ${escapeHtml7(record.mediaPipeline.status)} \xB7 Quality: ${escapeHtml7(record.mediaPipeline.qualityStatus)} \xB7 Transport: ${escapeHtml7(record.mediaPipeline.transportStatus ?? "n/a")} \xB7 Graph: ${escapeHtml7(record.mediaPipeline.processorGraphStatus ?? "n/a")} \xB7 Frames: ${String(record.mediaPipeline.frames)} \xB7 Jitter: ${record.mediaPipeline.jitterMs === undefined ? "n/a" : `${String(record.mediaPipeline.jitterMs)}ms`}</p><ul>${record.mediaPipeline.issueCodes.length ? record.mediaPipeline.issueCodes.map((code) => `<li><strong>${escapeHtml7(code)}</strong></li>`).join("") : "<li>No media pipeline issue codes.</li>"}</ul></section>` : "";
11508
- const mediaPipelineCard = record.mediaPipeline ? `<div class="card"><span>Media pipeline</span><strong>${escapeHtml7(record.mediaPipeline.status)}</strong><span>${String(record.mediaPipeline.issueCodes.length)} issue code(s)</span></div>` : "";
11508
+ const mediaPipelineSection = record.mediaPipeline ? `<section id="media-pipeline"><h2>Media Pipeline</h2><p class="muted">Surface: ${escapeHtml(record.mediaPipeline.surface)} \xB7 Status: ${escapeHtml(record.mediaPipeline.status)} \xB7 Quality: ${escapeHtml(record.mediaPipeline.qualityStatus)} \xB7 Transport: ${escapeHtml(record.mediaPipeline.transportStatus ?? "n/a")} \xB7 Graph: ${escapeHtml(record.mediaPipeline.processorGraphStatus ?? "n/a")} \xB7 Frames: ${String(record.mediaPipeline.frames)} \xB7 Jitter: ${record.mediaPipeline.jitterMs === undefined ? "n/a" : `${String(record.mediaPipeline.jitterMs)}ms`}</p><ul>${record.mediaPipeline.issueCodes.length ? record.mediaPipeline.issueCodes.map((code) => `<li><strong>${escapeHtml(code)}</strong></li>`).join("") : "<li>No media pipeline issue codes.</li>"}</ul></section>` : "";
11509
+ const mediaPipelineCard = record.mediaPipeline ? `<div class="card"><span>Media pipeline</span><strong>${escapeHtml(record.mediaPipeline.status)}</strong><span>${String(record.mediaPipeline.issueCodes.length)} issue code(s)</span></div>` : "";
11509
11510
  const mediaPipelineNavLink = record.mediaPipeline ? '<a href="#media-pipeline">Media pipeline</a>' : "";
11510
- const snippet = escapeHtml7(`app.use(
11511
+ const snippet = escapeHtml(`app.use(
11511
11512
  createVoiceOperationsRecordRoutes({
11512
11513
  audit: auditStore,
11513
11514
  integrationEvents: opsEvents,
@@ -11521,9 +11522,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
11521
11522
  tasks: opsTasks
11522
11523
  })
11523
11524
  );`);
11524
- const incidentMarkdown = escapeHtml7(renderVoiceOperationsRecordIncidentMarkdown(record));
11525
- const incidentLink = options.incidentHref ? `<a href="${escapeHtml7(options.incidentHref)}">Download incident.md</a>` : "";
11526
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml7(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml7(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml7(record.status)}">${escapeHtml7(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#telephony-media">Telephony media</a>${mediaPipelineNavLink}<a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs2(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml7(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Telephony media</span><strong>${String(record.telephonyMedia.media)}</strong><span>${String(record.telephonyMedia.inbound)} inbound / ${String(record.telephonyMedia.outbound)} outbound / ${String(record.telephonyMedia.clears)} clears</span></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div>${mediaPipelineCard}</section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="telephony-media"><h2>Telephony Media</h2><p class="muted">Live <code>client.telephony_media</code> stream lifecycle evidence attached to this session. Carriers: ${escapeHtml7(record.telephonyMedia.carriers.join(", ") || "none")}. Streams: ${escapeHtml7(record.telephonyMedia.streamIds.join(", ") || "none")}. Inbound: ${String(record.telephonyMedia.inbound)}. Outbound: ${String(record.telephonyMedia.outbound)}. Marks: ${String(record.telephonyMedia.marks)}. Clears: ${String(record.telephonyMedia.clears)}.</p><ul>${telephonyMedia}</ul></section>${mediaPipelineSection}<section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, media streams, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
11525
+ const incidentMarkdown = escapeHtml(renderVoiceOperationsRecordIncidentMarkdown(record));
11526
+ const incidentLink = options.incidentHref ? `<a href="${escapeHtml(options.incidentHref)}">Download incident.md</a>` : "";
11527
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml(record.status)}">${escapeHtml(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#telephony-media">Telephony media</a>${mediaPipelineNavLink}<a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs2(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Telephony media</span><strong>${String(record.telephonyMedia.media)}</strong><span>${String(record.telephonyMedia.inbound)} inbound / ${String(record.telephonyMedia.outbound)} outbound / ${String(record.telephonyMedia.clears)} clears</span></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div>${mediaPipelineCard}</section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="telephony-media"><h2>Telephony Media</h2><p class="muted">Live <code>client.telephony_media</code> stream lifecycle evidence attached to this session. Carriers: ${escapeHtml(record.telephonyMedia.carriers.join(", ") || "none")}. Streams: ${escapeHtml(record.telephonyMedia.streamIds.join(", ") || "none")}. Inbound: ${String(record.telephonyMedia.inbound)}. Outbound: ${String(record.telephonyMedia.outbound)}. Marks: ${String(record.telephonyMedia.marks)}. Clears: ${String(record.telephonyMedia.clears)}.</p><ul>${telephonyMedia}</ul></section>${mediaPipelineSection}<section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, media streams, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
11527
11528
  };
11528
11529
  var createVoiceOperationsRecordRoutes = (options) => {
11529
11530
  const path = options.path ?? "/api/voice-operations/:sessionId";
@@ -12414,7 +12415,6 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
12414
12415
  return parameters;
12415
12416
  };
12416
12417
  var joinUrlPath = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
12417
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
12418
12418
  var getWebhookVerificationUrl = (webhook, input) => {
12419
12419
  if (!webhook?.verificationUrl) {
12420
12420
  return;
@@ -12459,23 +12459,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
12459
12459
  };
12460
12460
  var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
12461
12461
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
12462
- <h1>${escapeHtml8(title)}</h1>
12462
+ <h1>${escapeHtml(title)}</h1>
12463
12463
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
12464
12464
  <section>
12465
12465
  <h2>URLs</h2>
12466
12466
  <ul>
12467
- <li><strong>TwiML:</strong> <code>${escapeHtml8(status.urls.twiml)}</code></li>
12468
- <li><strong>Media stream:</strong> <code>${escapeHtml8(status.urls.stream)}</code></li>
12469
- <li><strong>Status webhook:</strong> <code>${escapeHtml8(status.urls.webhook)}</code></li>
12467
+ <li><strong>TwiML:</strong> <code>${escapeHtml(status.urls.twiml)}</code></li>
12468
+ <li><strong>Media stream:</strong> <code>${escapeHtml(status.urls.stream)}</code></li>
12469
+ <li><strong>Status webhook:</strong> <code>${escapeHtml(status.urls.webhook)}</code></li>
12470
12470
  </ul>
12471
12471
  </section>
12472
12472
  <section>
12473
12473
  <h2>Signing</h2>
12474
12474
  <p>Mode: <code>${status.signing.mode}</code></p>
12475
- ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml8(status.signing.verificationUrl)}</code></p>` : ""}
12475
+ ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml(status.signing.verificationUrl)}</code></p>` : ""}
12476
12476
  </section>
12477
- ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml8(name)}</code></li>`).join("")}</ul></section>` : ""}
12478
- ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml8(warning)}</li>`).join("")}</ul></section>` : ""}
12477
+ ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml(name)}</code></li>`).join("")}</ul></section>` : ""}
12478
+ ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml(warning)}</li>`).join("")}</ul></section>` : ""}
12479
12479
  </main>`;
12480
12480
  var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&amp;", "&");
12481
12481
  var createSmokeCheck = (name, status, message, details) => ({
@@ -12486,20 +12486,20 @@ var createSmokeCheck = (name, status, message, details) => ({
12486
12486
  });
12487
12487
  var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
12488
12488
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
12489
- <h1>${escapeHtml8(title)}</h1>
12489
+ <h1>${escapeHtml(title)}</h1>
12490
12490
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
12491
12491
  <section>
12492
12492
  <h2>Checks</h2>
12493
12493
  <ul>
12494
- ${report.checks.map((check) => `<li><strong>${escapeHtml8(check.name)}</strong>: ${escapeHtml8(check.status)}${check.message ? ` - ${escapeHtml8(check.message)}` : ""}</li>`).join("")}
12494
+ ${report.checks.map((check) => `<li><strong>${escapeHtml(check.name)}</strong>: ${escapeHtml(check.status)}${check.message ? ` - ${escapeHtml(check.message)}` : ""}</li>`).join("")}
12495
12495
  </ul>
12496
12496
  </section>
12497
12497
  <section>
12498
12498
  <h2>Observed URLs</h2>
12499
12499
  <ul>
12500
- <li><strong>TwiML:</strong> <code>${escapeHtml8(report.setup.urls.twiml)}</code></li>
12501
- <li><strong>Stream:</strong> <code>${escapeHtml8(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
12502
- <li><strong>Webhook:</strong> <code>${escapeHtml8(report.setup.urls.webhook)}</code></li>
12500
+ <li><strong>TwiML:</strong> <code>${escapeHtml(report.setup.urls.twiml)}</code></li>
12501
+ <li><strong>Stream:</strong> <code>${escapeHtml(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
12502
+ <li><strong>Webhook:</strong> <code>${escapeHtml(report.setup.urls.webhook)}</code></li>
12503
12503
  </ul>
12504
12504
  </section>
12505
12505
  </main>`;
@@ -37,7 +37,7 @@ export { VoiceCostDashboard } from "./VoiceCostDashboard";
37
37
  export { VoiceLiveAgentConsole } from "./VoiceLiveAgentConsole";
38
38
  export { VoiceLiveCallViewer } from "./VoiceLiveCallViewer";
39
39
  export { VoiceReplayTimeline } from "./VoiceReplayTimeline";
40
- export type { VoiceWidgetLabels, VoiceWidgetTheme, } from "./VoiceWidget";
40
+ export type { VoiceWidgetLabels, VoiceWidgetTheme } from "./VoiceWidget";
41
41
  export { useVoiceProviderStatus } from "./useVoiceProviderStatus";
42
42
  export { useVoiceProviderCapabilities } from "./useVoiceProviderCapabilities";
43
43
  export { useVoiceProviderContracts } from "./useVoiceProviderContracts";