@absolutejs/voice 0.0.22-beta.333 → 0.0.22-beta.335
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.js +433 -168
- package/dist/index.d.ts +2 -2
- package/dist/index.js +555 -286
- package/dist/proofTrends.d.ts +107 -0
- package/dist/react/index.js +393 -128
- package/dist/vue/index.js +368 -103
- package/package.json +1 -1
package/dist/vue/index.js
CHANGED
|
@@ -1490,7 +1490,7 @@ var maxNumber = (values) => {
|
|
|
1490
1490
|
return finite.length > 0 ? Math.max(...finite) : undefined;
|
|
1491
1491
|
};
|
|
1492
1492
|
var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
|
|
1493
|
-
var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms;
|
|
1493
|
+
var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
|
|
1494
1494
|
var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
|
|
1495
1495
|
var readRuntimeChannelMetric = (report, key) => {
|
|
1496
1496
|
const summaryValue = report.summary.runtimeChannel?.[key];
|
|
@@ -1508,6 +1508,91 @@ var readProofTrendRuntimeChannel = (report) => ({
|
|
|
1508
1508
|
samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
|
|
1509
1509
|
status: report.summary.runtimeChannel?.status
|
|
1510
1510
|
});
|
|
1511
|
+
var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
|
|
1512
|
+
var providerSortScore = (provider) => [
|
|
1513
|
+
recommendationStatusRank[provider.status],
|
|
1514
|
+
provider.p95Ms ?? Number.POSITIVE_INFINITY,
|
|
1515
|
+
provider.averageMs ?? Number.POSITIVE_INFINITY,
|
|
1516
|
+
provider.samples === undefined ? Number.POSITIVE_INFINITY : -provider.samples,
|
|
1517
|
+
provider.id
|
|
1518
|
+
];
|
|
1519
|
+
var compareProviders = (left, right) => {
|
|
1520
|
+
const leftScore = providerSortScore(left);
|
|
1521
|
+
const rightScore = providerSortScore(right);
|
|
1522
|
+
for (let index = 0;index < leftScore.length; index += 1) {
|
|
1523
|
+
const leftValue = leftScore[index];
|
|
1524
|
+
const rightValue = rightScore[index];
|
|
1525
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
1526
|
+
if (leftValue !== rightValue) {
|
|
1527
|
+
return leftValue - rightValue;
|
|
1528
|
+
}
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1531
|
+
const compared = String(leftValue).localeCompare(String(rightValue));
|
|
1532
|
+
if (compared !== 0) {
|
|
1533
|
+
return compared;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return 0;
|
|
1537
|
+
};
|
|
1538
|
+
var summarizeProofTrendProviders = (report, budgetMs) => {
|
|
1539
|
+
const sourceProviders = report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : undefined;
|
|
1540
|
+
const providersById = new Map;
|
|
1541
|
+
if (sourceProviders) {
|
|
1542
|
+
for (const provider of sourceProviders) {
|
|
1543
|
+
if (provider.id) {
|
|
1544
|
+
providersById.set(provider.id, provider);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
} else {
|
|
1548
|
+
for (const cycle of report.cycles) {
|
|
1549
|
+
for (const provider of cycle.providers ?? []) {
|
|
1550
|
+
if (!provider.id) {
|
|
1551
|
+
continue;
|
|
1552
|
+
}
|
|
1553
|
+
const existing = providersById.get(provider.id);
|
|
1554
|
+
providersById.set(provider.id, {
|
|
1555
|
+
averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
|
|
1556
|
+
id: provider.id,
|
|
1557
|
+
label: existing?.label ?? provider.label,
|
|
1558
|
+
p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
|
|
1559
|
+
p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
|
|
1560
|
+
role: existing?.role ?? provider.role,
|
|
1561
|
+
samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
|
|
1562
|
+
status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
return [...providersById.values()].map((provider) => {
|
|
1568
|
+
const status = provider.p95Ms === undefined ? normalizeProviderStatus(provider.status) : withinBudget(provider.p95Ms, budgetMs) ? normalizeProviderStatus(provider.status) === "fail" ? "fail" : "pass" : normalizeProviderStatus(provider.status) === "fail" ? "fail" : "warn";
|
|
1569
|
+
return {
|
|
1570
|
+
averageMs: provider.averageMs,
|
|
1571
|
+
id: provider.id,
|
|
1572
|
+
label: provider.label,
|
|
1573
|
+
nextMove: status === "pass" ? "Eligible for latency-sensitive routing based on sustained proof." : provider.p95Ms === undefined ? "Collect provider-specific latency samples before routing latency-sensitive traffic here." : "Keep as fallback or tune provider/model/runtime budgets before using for latency-sensitive routing.",
|
|
1574
|
+
p50Ms: provider.p50Ms,
|
|
1575
|
+
p95Ms: provider.p95Ms,
|
|
1576
|
+
rank: 0,
|
|
1577
|
+
role: provider.role,
|
|
1578
|
+
samples: provider.samples,
|
|
1579
|
+
status
|
|
1580
|
+
};
|
|
1581
|
+
}).sort(compareProviders).map((provider, index) => ({ ...provider, rank: index + 1 }));
|
|
1582
|
+
};
|
|
1583
|
+
var shouldSwitchProvider = (current, best, options) => {
|
|
1584
|
+
if (!current || !best || current.id === best.id || best.status !== "pass") {
|
|
1585
|
+
return false;
|
|
1586
|
+
}
|
|
1587
|
+
if (current.p95Ms === undefined || best.p95Ms === undefined) {
|
|
1588
|
+
return false;
|
|
1589
|
+
}
|
|
1590
|
+
const minImprovementMs = options.providerSwitchMinImprovementMs ?? 100;
|
|
1591
|
+
const minImprovementRatio = options.providerSwitchMinImprovementRatio ?? 0.1;
|
|
1592
|
+
const improvementMs = current.p95Ms - best.p95Ms;
|
|
1593
|
+
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
1594
|
+
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
1595
|
+
};
|
|
1511
1596
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
1512
1597
|
const issues = [];
|
|
1513
1598
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -1599,6 +1684,186 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
1599
1684
|
}
|
|
1600
1685
|
return assertion;
|
|
1601
1686
|
};
|
|
1687
|
+
var DEFAULT_RECOMMENDATION_BUDGETS = {
|
|
1688
|
+
maxLiveP95Ms: 800,
|
|
1689
|
+
maxProviderP95Ms: 1000,
|
|
1690
|
+
maxRuntimeBackpressureEvents: 0,
|
|
1691
|
+
maxRuntimeFirstAudioLatencyMs: 600,
|
|
1692
|
+
maxRuntimeInterruptionP95Ms: 300,
|
|
1693
|
+
maxRuntimeJitterMs: 30,
|
|
1694
|
+
maxRuntimeTimestampDriftMs: 800,
|
|
1695
|
+
maxTurnP95Ms: 700
|
|
1696
|
+
};
|
|
1697
|
+
var withinBudget = (value, budget) => typeof value === "number" && Number.isFinite(value) && value <= budget;
|
|
1698
|
+
var recommendationStatusRank = {
|
|
1699
|
+
pass: 0,
|
|
1700
|
+
warn: 1,
|
|
1701
|
+
fail: 2
|
|
1702
|
+
};
|
|
1703
|
+
var worstRecommendationStatus = (recommendations) => recommendations.reduce((status, recommendation) => recommendationStatusRank[recommendation.status] > recommendationStatusRank[status] ? recommendation.status : status, "pass");
|
|
1704
|
+
var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
1705
|
+
const budgets = { ...DEFAULT_RECOMMENDATION_BUDGETS, ...options };
|
|
1706
|
+
const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
|
|
1707
|
+
const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
|
|
1708
|
+
const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
|
|
1709
|
+
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
1710
|
+
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
1711
|
+
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
1712
|
+
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
1713
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestProvider, options);
|
|
1714
|
+
const recommendations = [];
|
|
1715
|
+
const issues = [];
|
|
1716
|
+
if (report.ok !== true) {
|
|
1717
|
+
issues.push(`Proof trend report is ${report.status}; recommendations need a fresh passing trend artifact.`);
|
|
1718
|
+
}
|
|
1719
|
+
recommendations.push({
|
|
1720
|
+
evidence: {
|
|
1721
|
+
bestProviderId: bestProvider?.id,
|
|
1722
|
+
bestProviderP95Ms: bestProvider?.p95Ms,
|
|
1723
|
+
budgetMs: budgets.maxProviderP95Ms,
|
|
1724
|
+
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
1725
|
+
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
1726
|
+
providerComparisonCount: providers.length,
|
|
1727
|
+
providerP95Ms: maxProviderP95Ms
|
|
1728
|
+
},
|
|
1729
|
+
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive turns to ${bestProvider?.label ?? bestProvider?.id} for this call profile and keep the current path as fallback.` : bestProvider ? `Use ${bestProvider.label ?? bestProvider.id} as the fastest proven provider path for this call profile and keep collecting sustained comparisons.` : "Collect provider-specific sustained samples before making provider-specific routing decisions." : 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.",
|
|
1730
|
+
providerId: bestProvider?.id,
|
|
1731
|
+
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive routing to ${bestProvider?.label ?? bestProvider?.id}` : bestProvider ? `Prefer ${bestProvider.label ?? bestProvider.id} for this call profile` : "Collect provider-specific latency samples" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
|
|
1732
|
+
role: bestProvider?.role,
|
|
1733
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1734
|
+
surface: "provider-path"
|
|
1735
|
+
});
|
|
1736
|
+
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);
|
|
1737
|
+
recommendations.push({
|
|
1738
|
+
evidence: {
|
|
1739
|
+
backpressureEvents: runtimeChannel.maxBackpressureEvents,
|
|
1740
|
+
firstAudioBudgetMs: budgets.maxRuntimeFirstAudioLatencyMs,
|
|
1741
|
+
firstAudioMs: runtimeChannel.maxFirstAudioLatencyMs,
|
|
1742
|
+
interruptionBudgetMs: budgets.maxRuntimeInterruptionP95Ms,
|
|
1743
|
+
interruptionP95Ms: runtimeChannel.maxInterruptionP95Ms,
|
|
1744
|
+
jitterBudgetMs: budgets.maxRuntimeJitterMs,
|
|
1745
|
+
jitterMs: runtimeChannel.maxJitterMs,
|
|
1746
|
+
samples: runtimeChannel.samples,
|
|
1747
|
+
timestampDriftMs: runtimeChannel.maxTimestampDriftMs
|
|
1748
|
+
},
|
|
1749
|
+
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.",
|
|
1750
|
+
recommendation: runtimePass ? "Keep current runtime channel" : "Tune runtime channel before promotion",
|
|
1751
|
+
status: runtimePass ? "pass" : runtimeChannel.samples === undefined ? "fail" : "warn",
|
|
1752
|
+
surface: "runtime-channel"
|
|
1753
|
+
});
|
|
1754
|
+
recommendations.push({
|
|
1755
|
+
evidence: {
|
|
1756
|
+
budgetMs: budgets.maxLiveP95Ms,
|
|
1757
|
+
liveP95Ms: maxLiveP95Ms
|
|
1758
|
+
},
|
|
1759
|
+
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.",
|
|
1760
|
+
recommendation: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep live-latency settings" : "Tune live-latency path",
|
|
1761
|
+
status: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "pass" : maxLiveP95Ms === undefined ? "fail" : "warn",
|
|
1762
|
+
surface: "live-latency"
|
|
1763
|
+
});
|
|
1764
|
+
recommendations.push({
|
|
1765
|
+
evidence: {
|
|
1766
|
+
budgetMs: budgets.maxTurnP95Ms,
|
|
1767
|
+
turnP95Ms: maxTurnP95Ms
|
|
1768
|
+
},
|
|
1769
|
+
nextMove: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep current turn pipeline defaults." : "Reduce tool/provider latency or split the turn pipeline before promotion.",
|
|
1770
|
+
recommendation: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep turn pipeline" : "Tune turn pipeline",
|
|
1771
|
+
status: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "pass" : maxTurnP95Ms === undefined ? "fail" : "warn",
|
|
1772
|
+
surface: "turn-latency"
|
|
1773
|
+
});
|
|
1774
|
+
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
1775
|
+
return {
|
|
1776
|
+
bestProvider,
|
|
1777
|
+
generatedAt: new Date().toISOString(),
|
|
1778
|
+
issues,
|
|
1779
|
+
ok: status !== "fail",
|
|
1780
|
+
providers,
|
|
1781
|
+
recommendations,
|
|
1782
|
+
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
1783
|
+
status,
|
|
1784
|
+
summary: {
|
|
1785
|
+
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
1786
|
+
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
1787
|
+
providerComparisonCount: providers.length,
|
|
1788
|
+
recommendedActions: recommendations.filter((item) => item.status !== "pass").length,
|
|
1789
|
+
switchRecommended: providerSwitchRecommended
|
|
1790
|
+
}
|
|
1791
|
+
};
|
|
1792
|
+
};
|
|
1793
|
+
var escapeHtml5 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1794
|
+
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
1795
|
+
var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
|
|
1796
|
+
`# ${title}`,
|
|
1797
|
+
"",
|
|
1798
|
+
`- Status: ${report.status}`,
|
|
1799
|
+
`- Source: ${report.source}`,
|
|
1800
|
+
`- Best provider: ${report.bestProvider?.label ?? report.bestProvider?.id ?? "n/a"}`,
|
|
1801
|
+
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
1802
|
+
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
1803
|
+
"",
|
|
1804
|
+
"| Surface | Status | Recommendation | Next move |",
|
|
1805
|
+
"| --- | --- | --- | --- |",
|
|
1806
|
+
...report.recommendations.map((recommendation) => `| ${escapeMarkdown(recommendation.surface)} | ${recommendation.status} | ${escapeMarkdown(recommendation.recommendation)} | ${escapeMarkdown(recommendation.nextMove)} |`),
|
|
1807
|
+
"",
|
|
1808
|
+
"## Provider Comparison",
|
|
1809
|
+
"",
|
|
1810
|
+
"| Rank | Provider | Role | Status | P95 | Samples | Next move |",
|
|
1811
|
+
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
1812
|
+
...report.providers.length ? report.providers.map((provider) => `| ${String(provider.rank)} | ${escapeMarkdown(provider.label ?? provider.id)} | ${escapeMarkdown(provider.role ?? "n/a")} | ${provider.status} | ${provider.p95Ms === undefined ? "n/a" : String(provider.p95Ms)} | ${provider.samples === undefined ? "n/a" : String(provider.samples)} | ${escapeMarkdown(provider.nextMove)} |`) : ["| n/a | n/a | n/a | n/a | n/a | n/a | No provider-specific samples were present. |"],
|
|
1813
|
+
"",
|
|
1814
|
+
"## Issues",
|
|
1815
|
+
"",
|
|
1816
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
1817
|
+
].join(`
|
|
1818
|
+
`);
|
|
1819
|
+
var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
|
|
1820
|
+
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("");
|
|
1821
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
|
|
1822
|
+
const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml5(provider.label ?? provider.id)}</strong><span>${escapeHtml5(provider.role ?? "provider")} \xB7 ${escapeHtml5(provider.status)} \xB7 p95 ${escapeHtml5(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml5(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml5(provider.nextMove)}</small></li>`).join("");
|
|
1823
|
+
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}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${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">Best ${escapeHtml5(report.bestProvider?.label ?? report.bestProvider?.id ?? "n/a")}</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>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
|
|
1824
|
+
};
|
|
1825
|
+
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
1826
|
+
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
|
1827
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/proof-trend-recommendations" : options.htmlPath;
|
|
1828
|
+
const markdownPath = options.markdownPath === undefined ? "/voice/proof-trend-recommendations.md" : options.markdownPath;
|
|
1829
|
+
const title = options.title ?? "Voice Provider Runtime Recommendations";
|
|
1830
|
+
const routes = new Elysia({
|
|
1831
|
+
name: options.name ?? "absolutejs-voice-proof-trend-recommendations"
|
|
1832
|
+
});
|
|
1833
|
+
const loadReport = async () => {
|
|
1834
|
+
const value = options.source !== undefined ? typeof options.source === "function" ? await options.source() : options.source : options.jsonPath ? await readVoiceProofTrendReportFile(options.jsonPath, {
|
|
1835
|
+
maxAgeMs: options.maxAgeMs
|
|
1836
|
+
}) : buildEmptyVoiceProofTrendReport("", options.maxAgeMs);
|
|
1837
|
+
return buildVoiceProofTrendRecommendationReport(normalizeVoiceProofTrendReport(value, {
|
|
1838
|
+
maxAgeMs: options.maxAgeMs,
|
|
1839
|
+
source: options.jsonPath
|
|
1840
|
+
}), options);
|
|
1841
|
+
};
|
|
1842
|
+
routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
|
|
1843
|
+
if (htmlPath !== false) {
|
|
1844
|
+
routes.get(htmlPath, async () => {
|
|
1845
|
+
const report = await loadReport();
|
|
1846
|
+
return new Response(renderVoiceProofTrendRecommendationHTML(report, title), {
|
|
1847
|
+
headers: {
|
|
1848
|
+
"content-type": "text/html; charset=utf-8",
|
|
1849
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
1850
|
+
}
|
|
1851
|
+
});
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
if (markdownPath !== false) {
|
|
1855
|
+
routes.get(markdownPath, async () => {
|
|
1856
|
+
const report = await loadReport();
|
|
1857
|
+
return new Response(renderVoiceProofTrendRecommendationMarkdown(report, title), {
|
|
1858
|
+
headers: {
|
|
1859
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
1860
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
1861
|
+
}
|
|
1862
|
+
});
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
return routes;
|
|
1866
|
+
};
|
|
1602
1867
|
var createVoiceProofTrendRoutes = (options) => {
|
|
1603
1868
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
1604
1869
|
const routes = new Elysia({
|
|
@@ -1720,7 +1985,7 @@ var DEFAULT_LINKS2 = [
|
|
|
1720
1985
|
{ href: "/voice/proof-trends", label: "Trend page" },
|
|
1721
1986
|
{ href: "/api/voice/proof-trends", label: "Trend JSON" }
|
|
1722
1987
|
];
|
|
1723
|
-
var
|
|
1988
|
+
var escapeHtml6 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1724
1989
|
var formatMs = (value) => typeof value === "number" && Number.isFinite(value) ? `${Math.round(value)}ms` : "n/a";
|
|
1725
1990
|
var statusLabel = (report) => {
|
|
1726
1991
|
if (!report) {
|
|
@@ -1770,19 +2035,19 @@ var createVoiceProofTrendsViewModel = (snapshot, options = {}) => {
|
|
|
1770
2035
|
var renderVoiceProofTrendsHTML = (snapshot, options = {}) => {
|
|
1771
2036
|
const model = createVoiceProofTrendsViewModel(snapshot, options);
|
|
1772
2037
|
const metrics = model.metrics.length ? `<div class="absolute-voice-proof-trends__metrics">${model.metrics.map((metric) => `<article>
|
|
1773
|
-
<span>${
|
|
1774
|
-
<strong>${
|
|
1775
|
-
</article>`).join("")}</div>` : `<p class="absolute-voice-proof-trends__empty">${model.error ?
|
|
1776
|
-
const links = model.links.length ? `<p class="absolute-voice-proof-trends__links">${model.links.map((link) => `<a href="${
|
|
1777
|
-
return `<section class="absolute-voice-proof-trends absolute-voice-proof-trends--${
|
|
2038
|
+
<span>${escapeHtml6(metric.label)}</span>
|
|
2039
|
+
<strong>${escapeHtml6(metric.value)}</strong>
|
|
2040
|
+
</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>`;
|
|
2041
|
+
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>` : "";
|
|
2042
|
+
return `<section class="absolute-voice-proof-trends absolute-voice-proof-trends--${escapeHtml6(model.status)}">
|
|
1778
2043
|
<header class="absolute-voice-proof-trends__header">
|
|
1779
|
-
<span class="absolute-voice-proof-trends__eyebrow">${
|
|
1780
|
-
<strong class="absolute-voice-proof-trends__label">${
|
|
2044
|
+
<span class="absolute-voice-proof-trends__eyebrow">${escapeHtml6(model.title)}</span>
|
|
2045
|
+
<strong class="absolute-voice-proof-trends__label">${escapeHtml6(model.label)}</strong>
|
|
1781
2046
|
</header>
|
|
1782
|
-
<p class="absolute-voice-proof-trends__description">${
|
|
2047
|
+
<p class="absolute-voice-proof-trends__description">${escapeHtml6(model.description)}</p>
|
|
1783
2048
|
${metrics}
|
|
1784
2049
|
${links}
|
|
1785
|
-
${model.error ? `<p class="absolute-voice-proof-trends__error">${
|
|
2050
|
+
${model.error ? `<p class="absolute-voice-proof-trends__error">${escapeHtml6(model.error)}</p>` : ""}
|
|
1786
2051
|
</section>`;
|
|
1787
2052
|
};
|
|
1788
2053
|
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}`;
|
|
@@ -1990,7 +2255,7 @@ var DEFAULT_LINKS3 = [
|
|
|
1990
2255
|
{ href: "/production-readiness", label: "Readiness page" },
|
|
1991
2256
|
{ href: "/voice/slo-readiness-thresholds", label: "Gate thresholds" }
|
|
1992
2257
|
];
|
|
1993
|
-
var
|
|
2258
|
+
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1994
2259
|
var formatExplanationValue = (value, unit) => {
|
|
1995
2260
|
if (value === undefined || value === null) {
|
|
1996
2261
|
return "n/a";
|
|
@@ -2031,23 +2296,23 @@ var createVoiceReadinessFailuresViewModel = (snapshot, options = {}) => {
|
|
|
2031
2296
|
};
|
|
2032
2297
|
var renderVoiceReadinessFailuresHTML = (snapshot, options = {}) => {
|
|
2033
2298
|
const model = createVoiceReadinessFailuresViewModel(snapshot, options);
|
|
2034
|
-
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--${
|
|
2035
|
-
<span>${
|
|
2036
|
-
<strong>${
|
|
2037
|
-
<p>Observed ${
|
|
2038
|
-
<p>${
|
|
2039
|
-
<p class="absolute-voice-readiness-failures__links">${failure.evidenceHref ? `<a href="${
|
|
2040
|
-
</article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ?
|
|
2041
|
-
const links = model.links.length ? `<p class="absolute-voice-readiness-failures__links">${model.links.map((link) => `<a href="${
|
|
2042
|
-
return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${
|
|
2299
|
+
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)}">
|
|
2300
|
+
<span>${escapeHtml7(failure.status.toUpperCase())}</span>
|
|
2301
|
+
<strong>${escapeHtml7(failure.label)}</strong>
|
|
2302
|
+
<p>Observed ${escapeHtml7(failure.observed)} against ${escapeHtml7(failure.thresholdLabel)} ${escapeHtml7(failure.threshold)}.</p>
|
|
2303
|
+
<p>${escapeHtml7(failure.remediation)}</p>
|
|
2304
|
+
<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>
|
|
2305
|
+
</article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ? escapeHtml7(model.error) : "No calibrated readiness gate explanations are open."}</p>`;
|
|
2306
|
+
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>` : "";
|
|
2307
|
+
return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${escapeHtml7(model.status)}">
|
|
2043
2308
|
<header class="absolute-voice-readiness-failures__header">
|
|
2044
|
-
<span class="absolute-voice-readiness-failures__eyebrow">${
|
|
2045
|
-
<strong class="absolute-voice-readiness-failures__label">${
|
|
2309
|
+
<span class="absolute-voice-readiness-failures__eyebrow">${escapeHtml7(model.title)}</span>
|
|
2310
|
+
<strong class="absolute-voice-readiness-failures__label">${escapeHtml7(model.label)}</strong>
|
|
2046
2311
|
</header>
|
|
2047
|
-
<p class="absolute-voice-readiness-failures__description">${
|
|
2312
|
+
<p class="absolute-voice-readiness-failures__description">${escapeHtml7(model.description)}</p>
|
|
2048
2313
|
${failures}
|
|
2049
2314
|
${links}
|
|
2050
|
-
${model.error ? `<p class="absolute-voice-readiness-failures__error">${
|
|
2315
|
+
${model.error ? `<p class="absolute-voice-readiness-failures__error">${escapeHtml7(model.error)}</p>` : ""}
|
|
2051
2316
|
</section>`;
|
|
2052
2317
|
};
|
|
2053
2318
|
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}`;
|
|
@@ -2264,7 +2529,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
|
|
|
2264
2529
|
};
|
|
2265
2530
|
|
|
2266
2531
|
// src/client/providerSimulationControlsWidget.ts
|
|
2267
|
-
var
|
|
2532
|
+
var escapeHtml8 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2268
2533
|
var formatKind = (kind) => (kind ?? "stt").toUpperCase();
|
|
2269
2534
|
var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
2270
2535
|
const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
|
|
@@ -2284,18 +2549,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
|
2284
2549
|
};
|
|
2285
2550
|
var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
|
|
2286
2551
|
const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
|
|
2287
|
-
const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${
|
|
2288
|
-
const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${
|
|
2552
|
+
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("");
|
|
2553
|
+
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("");
|
|
2289
2554
|
return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
|
|
2290
2555
|
<header class="absolute-voice-provider-simulation__header">
|
|
2291
|
-
<span class="absolute-voice-provider-simulation__eyebrow">${
|
|
2292
|
-
<strong class="absolute-voice-provider-simulation__label">${
|
|
2556
|
+
<span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml8(model.title)}</span>
|
|
2557
|
+
<strong class="absolute-voice-provider-simulation__label">${escapeHtml8(model.label)}</strong>
|
|
2293
2558
|
</header>
|
|
2294
|
-
<p class="absolute-voice-provider-simulation__description">${
|
|
2295
|
-
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${
|
|
2559
|
+
<p class="absolute-voice-provider-simulation__description">${escapeHtml8(model.description)}</p>
|
|
2560
|
+
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml8(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
|
|
2296
2561
|
<div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
|
|
2297
|
-
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${
|
|
2298
|
-
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${
|
|
2562
|
+
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml8(snapshot.error)}</p>` : ""}
|
|
2563
|
+
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml8(model.resultText)}</pre>` : ""}
|
|
2299
2564
|
</section>`;
|
|
2300
2565
|
};
|
|
2301
2566
|
var bindVoiceProviderSimulationControls = (element, store) => {
|
|
@@ -2556,7 +2821,7 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
|
|
|
2556
2821
|
// src/client/providerCapabilitiesWidget.ts
|
|
2557
2822
|
var DEFAULT_TITLE7 = "Provider Capabilities";
|
|
2558
2823
|
var DEFAULT_DESCRIPTION7 = "Configured, selected, and healthy voice providers for this deployment.";
|
|
2559
|
-
var
|
|
2824
|
+
var escapeHtml9 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2560
2825
|
var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
2561
2826
|
var formatKind2 = (kind) => kind.toUpperCase();
|
|
2562
2827
|
var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
@@ -2611,25 +2876,25 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
|
|
|
2611
2876
|
};
|
|
2612
2877
|
var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
|
|
2613
2878
|
const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
|
|
2614
|
-
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--${
|
|
2879
|
+
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)}">
|
|
2615
2880
|
<header>
|
|
2616
|
-
<strong>${
|
|
2617
|
-
<span>${
|
|
2881
|
+
<strong>${escapeHtml9(capability.label)}</strong>
|
|
2882
|
+
<span>${escapeHtml9(formatStatus2(capability.status))}</span>
|
|
2618
2883
|
</header>
|
|
2619
|
-
<p>${
|
|
2884
|
+
<p>${escapeHtml9(capability.detail)}</p>
|
|
2620
2885
|
<dl>${capability.rows.map((row) => `<div>
|
|
2621
|
-
<dt>${
|
|
2622
|
-
<dd>${
|
|
2886
|
+
<dt>${escapeHtml9(row.label)}</dt>
|
|
2887
|
+
<dd>${escapeHtml9(row.value)}</dd>
|
|
2623
2888
|
</div>`).join("")}</dl>
|
|
2624
2889
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
|
|
2625
|
-
return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${
|
|
2890
|
+
return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml9(model.status)}">
|
|
2626
2891
|
<header class="absolute-voice-provider-capabilities__header">
|
|
2627
|
-
<span class="absolute-voice-provider-capabilities__eyebrow">${
|
|
2628
|
-
<strong class="absolute-voice-provider-capabilities__label">${
|
|
2892
|
+
<span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml9(model.title)}</span>
|
|
2893
|
+
<strong class="absolute-voice-provider-capabilities__label">${escapeHtml9(model.label)}</strong>
|
|
2629
2894
|
</header>
|
|
2630
|
-
<p class="absolute-voice-provider-capabilities__description">${
|
|
2895
|
+
<p class="absolute-voice-provider-capabilities__description">${escapeHtml9(model.description)}</p>
|
|
2631
2896
|
${capabilities}
|
|
2632
|
-
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${
|
|
2897
|
+
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml9(model.error)}</p>` : ""}
|
|
2633
2898
|
</section>`;
|
|
2634
2899
|
};
|
|
2635
2900
|
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}`;
|
|
@@ -2886,7 +3151,7 @@ function useVoiceProviderContracts(path = "/api/provider-contracts", options = {
|
|
|
2886
3151
|
// src/client/providerContractsWidget.ts
|
|
2887
3152
|
var DEFAULT_TITLE8 = "Provider Contracts";
|
|
2888
3153
|
var DEFAULT_DESCRIPTION8 = "Production contract coverage for provider env, latency, fallback, streaming, and capabilities.";
|
|
2889
|
-
var
|
|
3154
|
+
var escapeHtml10 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2890
3155
|
var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
2891
3156
|
var formatStatus3 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
2892
3157
|
var contractDetail = (row) => {
|
|
@@ -2930,26 +3195,26 @@ var createVoiceProviderContractsViewModel = (snapshot, options = {}) => {
|
|
|
2930
3195
|
};
|
|
2931
3196
|
var renderVoiceProviderContractsHTML = (snapshot, options = {}) => {
|
|
2932
3197
|
const model = createVoiceProviderContractsViewModel(snapshot, options);
|
|
2933
|
-
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--${
|
|
3198
|
+
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)}">
|
|
2934
3199
|
<header>
|
|
2935
|
-
<strong>${
|
|
2936
|
-
<span>${
|
|
3200
|
+
<strong>${escapeHtml10(row.label)}</strong>
|
|
3201
|
+
<span>${escapeHtml10(formatStatus3(row.status))}</span>
|
|
2937
3202
|
</header>
|
|
2938
|
-
<p>${
|
|
2939
|
-
${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${
|
|
3203
|
+
<p>${escapeHtml10(row.detail)}</p>
|
|
3204
|
+
${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>` : ""}
|
|
2940
3205
|
<dl>${row.rows.map((item) => `<div>
|
|
2941
|
-
<dt>${
|
|
2942
|
-
<dd>${
|
|
3206
|
+
<dt>${escapeHtml10(item.label)}</dt>
|
|
3207
|
+
<dd>${escapeHtml10(item.value)}</dd>
|
|
2943
3208
|
</div>`).join("")}</dl>
|
|
2944
3209
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-contracts__empty">Configure provider contracts to see production coverage.</p>';
|
|
2945
|
-
return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${
|
|
3210
|
+
return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml10(model.status)}">
|
|
2946
3211
|
<header class="absolute-voice-provider-contracts__header">
|
|
2947
|
-
<span class="absolute-voice-provider-contracts__eyebrow">${
|
|
2948
|
-
<strong class="absolute-voice-provider-contracts__label">${
|
|
3212
|
+
<span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml10(model.title)}</span>
|
|
3213
|
+
<strong class="absolute-voice-provider-contracts__label">${escapeHtml10(model.label)}</strong>
|
|
2949
3214
|
</header>
|
|
2950
|
-
<p class="absolute-voice-provider-contracts__description">${
|
|
3215
|
+
<p class="absolute-voice-provider-contracts__description">${escapeHtml10(model.description)}</p>
|
|
2951
3216
|
${rows}
|
|
2952
|
-
${model.error ? `<p class="absolute-voice-provider-contracts__error">${
|
|
3217
|
+
${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml10(model.error)}</p>` : ""}
|
|
2953
3218
|
</section>`;
|
|
2954
3219
|
};
|
|
2955
3220
|
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}`;
|
|
@@ -3146,7 +3411,7 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
3146
3411
|
// src/client/providerStatusWidget.ts
|
|
3147
3412
|
var DEFAULT_TITLE9 = "Voice Providers";
|
|
3148
3413
|
var DEFAULT_DESCRIPTION9 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
|
|
3149
|
-
var
|
|
3414
|
+
var escapeHtml11 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3150
3415
|
var formatProvider3 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
3151
3416
|
var formatStatus4 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
3152
3417
|
var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
|
|
@@ -3202,25 +3467,25 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
3202
3467
|
};
|
|
3203
3468
|
var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
|
|
3204
3469
|
const model = createVoiceProviderStatusViewModel(snapshot, options);
|
|
3205
|
-
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--${
|
|
3470
|
+
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)}">
|
|
3206
3471
|
<header>
|
|
3207
|
-
<strong>${
|
|
3208
|
-
<span>${
|
|
3472
|
+
<strong>${escapeHtml11(provider.label)}</strong>
|
|
3473
|
+
<span>${escapeHtml11(formatStatus4(provider.status))}</span>
|
|
3209
3474
|
</header>
|
|
3210
|
-
<p>${
|
|
3475
|
+
<p>${escapeHtml11(provider.detail)}</p>
|
|
3211
3476
|
<dl>${provider.rows.map((row) => `<div>
|
|
3212
|
-
<dt>${
|
|
3213
|
-
<dd>${
|
|
3477
|
+
<dt>${escapeHtml11(row.label)}</dt>
|
|
3478
|
+
<dd>${escapeHtml11(row.value)}</dd>
|
|
3214
3479
|
</div>`).join("")}</dl>
|
|
3215
3480
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
|
|
3216
|
-
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${
|
|
3481
|
+
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml11(model.status)}">
|
|
3217
3482
|
<header class="absolute-voice-provider-status__header">
|
|
3218
|
-
<span class="absolute-voice-provider-status__eyebrow">${
|
|
3219
|
-
<strong class="absolute-voice-provider-status__label">${
|
|
3483
|
+
<span class="absolute-voice-provider-status__eyebrow">${escapeHtml11(model.title)}</span>
|
|
3484
|
+
<strong class="absolute-voice-provider-status__label">${escapeHtml11(model.label)}</strong>
|
|
3220
3485
|
</header>
|
|
3221
|
-
<p class="absolute-voice-provider-status__description">${
|
|
3486
|
+
<p class="absolute-voice-provider-status__description">${escapeHtml11(model.description)}</p>
|
|
3222
3487
|
${providers}
|
|
3223
|
-
${model.error ? `<p class="absolute-voice-provider-status__error">${
|
|
3488
|
+
${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml11(model.error)}</p>` : ""}
|
|
3224
3489
|
</section>`;
|
|
3225
3490
|
};
|
|
3226
3491
|
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}`;
|
|
@@ -3449,7 +3714,7 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
|
|
|
3449
3714
|
// src/client/routingStatusWidget.ts
|
|
3450
3715
|
var DEFAULT_TITLE10 = "Voice Routing";
|
|
3451
3716
|
var DEFAULT_DESCRIPTION10 = "Latest provider routing decision from the self-hosted trace store.";
|
|
3452
|
-
var
|
|
3717
|
+
var escapeHtml12 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3453
3718
|
var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
|
|
3454
3719
|
var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
3455
3720
|
const decision = snapshot.decision;
|
|
@@ -3486,17 +3751,17 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
|
3486
3751
|
var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
|
|
3487
3752
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
3488
3753
|
const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
|
|
3489
|
-
<span>${
|
|
3490
|
-
<strong>${
|
|
3754
|
+
<span>${escapeHtml12(row.label)}</span>
|
|
3755
|
+
<strong>${escapeHtml12(row.value)}</strong>
|
|
3491
3756
|
</div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
|
|
3492
|
-
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${
|
|
3757
|
+
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml12(model.status)}">
|
|
3493
3758
|
<header class="absolute-voice-routing-status__header">
|
|
3494
|
-
<span class="absolute-voice-routing-status__eyebrow">${
|
|
3495
|
-
<strong class="absolute-voice-routing-status__label">${
|
|
3759
|
+
<span class="absolute-voice-routing-status__eyebrow">${escapeHtml12(model.title)}</span>
|
|
3760
|
+
<strong class="absolute-voice-routing-status__label">${escapeHtml12(model.label)}</strong>
|
|
3496
3761
|
</header>
|
|
3497
|
-
<p class="absolute-voice-routing-status__description">${
|
|
3762
|
+
<p class="absolute-voice-routing-status__description">${escapeHtml12(model.description)}</p>
|
|
3498
3763
|
${rows}
|
|
3499
|
-
${model.error ? `<p class="absolute-voice-routing-status__error">${
|
|
3764
|
+
${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml12(model.error)}</p>` : ""}
|
|
3500
3765
|
</section>`;
|
|
3501
3766
|
};
|
|
3502
3767
|
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}`;
|
|
@@ -3927,7 +4192,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
|
|
|
3927
4192
|
var DEFAULT_TITLE11 = "Turn Latency";
|
|
3928
4193
|
var DEFAULT_DESCRIPTION11 = "Per-turn timing from first transcript to commit and assistant response start.";
|
|
3929
4194
|
var DEFAULT_PROOF_LABEL = "Run latency proof";
|
|
3930
|
-
var
|
|
4195
|
+
var escapeHtml13 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3931
4196
|
var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
3932
4197
|
var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
3933
4198
|
const turns = (snapshot.report?.turns ?? []).map((turn) => ({
|
|
@@ -3955,25 +4220,25 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
|
3955
4220
|
};
|
|
3956
4221
|
var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
|
|
3957
4222
|
const model = createVoiceTurnLatencyViewModel(snapshot, options);
|
|
3958
|
-
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--${
|
|
4223
|
+
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--${escapeHtml13(turn.status)}">
|
|
3959
4224
|
<header>
|
|
3960
|
-
<strong>${
|
|
3961
|
-
<span>${
|
|
4225
|
+
<strong>${escapeHtml13(turn.label)}</strong>
|
|
4226
|
+
<span>${escapeHtml13(turn.status)}</span>
|
|
3962
4227
|
</header>
|
|
3963
4228
|
<dl>${turn.rows.map((row) => `<div>
|
|
3964
|
-
<dt>${
|
|
3965
|
-
<dd>${
|
|
4229
|
+
<dt>${escapeHtml13(row.label)}</dt>
|
|
4230
|
+
<dd>${escapeHtml13(row.value)}</dd>
|
|
3966
4231
|
</div>`).join("")}</dl>
|
|
3967
4232
|
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
|
|
3968
|
-
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${
|
|
4233
|
+
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml13(model.status)}">
|
|
3969
4234
|
<header class="absolute-voice-turn-latency__header">
|
|
3970
|
-
<span class="absolute-voice-turn-latency__eyebrow">${
|
|
3971
|
-
<strong class="absolute-voice-turn-latency__label">${
|
|
4235
|
+
<span class="absolute-voice-turn-latency__eyebrow">${escapeHtml13(model.title)}</span>
|
|
4236
|
+
<strong class="absolute-voice-turn-latency__label">${escapeHtml13(model.label)}</strong>
|
|
3972
4237
|
</header>
|
|
3973
|
-
<p class="absolute-voice-turn-latency__description">${
|
|
3974
|
-
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${
|
|
4238
|
+
<p class="absolute-voice-turn-latency__description">${escapeHtml13(model.description)}</p>
|
|
4239
|
+
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml13(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
|
|
3975
4240
|
${turns}
|
|
3976
|
-
${model.error ? `<p class="absolute-voice-turn-latency__error">${
|
|
4241
|
+
${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml13(model.error)}</p>` : ""}
|
|
3977
4242
|
</section>`;
|
|
3978
4243
|
};
|
|
3979
4244
|
var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
|
|
@@ -4206,7 +4471,7 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
|
|
|
4206
4471
|
// src/client/turnQualityWidget.ts
|
|
4207
4472
|
var DEFAULT_TITLE12 = "Turn Quality";
|
|
4208
4473
|
var DEFAULT_DESCRIPTION12 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
|
|
4209
|
-
var
|
|
4474
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
4210
4475
|
var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
|
|
4211
4476
|
var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
|
|
4212
4477
|
var getTurnDetail = (turn) => {
|
|
@@ -4256,25 +4521,25 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
|
|
|
4256
4521
|
};
|
|
4257
4522
|
var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
|
|
4258
4523
|
const model = createVoiceTurnQualityViewModel(snapshot, options);
|
|
4259
|
-
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--${
|
|
4524
|
+
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--${escapeHtml14(turn.status)}">
|
|
4260
4525
|
<header>
|
|
4261
|
-
<strong>${
|
|
4262
|
-
<span>${
|
|
4526
|
+
<strong>${escapeHtml14(turn.label)}</strong>
|
|
4527
|
+
<span>${escapeHtml14(turn.status)}</span>
|
|
4263
4528
|
</header>
|
|
4264
|
-
<p>${
|
|
4529
|
+
<p>${escapeHtml14(turn.detail)}</p>
|
|
4265
4530
|
<dl>${turn.rows.map((row) => `<div>
|
|
4266
|
-
<dt>${
|
|
4267
|
-
<dd>${
|
|
4531
|
+
<dt>${escapeHtml14(row.label)}</dt>
|
|
4532
|
+
<dd>${escapeHtml14(row.value)}</dd>
|
|
4268
4533
|
</div>`).join("")}</dl>
|
|
4269
4534
|
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
|
|
4270
|
-
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${
|
|
4535
|
+
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml14(model.status)}">
|
|
4271
4536
|
<header class="absolute-voice-turn-quality__header">
|
|
4272
|
-
<span class="absolute-voice-turn-quality__eyebrow">${
|
|
4273
|
-
<strong class="absolute-voice-turn-quality__label">${
|
|
4537
|
+
<span class="absolute-voice-turn-quality__eyebrow">${escapeHtml14(model.title)}</span>
|
|
4538
|
+
<strong class="absolute-voice-turn-quality__label">${escapeHtml14(model.label)}</strong>
|
|
4274
4539
|
</header>
|
|
4275
|
-
<p class="absolute-voice-turn-quality__description">${
|
|
4540
|
+
<p class="absolute-voice-turn-quality__description">${escapeHtml14(model.description)}</p>
|
|
4276
4541
|
${turns}
|
|
4277
|
-
${model.error ? `<p class="absolute-voice-turn-quality__error">${
|
|
4542
|
+
${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml14(model.error)}</p>` : ""}
|
|
4278
4543
|
</section>`;
|
|
4279
4544
|
};
|
|
4280
4545
|
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}`;
|