@absolutejs/voice 0.0.22-beta.333 → 0.0.22-beta.334

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.
@@ -1678,6 +1678,162 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
1678
1678
  }
1679
1679
  return assertion;
1680
1680
  };
1681
+ var DEFAULT_RECOMMENDATION_BUDGETS = {
1682
+ maxLiveP95Ms: 800,
1683
+ maxProviderP95Ms: 1000,
1684
+ maxRuntimeBackpressureEvents: 0,
1685
+ maxRuntimeFirstAudioLatencyMs: 600,
1686
+ maxRuntimeInterruptionP95Ms: 300,
1687
+ maxRuntimeJitterMs: 30,
1688
+ maxRuntimeTimestampDriftMs: 800,
1689
+ maxTurnP95Ms: 700
1690
+ };
1691
+ var withinBudget = (value, budget) => typeof value === "number" && Number.isFinite(value) && value <= budget;
1692
+ var recommendationStatusRank = {
1693
+ pass: 0,
1694
+ warn: 1,
1695
+ fail: 2
1696
+ };
1697
+ var worstRecommendationStatus = (recommendations) => recommendations.reduce((status, recommendation) => recommendationStatusRank[recommendation.status] > recommendationStatusRank[status] ? recommendation.status : status, "pass");
1698
+ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1699
+ const budgets = { ...DEFAULT_RECOMMENDATION_BUDGETS, ...options };
1700
+ const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
1701
+ const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
1702
+ const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
1703
+ const runtimeChannel = readProofTrendRuntimeChannel(report);
1704
+ const recommendations = [];
1705
+ const issues = [];
1706
+ if (report.ok !== true) {
1707
+ issues.push(`Proof trend report is ${report.status}; recommendations need a fresh passing trend artifact.`);
1708
+ }
1709
+ recommendations.push({
1710
+ evidence: {
1711
+ budgetMs: budgets.maxProviderP95Ms,
1712
+ providerP95Ms: maxProviderP95Ms
1713
+ },
1714
+ nextMove: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
1715
+ recommendation: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
1716
+ status: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
1717
+ surface: "provider-path"
1718
+ });
1719
+ const runtimePass = withinBudget(runtimeChannel.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) && withinBudget(runtimeChannel.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) && withinBudget(runtimeChannel.maxJitterMs, budgets.maxRuntimeJitterMs) && withinBudget(runtimeChannel.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) && withinBudget(runtimeChannel.maxBackpressureEvents, budgets.maxRuntimeBackpressureEvents);
1720
+ recommendations.push({
1721
+ evidence: {
1722
+ backpressureEvents: runtimeChannel.maxBackpressureEvents,
1723
+ firstAudioBudgetMs: budgets.maxRuntimeFirstAudioLatencyMs,
1724
+ firstAudioMs: runtimeChannel.maxFirstAudioLatencyMs,
1725
+ interruptionBudgetMs: budgets.maxRuntimeInterruptionP95Ms,
1726
+ interruptionP95Ms: runtimeChannel.maxInterruptionP95Ms,
1727
+ jitterBudgetMs: budgets.maxRuntimeJitterMs,
1728
+ jitterMs: runtimeChannel.maxJitterMs,
1729
+ samples: runtimeChannel.samples,
1730
+ timestampDriftMs: runtimeChannel.maxTimestampDriftMs
1731
+ },
1732
+ nextMove: runtimePass ? "Keep the current runtime-channel settings and use this artifact as the deploy gate baseline." : "Tune capture/output format, buffering, interruption threshold, or transport backpressure before promoting this runtime path.",
1733
+ recommendation: runtimePass ? "Keep current runtime channel" : "Tune runtime channel before promotion",
1734
+ status: runtimePass ? "pass" : runtimeChannel.samples === undefined ? "fail" : "warn",
1735
+ surface: "runtime-channel"
1736
+ });
1737
+ recommendations.push({
1738
+ evidence: {
1739
+ budgetMs: budgets.maxLiveP95Ms,
1740
+ liveP95Ms: maxLiveP95Ms
1741
+ },
1742
+ nextMove: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep browser live-latency defaults and continue watching long-window drift." : "Tune browser streaming, chunking, or readiness thresholds before release.",
1743
+ recommendation: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep live-latency settings" : "Tune live-latency path",
1744
+ status: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "pass" : maxLiveP95Ms === undefined ? "fail" : "warn",
1745
+ surface: "live-latency"
1746
+ });
1747
+ recommendations.push({
1748
+ evidence: {
1749
+ budgetMs: budgets.maxTurnP95Ms,
1750
+ turnP95Ms: maxTurnP95Ms
1751
+ },
1752
+ nextMove: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep current turn pipeline defaults." : "Reduce tool/provider latency or split the turn pipeline before promotion.",
1753
+ recommendation: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep turn pipeline" : "Tune turn pipeline",
1754
+ status: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "pass" : maxTurnP95Ms === undefined ? "fail" : "warn",
1755
+ surface: "turn-latency"
1756
+ });
1757
+ const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
1758
+ return {
1759
+ generatedAt: new Date().toISOString(),
1760
+ issues,
1761
+ ok: status !== "fail",
1762
+ recommendations,
1763
+ source: report.source || report.outputDir || report.runId || "proof-trends",
1764
+ status,
1765
+ summary: {
1766
+ keepCurrentProviderPath: recommendations.find((item) => item.surface === "provider-path")?.status === "pass",
1767
+ keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
1768
+ recommendedActions: recommendations.filter((item) => item.status !== "pass").length
1769
+ }
1770
+ };
1771
+ };
1772
+ var escapeHtml5 = (value) => String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1773
+ var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
1774
+ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
1775
+ `# ${title}`,
1776
+ "",
1777
+ `- Status: ${report.status}`,
1778
+ `- Source: ${report.source}`,
1779
+ `- Recommended actions: ${String(report.summary.recommendedActions)}`,
1780
+ "",
1781
+ "| Surface | Status | Recommendation | Next move |",
1782
+ "| --- | --- | --- | --- |",
1783
+ ...report.recommendations.map((recommendation) => `| ${escapeMarkdown(recommendation.surface)} | ${recommendation.status} | ${escapeMarkdown(recommendation.recommendation)} | ${escapeMarkdown(recommendation.nextMove)} |`),
1784
+ "",
1785
+ "## Issues",
1786
+ "",
1787
+ ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
1788
+ ].join(`
1789
+ `);
1790
+ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
1791
+ const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml5(recommendation.status)}"><p class="eyebrow">${escapeHtml5(recommendation.surface)} \xB7 ${escapeHtml5(recommendation.status)}</p><h2>${escapeHtml5(recommendation.recommendation)}</h2><p>${escapeHtml5(recommendation.nextMove)}</p><pre>${escapeHtml5(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
1792
+ const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
1793
+ 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:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml5(title)}</h1><p>Generated ${escapeHtml5(report.generatedAt)} from ${escapeHtml5(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml5(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
1794
+ };
1795
+ var createVoiceProofTrendRecommendationRoutes = (options) => {
1796
+ const path = options.path ?? "/api/voice/proof-trend-recommendations";
1797
+ const htmlPath = options.htmlPath === undefined ? "/voice/proof-trend-recommendations" : options.htmlPath;
1798
+ const markdownPath = options.markdownPath === undefined ? "/voice/proof-trend-recommendations.md" : options.markdownPath;
1799
+ const title = options.title ?? "Voice Provider Runtime Recommendations";
1800
+ const routes = new Elysia({
1801
+ name: options.name ?? "absolutejs-voice-proof-trend-recommendations"
1802
+ });
1803
+ const loadReport = async () => {
1804
+ const value = options.source !== undefined ? typeof options.source === "function" ? await options.source() : options.source : options.jsonPath ? await readVoiceProofTrendReportFile(options.jsonPath, {
1805
+ maxAgeMs: options.maxAgeMs
1806
+ }) : buildEmptyVoiceProofTrendReport("", options.maxAgeMs);
1807
+ return buildVoiceProofTrendRecommendationReport(normalizeVoiceProofTrendReport(value, {
1808
+ maxAgeMs: options.maxAgeMs,
1809
+ source: options.jsonPath
1810
+ }), options);
1811
+ };
1812
+ routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
1813
+ if (htmlPath !== false) {
1814
+ routes.get(htmlPath, async () => {
1815
+ const report = await loadReport();
1816
+ return new Response(renderVoiceProofTrendRecommendationHTML(report, title), {
1817
+ headers: {
1818
+ "content-type": "text/html; charset=utf-8",
1819
+ ...Object.fromEntries(new Headers(options.headers))
1820
+ }
1821
+ });
1822
+ });
1823
+ }
1824
+ if (markdownPath !== false) {
1825
+ routes.get(markdownPath, async () => {
1826
+ const report = await loadReport();
1827
+ return new Response(renderVoiceProofTrendRecommendationMarkdown(report, title), {
1828
+ headers: {
1829
+ "content-type": "text/markdown; charset=utf-8",
1830
+ ...Object.fromEntries(new Headers(options.headers))
1831
+ }
1832
+ });
1833
+ });
1834
+ }
1835
+ return routes;
1836
+ };
1681
1837
  var createVoiceProofTrendRoutes = (options) => {
1682
1838
  const path = options.path ?? "/api/voice/proof-trends";
1683
1839
  const routes = new Elysia({
@@ -1720,7 +1876,7 @@ var DEFAULT_LINKS2 = [
1720
1876
  { href: "/voice/proof-trends", label: "Trend page" },
1721
1877
  { href: "/api/voice/proof-trends", label: "Trend JSON" }
1722
1878
  ];
1723
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1879
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1724
1880
  var formatMs = (value) => typeof value === "number" && Number.isFinite(value) ? `${Math.round(value)}ms` : "n/a";
1725
1881
  var statusLabel = (report) => {
1726
1882
  if (!report) {
@@ -1770,19 +1926,19 @@ var createVoiceProofTrendsViewModel = (snapshot, options = {}) => {
1770
1926
  var renderVoiceProofTrendsHTML = (snapshot, options = {}) => {
1771
1927
  const model = createVoiceProofTrendsViewModel(snapshot, options);
1772
1928
  const metrics = model.metrics.length ? `<div class="absolute-voice-proof-trends__metrics">${model.metrics.map((metric) => `<article>
1773
- <span>${escapeHtml5(metric.label)}</span>
1774
- <strong>${escapeHtml5(metric.value)}</strong>
1775
- </article>`).join("")}</div>` : `<p class="absolute-voice-proof-trends__empty">${model.error ? escapeHtml5(model.error) : "Run the sustained proof trends script to populate evidence."}</p>`;
1776
- const links = model.links.length ? `<p class="absolute-voice-proof-trends__links">${model.links.map((link) => `<a href="${escapeHtml5(link.href)}">${escapeHtml5(link.label)}</a>`).join("")}</p>` : "";
1777
- return `<section class="absolute-voice-proof-trends absolute-voice-proof-trends--${escapeHtml5(model.status)}">
1929
+ <span>${escapeHtml6(metric.label)}</span>
1930
+ <strong>${escapeHtml6(metric.value)}</strong>
1931
+ </article>`).join("")}</div>` : `<p class="absolute-voice-proof-trends__empty">${model.error ? escapeHtml6(model.error) : "Run the sustained proof trends script to populate evidence."}</p>`;
1932
+ const links = model.links.length ? `<p class="absolute-voice-proof-trends__links">${model.links.map((link) => `<a href="${escapeHtml6(link.href)}">${escapeHtml6(link.label)}</a>`).join("")}</p>` : "";
1933
+ return `<section class="absolute-voice-proof-trends absolute-voice-proof-trends--${escapeHtml6(model.status)}">
1778
1934
  <header class="absolute-voice-proof-trends__header">
1779
- <span class="absolute-voice-proof-trends__eyebrow">${escapeHtml5(model.title)}</span>
1780
- <strong class="absolute-voice-proof-trends__label">${escapeHtml5(model.label)}</strong>
1935
+ <span class="absolute-voice-proof-trends__eyebrow">${escapeHtml6(model.title)}</span>
1936
+ <strong class="absolute-voice-proof-trends__label">${escapeHtml6(model.label)}</strong>
1781
1937
  </header>
1782
- <p class="absolute-voice-proof-trends__description">${escapeHtml5(model.description)}</p>
1938
+ <p class="absolute-voice-proof-trends__description">${escapeHtml6(model.description)}</p>
1783
1939
  ${metrics}
1784
1940
  ${links}
1785
- ${model.error ? `<p class="absolute-voice-proof-trends__error">${escapeHtml5(model.error)}</p>` : ""}
1941
+ ${model.error ? `<p class="absolute-voice-proof-trends__error">${escapeHtml6(model.error)}</p>` : ""}
1786
1942
  </section>`;
1787
1943
  };
1788
1944
  var getVoiceProofTrendsCSS = () => `.absolute-voice-proof-trends{border:1px solid #99f6e4;border-radius:20px;background:#f0fdfa;color:#0f172a;padding:18px;box-shadow:0 18px 40px rgba(13,148,136,.12);font-family:inherit}.absolute-voice-proof-trends--warning,.absolute-voice-proof-trends--error{border-color:#f2a7a7;background:#fff7f4}.absolute-voice-proof-trends__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-proof-trends__eyebrow{color:#0f766e;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-proof-trends__label{font-size:24px;line-height:1}.absolute-voice-proof-trends__description,.absolute-voice-proof-trends__empty{color:#475569}.absolute-voice-proof-trends__metrics{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));margin-top:14px}.absolute-voice-proof-trends__metrics article{background:#fff;border:1px solid #ccfbf1;border-radius:16px;padding:12px}.absolute-voice-proof-trends__metrics span{color:#64748b;display:block;font-size:12px;font-weight:800;text-transform:uppercase}.absolute-voice-proof-trends__metrics strong{display:block;font-size:20px;margin-top:4px}.absolute-voice-proof-trends__links{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 0}.absolute-voice-proof-trends__links a{border:1px solid #99f6e4;border-radius:999px;color:#0f766e;font-weight:800;padding:6px 10px;text-decoration:none}.absolute-voice-proof-trends__error{color:#9f1239;font-weight:700}`;
@@ -1967,7 +2123,7 @@ var DEFAULT_LINKS3 = [
1967
2123
  { href: "/production-readiness", label: "Readiness page" },
1968
2124
  { href: "/voice/slo-readiness-thresholds", label: "Gate thresholds" }
1969
2125
  ];
1970
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2126
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1971
2127
  var formatExplanationValue = (value, unit) => {
1972
2128
  if (value === undefined || value === null) {
1973
2129
  return "n/a";
@@ -2008,23 +2164,23 @@ var createVoiceReadinessFailuresViewModel = (snapshot, options = {}) => {
2008
2164
  };
2009
2165
  var renderVoiceReadinessFailuresHTML = (snapshot, options = {}) => {
2010
2166
  const model = createVoiceReadinessFailuresViewModel(snapshot, options);
2011
- const failures = model.failures.length ? `<div class="absolute-voice-readiness-failures__items">${model.failures.map((failure) => `<article class="absolute-voice-readiness-failures__item absolute-voice-readiness-failures__item--${escapeHtml6(failure.status)}">
2012
- <span>${escapeHtml6(failure.status.toUpperCase())}</span>
2013
- <strong>${escapeHtml6(failure.label)}</strong>
2014
- <p>Observed ${escapeHtml6(failure.observed)} against ${escapeHtml6(failure.thresholdLabel)} ${escapeHtml6(failure.threshold)}.</p>
2015
- <p>${escapeHtml6(failure.remediation)}</p>
2016
- <p class="absolute-voice-readiness-failures__links">${failure.evidenceHref ? `<a href="${escapeHtml6(failure.evidenceHref)}">Evidence</a>` : ""}${failure.sourceHref ? `<a href="${escapeHtml6(failure.sourceHref)}">Threshold source</a>` : ""}</p>
2017
- </article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ? escapeHtml6(model.error) : "No calibrated readiness gate explanations are open."}</p>`;
2018
- const links = model.links.length ? `<p class="absolute-voice-readiness-failures__links">${model.links.map((link) => `<a href="${escapeHtml6(link.href)}">${escapeHtml6(link.label)}</a>`).join("")}</p>` : "";
2019
- return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${escapeHtml6(model.status)}">
2167
+ const failures = model.failures.length ? `<div class="absolute-voice-readiness-failures__items">${model.failures.map((failure) => `<article class="absolute-voice-readiness-failures__item absolute-voice-readiness-failures__item--${escapeHtml7(failure.status)}">
2168
+ <span>${escapeHtml7(failure.status.toUpperCase())}</span>
2169
+ <strong>${escapeHtml7(failure.label)}</strong>
2170
+ <p>Observed ${escapeHtml7(failure.observed)} against ${escapeHtml7(failure.thresholdLabel)} ${escapeHtml7(failure.threshold)}.</p>
2171
+ <p>${escapeHtml7(failure.remediation)}</p>
2172
+ <p class="absolute-voice-readiness-failures__links">${failure.evidenceHref ? `<a href="${escapeHtml7(failure.evidenceHref)}">Evidence</a>` : ""}${failure.sourceHref ? `<a href="${escapeHtml7(failure.sourceHref)}">Threshold source</a>` : ""}</p>
2173
+ </article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ? escapeHtml7(model.error) : "No calibrated readiness gate explanations are open."}</p>`;
2174
+ const links = model.links.length ? `<p class="absolute-voice-readiness-failures__links">${model.links.map((link) => `<a href="${escapeHtml7(link.href)}">${escapeHtml7(link.label)}</a>`).join("")}</p>` : "";
2175
+ return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${escapeHtml7(model.status)}">
2020
2176
  <header class="absolute-voice-readiness-failures__header">
2021
- <span class="absolute-voice-readiness-failures__eyebrow">${escapeHtml6(model.title)}</span>
2022
- <strong class="absolute-voice-readiness-failures__label">${escapeHtml6(model.label)}</strong>
2177
+ <span class="absolute-voice-readiness-failures__eyebrow">${escapeHtml7(model.title)}</span>
2178
+ <strong class="absolute-voice-readiness-failures__label">${escapeHtml7(model.label)}</strong>
2023
2179
  </header>
2024
- <p class="absolute-voice-readiness-failures__description">${escapeHtml6(model.description)}</p>
2180
+ <p class="absolute-voice-readiness-failures__description">${escapeHtml7(model.description)}</p>
2025
2181
  ${failures}
2026
2182
  ${links}
2027
- ${model.error ? `<p class="absolute-voice-readiness-failures__error">${escapeHtml6(model.error)}</p>` : ""}
2183
+ ${model.error ? `<p class="absolute-voice-readiness-failures__error">${escapeHtml7(model.error)}</p>` : ""}
2028
2184
  </section>`;
2029
2185
  };
2030
2186
  var getVoiceReadinessFailuresCSS = () => `.absolute-voice-readiness-failures{border:1px solid #fed7aa;border-radius:20px;background:#fff7ed;color:#1c1917;padding:18px;box-shadow:0 18px 40px rgba(234,88,12,.12);font-family:inherit}.absolute-voice-readiness-failures--ready{border-color:#86efac;background:#f0fdf4}.absolute-voice-readiness-failures--error{border-color:#fda4af;background:#fff1f2}.absolute-voice-readiness-failures__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-readiness-failures__eyebrow{color:#9a3412;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-readiness-failures__label{font-size:24px;line-height:1}.absolute-voice-readiness-failures__description,.absolute-voice-readiness-failures__empty{color:#57534e}.absolute-voice-readiness-failures__items{display:grid;gap:10px;margin-top:14px}.absolute-voice-readiness-failures__item{background:white;border:1px solid #fed7aa;border-radius:16px;padding:12px}.absolute-voice-readiness-failures__item--fail{border-color:#fb7185}.absolute-voice-readiness-failures__item span{color:#9a3412;display:block;font-size:12px;font-weight:900;text-transform:uppercase}.absolute-voice-readiness-failures__item strong{display:block;font-size:18px;margin-top:4px}.absolute-voice-readiness-failures__item p{margin:.45rem 0 0}.absolute-voice-readiness-failures__links{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 0}.absolute-voice-readiness-failures__links a{border:1px solid #fdba74;border-radius:999px;color:#9a3412;font-weight:800;padding:6px 10px;text-decoration:none}.absolute-voice-readiness-failures__error{color:#9f1239;font-weight:700}`;
@@ -2253,7 +2409,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
2253
2409
  };
2254
2410
 
2255
2411
  // src/client/providerSimulationControlsWidget.ts
2256
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2412
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2257
2413
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
2258
2414
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
2259
2415
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -2273,18 +2429,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
2273
2429
  };
2274
2430
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
2275
2431
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
2276
- const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml7(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml7(provider.provider)} ${escapeHtml7(formatKind(options.kind))} failure</button>`).join("");
2277
- const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml7(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml7(provider.provider)} recovered</button>`).join("");
2432
+ const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml8(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml8(provider.provider)} ${escapeHtml8(formatKind(options.kind))} failure</button>`).join("");
2433
+ const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml8(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml8(provider.provider)} recovered</button>`).join("");
2278
2434
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
2279
2435
  <header class="absolute-voice-provider-simulation__header">
2280
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml7(model.title)}</span>
2281
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml7(model.label)}</strong>
2436
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml8(model.title)}</span>
2437
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml8(model.label)}</strong>
2282
2438
  </header>
2283
- <p class="absolute-voice-provider-simulation__description">${escapeHtml7(model.description)}</p>
2284
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml7(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
2439
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml8(model.description)}</p>
2440
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml8(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
2285
2441
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
2286
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml7(snapshot.error)}</p>` : ""}
2287
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml7(model.resultText)}</pre>` : ""}
2442
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml8(snapshot.error)}</p>` : ""}
2443
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml8(model.resultText)}</pre>` : ""}
2288
2444
  </section>`;
2289
2445
  };
2290
2446
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -2544,7 +2700,7 @@ var useVoiceProviderCapabilities = (path = "/api/provider-capabilities", options
2544
2700
  // src/client/providerCapabilitiesWidget.ts
2545
2701
  var DEFAULT_TITLE7 = "Provider Capabilities";
2546
2702
  var DEFAULT_DESCRIPTION7 = "Configured, selected, and healthy voice providers for this deployment.";
2547
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2703
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2548
2704
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2549
2705
  var formatKind2 = (kind) => kind.toUpperCase();
2550
2706
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -2599,25 +2755,25 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
2599
2755
  };
2600
2756
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
2601
2757
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
2602
- const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml8(capability.status)}">
2758
+ const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml9(capability.status)}">
2603
2759
  <header>
2604
- <strong>${escapeHtml8(capability.label)}</strong>
2605
- <span>${escapeHtml8(formatStatus2(capability.status))}</span>
2760
+ <strong>${escapeHtml9(capability.label)}</strong>
2761
+ <span>${escapeHtml9(formatStatus2(capability.status))}</span>
2606
2762
  </header>
2607
- <p>${escapeHtml8(capability.detail)}</p>
2763
+ <p>${escapeHtml9(capability.detail)}</p>
2608
2764
  <dl>${capability.rows.map((row) => `<div>
2609
- <dt>${escapeHtml8(row.label)}</dt>
2610
- <dd>${escapeHtml8(row.value)}</dd>
2765
+ <dt>${escapeHtml9(row.label)}</dt>
2766
+ <dd>${escapeHtml9(row.value)}</dd>
2611
2767
  </div>`).join("")}</dl>
2612
2768
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
2613
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml8(model.status)}">
2769
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml9(model.status)}">
2614
2770
  <header class="absolute-voice-provider-capabilities__header">
2615
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml8(model.title)}</span>
2616
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml8(model.label)}</strong>
2771
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml9(model.title)}</span>
2772
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml9(model.label)}</strong>
2617
2773
  </header>
2618
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml8(model.description)}</p>
2774
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml9(model.description)}</p>
2619
2775
  ${capabilities}
2620
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml8(model.error)}</p>` : ""}
2776
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml9(model.error)}</p>` : ""}
2621
2777
  </section>`;
2622
2778
  };
2623
2779
  var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
@@ -2835,7 +2991,7 @@ var useVoiceProviderContracts = (path = "/api/provider-contracts", options = {})
2835
2991
  // src/client/providerContractsWidget.ts
2836
2992
  var DEFAULT_TITLE8 = "Provider Contracts";
2837
2993
  var DEFAULT_DESCRIPTION8 = "Production contract coverage for provider env, latency, fallback, streaming, and capabilities.";
2838
- var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2994
+ var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2839
2995
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2840
2996
  var formatStatus3 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
2841
2997
  var contractDetail = (row) => {
@@ -2879,26 +3035,26 @@ var createVoiceProviderContractsViewModel = (snapshot, options = {}) => {
2879
3035
  };
2880
3036
  var renderVoiceProviderContractsHTML = (snapshot, options = {}) => {
2881
3037
  const model = createVoiceProviderContractsViewModel(snapshot, options);
2882
- const rows = model.rows.length ? `<div class="absolute-voice-provider-contracts__rows">${model.rows.map((row) => `<article class="absolute-voice-provider-contracts__row absolute-voice-provider-contracts__row--${escapeHtml9(row.status)}">
3038
+ const rows = model.rows.length ? `<div class="absolute-voice-provider-contracts__rows">${model.rows.map((row) => `<article class="absolute-voice-provider-contracts__row absolute-voice-provider-contracts__row--${escapeHtml10(row.status)}">
2883
3039
  <header>
2884
- <strong>${escapeHtml9(row.label)}</strong>
2885
- <span>${escapeHtml9(formatStatus3(row.status))}</span>
3040
+ <strong>${escapeHtml10(row.label)}</strong>
3041
+ <span>${escapeHtml10(formatStatus3(row.status))}</span>
2886
3042
  </header>
2887
- <p>${escapeHtml9(row.detail)}</p>
2888
- ${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${escapeHtml9(remediation.href)}">${escapeHtml9(remediation.label)}</a>` : `<strong>${escapeHtml9(remediation.label)}</strong>`}<span>${escapeHtml9(remediation.detail)}</span></li>`).join("")}</ul>` : ""}
3043
+ <p>${escapeHtml10(row.detail)}</p>
3044
+ ${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${escapeHtml10(remediation.href)}">${escapeHtml10(remediation.label)}</a>` : `<strong>${escapeHtml10(remediation.label)}</strong>`}<span>${escapeHtml10(remediation.detail)}</span></li>`).join("")}</ul>` : ""}
2889
3045
  <dl>${row.rows.map((item) => `<div>
2890
- <dt>${escapeHtml9(item.label)}</dt>
2891
- <dd>${escapeHtml9(item.value)}</dd>
3046
+ <dt>${escapeHtml10(item.label)}</dt>
3047
+ <dd>${escapeHtml10(item.value)}</dd>
2892
3048
  </div>`).join("")}</dl>
2893
3049
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-contracts__empty">Configure provider contracts to see production coverage.</p>';
2894
- return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml9(model.status)}">
3050
+ return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml10(model.status)}">
2895
3051
  <header class="absolute-voice-provider-contracts__header">
2896
- <span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml9(model.title)}</span>
2897
- <strong class="absolute-voice-provider-contracts__label">${escapeHtml9(model.label)}</strong>
3052
+ <span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml10(model.title)}</span>
3053
+ <strong class="absolute-voice-provider-contracts__label">${escapeHtml10(model.label)}</strong>
2898
3054
  </header>
2899
- <p class="absolute-voice-provider-contracts__description">${escapeHtml9(model.description)}</p>
3055
+ <p class="absolute-voice-provider-contracts__description">${escapeHtml10(model.description)}</p>
2900
3056
  ${rows}
2901
- ${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml9(model.error)}</p>` : ""}
3057
+ ${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml10(model.error)}</p>` : ""}
2902
3058
  </section>`;
2903
3059
  };
2904
3060
  var getVoiceProviderContractsCSS = () => `.absolute-voice-provider-contracts{border:1px solid #b8dcc7;border-radius:20px;background:#f7fff9;color:#09140d;padding:18px;box-shadow:0 18px 40px rgba(21,83,45,.12);font-family:inherit}.absolute-voice-provider-contracts--error,.absolute-voice-provider-contracts--warning{border-color:#f2a7a7;background:#fff7f4}.absolute-voice-provider-contracts__header,.absolute-voice-provider-contracts__row header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-contracts__eyebrow{color:#166534;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-contracts__label{font-size:24px;line-height:1}.absolute-voice-provider-contracts__description,.absolute-voice-provider-contracts__row p,.absolute-voice-provider-contracts__row dt,.absolute-voice-provider-contracts__empty{color:#405448}.absolute-voice-provider-contracts__rows{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-contracts__row{background:#fff;border:1px solid #d6eadb;border-radius:16px;padding:14px}.absolute-voice-provider-contracts__row--pass{border-color:#86efac}.absolute-voice-provider-contracts__row--warn,.absolute-voice-provider-contracts__row--fail{border-color:#f2a7a7}.absolute-voice-provider-contracts__row p{margin:10px 0}.absolute-voice-provider-contracts__remediations{display:grid;gap:8px;list-style:none;margin:0 0 10px;padding:0}.absolute-voice-provider-contracts__remediations li{background:#fff7ed;border:1px solid #fed7aa;border-radius:12px;display:grid;gap:3px;padding:8px}.absolute-voice-provider-contracts__remediations a,.absolute-voice-provider-contracts__remediations strong{color:#9a3412}.absolute-voice-provider-contracts__remediations span{color:#7c2d12}.absolute-voice-provider-contracts__row dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-contracts__row div{background:#f7fff9;border:1px solid #d6eadb;border-radius:12px;padding:8px}.absolute-voice-provider-contracts__row dt{font-size:12px}.absolute-voice-provider-contracts__row dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-contracts__error{color:#9f1239;font-weight:700}`;
@@ -3137,7 +3293,7 @@ var useVoiceProviderStatus = (path = "/api/provider-status", options = {}) => {
3137
3293
  // src/client/providerStatusWidget.ts
3138
3294
  var DEFAULT_TITLE9 = "Voice Providers";
3139
3295
  var DEFAULT_DESCRIPTION9 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
3140
- var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3296
+ var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3141
3297
  var formatProvider3 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
3142
3298
  var formatStatus4 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
3143
3299
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -3193,25 +3349,25 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
3193
3349
  };
3194
3350
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
3195
3351
  const model = createVoiceProviderStatusViewModel(snapshot, options);
3196
- const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml10(provider.status)}">
3352
+ const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml11(provider.status)}">
3197
3353
  <header>
3198
- <strong>${escapeHtml10(provider.label)}</strong>
3199
- <span>${escapeHtml10(formatStatus4(provider.status))}</span>
3354
+ <strong>${escapeHtml11(provider.label)}</strong>
3355
+ <span>${escapeHtml11(formatStatus4(provider.status))}</span>
3200
3356
  </header>
3201
- <p>${escapeHtml10(provider.detail)}</p>
3357
+ <p>${escapeHtml11(provider.detail)}</p>
3202
3358
  <dl>${provider.rows.map((row) => `<div>
3203
- <dt>${escapeHtml10(row.label)}</dt>
3204
- <dd>${escapeHtml10(row.value)}</dd>
3359
+ <dt>${escapeHtml11(row.label)}</dt>
3360
+ <dd>${escapeHtml11(row.value)}</dd>
3205
3361
  </div>`).join("")}</dl>
3206
3362
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
3207
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml10(model.status)}">
3363
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml11(model.status)}">
3208
3364
  <header class="absolute-voice-provider-status__header">
3209
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml10(model.title)}</span>
3210
- <strong class="absolute-voice-provider-status__label">${escapeHtml10(model.label)}</strong>
3365
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml11(model.title)}</span>
3366
+ <strong class="absolute-voice-provider-status__label">${escapeHtml11(model.label)}</strong>
3211
3367
  </header>
3212
- <p class="absolute-voice-provider-status__description">${escapeHtml10(model.description)}</p>
3368
+ <p class="absolute-voice-provider-status__description">${escapeHtml11(model.description)}</p>
3213
3369
  ${providers}
3214
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml10(model.error)}</p>` : ""}
3370
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml11(model.error)}</p>` : ""}
3215
3371
  </section>`;
3216
3372
  };
3217
3373
  var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
@@ -3434,7 +3590,7 @@ var useVoiceRoutingStatus = (path = "/api/routing/latest", options = {}) => {
3434
3590
  // src/client/routingStatusWidget.ts
3435
3591
  var DEFAULT_TITLE10 = "Voice Routing";
3436
3592
  var DEFAULT_DESCRIPTION10 = "Latest provider routing decision from the self-hosted trace store.";
3437
- var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3593
+ var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3438
3594
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
3439
3595
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
3440
3596
  const decision = snapshot.decision;
@@ -3471,17 +3627,17 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
3471
3627
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
3472
3628
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
3473
3629
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
3474
- <span>${escapeHtml11(row.label)}</span>
3475
- <strong>${escapeHtml11(row.value)}</strong>
3630
+ <span>${escapeHtml12(row.label)}</span>
3631
+ <strong>${escapeHtml12(row.value)}</strong>
3476
3632
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
3477
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml11(model.status)}">
3633
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml12(model.status)}">
3478
3634
  <header class="absolute-voice-routing-status__header">
3479
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml11(model.title)}</span>
3480
- <strong class="absolute-voice-routing-status__label">${escapeHtml11(model.label)}</strong>
3635
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml12(model.title)}</span>
3636
+ <strong class="absolute-voice-routing-status__label">${escapeHtml12(model.label)}</strong>
3481
3637
  </header>
3482
- <p class="absolute-voice-routing-status__description">${escapeHtml11(model.description)}</p>
3638
+ <p class="absolute-voice-routing-status__description">${escapeHtml12(model.description)}</p>
3483
3639
  ${rows}
3484
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml11(model.error)}</p>` : ""}
3640
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml12(model.error)}</p>` : ""}
3485
3641
  </section>`;
3486
3642
  };
3487
3643
  var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
@@ -3661,7 +3817,7 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
3661
3817
  // src/client/traceTimelineWidget.ts
3662
3818
  var DEFAULT_TITLE11 = "Voice Traces";
3663
3819
  var DEFAULT_DESCRIPTION11 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
3664
- var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3820
+ var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3665
3821
  var formatMs2 = (value) => typeof value === "number" ? `${value}ms` : "n/a";
3666
3822
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
3667
3823
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -3691,27 +3847,27 @@ var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
3691
3847
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
3692
3848
  const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => {
3693
3849
  const supportLinks = [
3694
- `<a href="${escapeHtml12(session.detailHref)}">Open timeline</a>`,
3695
- session.operationsRecordHref ? `<a href="${escapeHtml12(session.operationsRecordHref)}">Open operations record</a>` : undefined,
3696
- session.incidentBundleHref ? `<a href="${escapeHtml12(session.incidentBundleHref)}">Export incident bundle</a>` : undefined
3850
+ `<a href="${escapeHtml13(session.detailHref)}">Open timeline</a>`,
3851
+ session.operationsRecordHref ? `<a href="${escapeHtml13(session.operationsRecordHref)}">Open operations record</a>` : undefined,
3852
+ session.incidentBundleHref ? `<a href="${escapeHtml13(session.incidentBundleHref)}">Export incident bundle</a>` : undefined
3697
3853
  ].filter(Boolean).join("");
3698
- return `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml12(session.status)}">
3854
+ return `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml13(session.status)}">
3699
3855
  <header>
3700
- <strong>${escapeHtml12(session.sessionId)}</strong>
3701
- <span>${escapeHtml12(session.status)}</span>
3856
+ <strong>${escapeHtml13(session.sessionId)}</strong>
3857
+ <span>${escapeHtml13(session.status)}</span>
3702
3858
  </header>
3703
- <p>${escapeHtml12(session.label)} \xB7 ${escapeHtml12(session.durationLabel)} \xB7 ${escapeHtml12(session.providerLabel)}</p>
3859
+ <p>${escapeHtml13(session.label)} \xB7 ${escapeHtml13(session.durationLabel)} \xB7 ${escapeHtml13(session.providerLabel)}</p>
3704
3860
  <p class="absolute-voice-trace-timeline__actions">${supportLinks}</p>
3705
3861
  </article>`;
3706
3862
  }).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
3707
- return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml12(model.status)}">
3863
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml13(model.status)}">
3708
3864
  <header class="absolute-voice-trace-timeline__header">
3709
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml12(model.title)}</span>
3710
- <strong class="absolute-voice-trace-timeline__label">${escapeHtml12(model.label)}</strong>
3865
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml13(model.title)}</span>
3866
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml13(model.label)}</strong>
3711
3867
  </header>
3712
- <p class="absolute-voice-trace-timeline__description">${escapeHtml12(model.description)}</p>
3868
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml13(model.description)}</p>
3713
3869
  ${sessions}
3714
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml12(model.error)}</p>` : ""}
3870
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml13(model.error)}</p>` : ""}
3715
3871
  </section>`;
3716
3872
  };
3717
3873
  var getVoiceTraceTimelineCSS = () => `.absolute-voice-trace-timeline{border:1px solid #bad7d3;border-radius:20px;background:#f3fffb;color:#09201c;padding:18px;box-shadow:0 18px 40px rgba(9,32,28,.12);font-family:inherit}.absolute-voice-trace-timeline--error,.absolute-voice-trace-timeline--failed{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-trace-timeline--warning{border-color:#fbbf24;background:#fffaf0}.absolute-voice-trace-timeline__header,.absolute-voice-trace-timeline__session header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-trace-timeline__eyebrow{color:#17665b;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-trace-timeline__label{font-size:24px;line-height:1}.absolute-voice-trace-timeline__description,.absolute-voice-trace-timeline__session p,.absolute-voice-trace-timeline__empty{color:#35544f}.absolute-voice-trace-timeline__sessions{display:grid;gap:12px;margin-top:14px}.absolute-voice-trace-timeline__session{background:#fff;border:1px solid #cfe7e2;border-radius:16px;padding:14px}.absolute-voice-trace-timeline__session--failed{border-color:#f2a7a7}.absolute-voice-trace-timeline__session--warning{border-color:#fbbf24}.absolute-voice-trace-timeline__session p{margin:10px 0}.absolute-voice-trace-timeline__actions{display:flex;flex-wrap:wrap;gap:10px}.absolute-voice-trace-timeline__session a{color:#0f766e;font-weight:800}.absolute-voice-trace-timeline__empty{margin:14px 0 0}.absolute-voice-trace-timeline__error{color:#9f1239;font-weight:700}`;
@@ -3963,7 +4119,7 @@ var useVoiceAgentSquadStatus = (path = "/api/voice-traces", options = {}) => {
3963
4119
  // src/client/agentSquadStatusWidget.ts
3964
4120
  var DEFAULT_TITLE12 = "Voice Agent Squad";
3965
4121
  var DEFAULT_DESCRIPTION12 = "Current specialist and recent handoffs from your self-hosted voice traces.";
3966
- var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4122
+ var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3967
4123
  var labelFor = (current) => {
3968
4124
  if (!current)
3969
4125
  return "Waiting for specialist activity";
@@ -3990,24 +4146,24 @@ var renderVoiceAgentSquadStatusHTML = (snapshot, options = {}) => {
3990
4146
  const model = createVoiceAgentSquadStatusViewModel(snapshot, options);
3991
4147
  const current = model.current;
3992
4148
  const rows = model.sessions.length ? model.sessions.slice(0, 5).map((session) => `<li>
3993
- <span>${escapeHtml13(session.sessionId)}</span>
3994
- <strong>${escapeHtml13(session.targetAgentId ?? "none")}</strong>
3995
- <em>${escapeHtml13(session.status)}</em>
3996
- ${session.summary || session.reason ? `<p>${escapeHtml13(session.summary ?? session.reason ?? "")}</p>` : ""}
4149
+ <span>${escapeHtml14(session.sessionId)}</span>
4150
+ <strong>${escapeHtml14(session.targetAgentId ?? "none")}</strong>
4151
+ <em>${escapeHtml14(session.status)}</em>
4152
+ ${session.summary || session.reason ? `<p>${escapeHtml14(session.summary ?? session.reason ?? "")}</p>` : ""}
3997
4153
  </li>`).join("") : "<li><span>No squad traces yet.</span><strong>Waiting</strong></li>";
3998
4154
  return `<section class="absolute-voice-agent-squad-status">
3999
4155
  <header>
4000
- <span>${escapeHtml13(model.title)}</span>
4001
- <strong>${escapeHtml13(model.label)}</strong>
4156
+ <span>${escapeHtml14(model.title)}</span>
4157
+ <strong>${escapeHtml14(model.label)}</strong>
4002
4158
  </header>
4003
- <p>${escapeHtml13(model.description)}</p>
4159
+ <p>${escapeHtml14(model.description)}</p>
4004
4160
  <div>
4005
- <span>Session</span><strong>${escapeHtml13(current?.sessionId ?? "n/a")}</strong>
4006
- <span>From</span><strong>${escapeHtml13(current?.fromAgentId ?? "n/a")}</strong>
4007
- <span>Status</span><strong>${escapeHtml13(current?.status ?? "idle")}</strong>
4161
+ <span>Session</span><strong>${escapeHtml14(current?.sessionId ?? "n/a")}</strong>
4162
+ <span>From</span><strong>${escapeHtml14(current?.fromAgentId ?? "n/a")}</strong>
4163
+ <span>Status</span><strong>${escapeHtml14(current?.status ?? "idle")}</strong>
4008
4164
  </div>
4009
4165
  <ul>${rows}</ul>
4010
- ${model.error ? `<p class="absolute-voice-agent-squad-status__error">${escapeHtml13(model.error)}</p>` : ""}
4166
+ ${model.error ? `<p class="absolute-voice-agent-squad-status__error">${escapeHtml14(model.error)}</p>` : ""}
4011
4167
  </section>`;
4012
4168
  };
4013
4169
  var getVoiceAgentSquadStatusCSS = () => `.absolute-voice-agent-squad-status{border:1px solid #38bdf866;border-radius:20px;background:#0f172a;color:#f8fafc;padding:18px;font-family:inherit}.absolute-voice-agent-squad-status header{display:grid;gap:4px}.absolute-voice-agent-squad-status header span{color:#7dd3fc;font-size:12px;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-agent-squad-status header strong{font-size:20px}.absolute-voice-agent-squad-status p{color:#cbd5e1}.absolute-voice-agent-squad-status div{display:grid;gap:6px;grid-template-columns:max-content 1fr;margin:14px 0}.absolute-voice-agent-squad-status div span{color:#94a3b8}.absolute-voice-agent-squad-status ul{display:grid;gap:8px;list-style:none;margin:0;padding:0}.absolute-voice-agent-squad-status li{background:#020617;border:1px solid #1e293b;border-radius:14px;padding:10px}.absolute-voice-agent-squad-status li span{color:#94a3b8;display:block;font-size:12px}.absolute-voice-agent-squad-status li strong{display:block}.absolute-voice-agent-squad-status li em{color:#7dd3fc;font-style:normal}.absolute-voice-agent-squad-status__error{color:#fecaca;font-weight:800}`;
@@ -4244,7 +4400,7 @@ var useVoiceTurnLatency = (path = "/api/turn-latency", options = {}) => {
4244
4400
  var DEFAULT_TITLE13 = "Turn Latency";
4245
4401
  var DEFAULT_DESCRIPTION13 = "Per-turn timing from first transcript to commit and assistant response start.";
4246
4402
  var DEFAULT_PROOF_LABEL = "Run latency proof";
4247
- var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4403
+ var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4248
4404
  var formatMs3 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
4249
4405
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
4250
4406
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -4272,25 +4428,25 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
4272
4428
  };
4273
4429
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
4274
4430
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
4275
- const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml14(turn.status)}">
4431
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml15(turn.status)}">
4276
4432
  <header>
4277
- <strong>${escapeHtml14(turn.label)}</strong>
4278
- <span>${escapeHtml14(turn.status)}</span>
4433
+ <strong>${escapeHtml15(turn.label)}</strong>
4434
+ <span>${escapeHtml15(turn.status)}</span>
4279
4435
  </header>
4280
4436
  <dl>${turn.rows.map((row) => `<div>
4281
- <dt>${escapeHtml14(row.label)}</dt>
4282
- <dd>${escapeHtml14(row.value)}</dd>
4437
+ <dt>${escapeHtml15(row.label)}</dt>
4438
+ <dd>${escapeHtml15(row.value)}</dd>
4283
4439
  </div>`).join("")}</dl>
4284
4440
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
4285
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml14(model.status)}">
4441
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml15(model.status)}">
4286
4442
  <header class="absolute-voice-turn-latency__header">
4287
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml14(model.title)}</span>
4288
- <strong class="absolute-voice-turn-latency__label">${escapeHtml14(model.label)}</strong>
4443
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml15(model.title)}</span>
4444
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml15(model.label)}</strong>
4289
4445
  </header>
4290
- <p class="absolute-voice-turn-latency__description">${escapeHtml14(model.description)}</p>
4291
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml14(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
4446
+ <p class="absolute-voice-turn-latency__description">${escapeHtml15(model.description)}</p>
4447
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml15(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
4292
4448
  ${turns}
4293
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml14(model.error)}</p>` : ""}
4449
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml15(model.error)}</p>` : ""}
4294
4450
  </section>`;
4295
4451
  };
4296
4452
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -4526,7 +4682,7 @@ var useVoiceTurnQuality = (path = "/api/turn-quality", options = {}) => {
4526
4682
  // src/client/turnQualityWidget.ts
4527
4683
  var DEFAULT_TITLE14 = "Turn Quality";
4528
4684
  var DEFAULT_DESCRIPTION14 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
4529
- var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4685
+ var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4530
4686
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
4531
4687
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
4532
4688
  var getTurnDetail = (turn) => {
@@ -4576,25 +4732,25 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
4576
4732
  };
4577
4733
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
4578
4734
  const model = createVoiceTurnQualityViewModel(snapshot, options);
4579
- const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml15(turn.status)}">
4735
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml16(turn.status)}">
4580
4736
  <header>
4581
- <strong>${escapeHtml15(turn.label)}</strong>
4582
- <span>${escapeHtml15(turn.status)}</span>
4737
+ <strong>${escapeHtml16(turn.label)}</strong>
4738
+ <span>${escapeHtml16(turn.status)}</span>
4583
4739
  </header>
4584
- <p>${escapeHtml15(turn.detail)}</p>
4740
+ <p>${escapeHtml16(turn.detail)}</p>
4585
4741
  <dl>${turn.rows.map((row) => `<div>
4586
- <dt>${escapeHtml15(row.label)}</dt>
4587
- <dd>${escapeHtml15(row.value)}</dd>
4742
+ <dt>${escapeHtml16(row.label)}</dt>
4743
+ <dd>${escapeHtml16(row.value)}</dd>
4588
4744
  </div>`).join("")}</dl>
4589
4745
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
4590
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml15(model.status)}">
4746
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml16(model.status)}">
4591
4747
  <header class="absolute-voice-turn-quality__header">
4592
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml15(model.title)}</span>
4593
- <strong class="absolute-voice-turn-quality__label">${escapeHtml15(model.label)}</strong>
4748
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml16(model.title)}</span>
4749
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml16(model.label)}</strong>
4594
4750
  </header>
4595
- <p class="absolute-voice-turn-quality__description">${escapeHtml15(model.description)}</p>
4751
+ <p class="absolute-voice-turn-quality__description">${escapeHtml16(model.description)}</p>
4596
4752
  ${turns}
4597
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml15(model.error)}</p>` : ""}
4753
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml16(model.error)}</p>` : ""}
4598
4754
  </section>`;
4599
4755
  };
4600
4756
  var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;