@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/react/index.js
CHANGED
|
@@ -1569,7 +1569,7 @@ var maxNumber = (values) => {
|
|
|
1569
1569
|
return finite.length > 0 ? Math.max(...finite) : undefined;
|
|
1570
1570
|
};
|
|
1571
1571
|
var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
|
|
1572
|
-
var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms;
|
|
1572
|
+
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)));
|
|
1573
1573
|
var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
|
|
1574
1574
|
var readRuntimeChannelMetric = (report, key) => {
|
|
1575
1575
|
const summaryValue = report.summary.runtimeChannel?.[key];
|
|
@@ -1587,6 +1587,91 @@ var readProofTrendRuntimeChannel = (report) => ({
|
|
|
1587
1587
|
samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
|
|
1588
1588
|
status: report.summary.runtimeChannel?.status
|
|
1589
1589
|
});
|
|
1590
|
+
var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
|
|
1591
|
+
var providerSortScore = (provider) => [
|
|
1592
|
+
recommendationStatusRank[provider.status],
|
|
1593
|
+
provider.p95Ms ?? Number.POSITIVE_INFINITY,
|
|
1594
|
+
provider.averageMs ?? Number.POSITIVE_INFINITY,
|
|
1595
|
+
provider.samples === undefined ? Number.POSITIVE_INFINITY : -provider.samples,
|
|
1596
|
+
provider.id
|
|
1597
|
+
];
|
|
1598
|
+
var compareProviders = (left, right) => {
|
|
1599
|
+
const leftScore = providerSortScore(left);
|
|
1600
|
+
const rightScore = providerSortScore(right);
|
|
1601
|
+
for (let index = 0;index < leftScore.length; index += 1) {
|
|
1602
|
+
const leftValue = leftScore[index];
|
|
1603
|
+
const rightValue = rightScore[index];
|
|
1604
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
1605
|
+
if (leftValue !== rightValue) {
|
|
1606
|
+
return leftValue - rightValue;
|
|
1607
|
+
}
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
const compared = String(leftValue).localeCompare(String(rightValue));
|
|
1611
|
+
if (compared !== 0) {
|
|
1612
|
+
return compared;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
return 0;
|
|
1616
|
+
};
|
|
1617
|
+
var summarizeProofTrendProviders = (report, budgetMs) => {
|
|
1618
|
+
const sourceProviders = report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : undefined;
|
|
1619
|
+
const providersById = new Map;
|
|
1620
|
+
if (sourceProviders) {
|
|
1621
|
+
for (const provider of sourceProviders) {
|
|
1622
|
+
if (provider.id) {
|
|
1623
|
+
providersById.set(provider.id, provider);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
} else {
|
|
1627
|
+
for (const cycle of report.cycles) {
|
|
1628
|
+
for (const provider of cycle.providers ?? []) {
|
|
1629
|
+
if (!provider.id) {
|
|
1630
|
+
continue;
|
|
1631
|
+
}
|
|
1632
|
+
const existing = providersById.get(provider.id);
|
|
1633
|
+
providersById.set(provider.id, {
|
|
1634
|
+
averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
|
|
1635
|
+
id: provider.id,
|
|
1636
|
+
label: existing?.label ?? provider.label,
|
|
1637
|
+
p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
|
|
1638
|
+
p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
|
|
1639
|
+
role: existing?.role ?? provider.role,
|
|
1640
|
+
samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
|
|
1641
|
+
status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
return [...providersById.values()].map((provider) => {
|
|
1647
|
+
const status = provider.p95Ms === undefined ? normalizeProviderStatus(provider.status) : withinBudget(provider.p95Ms, budgetMs) ? normalizeProviderStatus(provider.status) === "fail" ? "fail" : "pass" : normalizeProviderStatus(provider.status) === "fail" ? "fail" : "warn";
|
|
1648
|
+
return {
|
|
1649
|
+
averageMs: provider.averageMs,
|
|
1650
|
+
id: provider.id,
|
|
1651
|
+
label: provider.label,
|
|
1652
|
+
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.",
|
|
1653
|
+
p50Ms: provider.p50Ms,
|
|
1654
|
+
p95Ms: provider.p95Ms,
|
|
1655
|
+
rank: 0,
|
|
1656
|
+
role: provider.role,
|
|
1657
|
+
samples: provider.samples,
|
|
1658
|
+
status
|
|
1659
|
+
};
|
|
1660
|
+
}).sort(compareProviders).map((provider, index) => ({ ...provider, rank: index + 1 }));
|
|
1661
|
+
};
|
|
1662
|
+
var shouldSwitchProvider = (current, best, options) => {
|
|
1663
|
+
if (!current || !best || current.id === best.id || best.status !== "pass") {
|
|
1664
|
+
return false;
|
|
1665
|
+
}
|
|
1666
|
+
if (current.p95Ms === undefined || best.p95Ms === undefined) {
|
|
1667
|
+
return false;
|
|
1668
|
+
}
|
|
1669
|
+
const minImprovementMs = options.providerSwitchMinImprovementMs ?? 100;
|
|
1670
|
+
const minImprovementRatio = options.providerSwitchMinImprovementRatio ?? 0.1;
|
|
1671
|
+
const improvementMs = current.p95Ms - best.p95Ms;
|
|
1672
|
+
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
1673
|
+
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
1674
|
+
};
|
|
1590
1675
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
1591
1676
|
const issues = [];
|
|
1592
1677
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -1678,6 +1763,186 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
1678
1763
|
}
|
|
1679
1764
|
return assertion;
|
|
1680
1765
|
};
|
|
1766
|
+
var DEFAULT_RECOMMENDATION_BUDGETS = {
|
|
1767
|
+
maxLiveP95Ms: 800,
|
|
1768
|
+
maxProviderP95Ms: 1000,
|
|
1769
|
+
maxRuntimeBackpressureEvents: 0,
|
|
1770
|
+
maxRuntimeFirstAudioLatencyMs: 600,
|
|
1771
|
+
maxRuntimeInterruptionP95Ms: 300,
|
|
1772
|
+
maxRuntimeJitterMs: 30,
|
|
1773
|
+
maxRuntimeTimestampDriftMs: 800,
|
|
1774
|
+
maxTurnP95Ms: 700
|
|
1775
|
+
};
|
|
1776
|
+
var withinBudget = (value, budget) => typeof value === "number" && Number.isFinite(value) && value <= budget;
|
|
1777
|
+
var recommendationStatusRank = {
|
|
1778
|
+
pass: 0,
|
|
1779
|
+
warn: 1,
|
|
1780
|
+
fail: 2
|
|
1781
|
+
};
|
|
1782
|
+
var worstRecommendationStatus = (recommendations) => recommendations.reduce((status, recommendation) => recommendationStatusRank[recommendation.status] > recommendationStatusRank[status] ? recommendation.status : status, "pass");
|
|
1783
|
+
var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
1784
|
+
const budgets = { ...DEFAULT_RECOMMENDATION_BUDGETS, ...options };
|
|
1785
|
+
const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
|
|
1786
|
+
const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
|
|
1787
|
+
const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
|
|
1788
|
+
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
1789
|
+
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
1790
|
+
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
1791
|
+
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
1792
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestProvider, options);
|
|
1793
|
+
const recommendations = [];
|
|
1794
|
+
const issues = [];
|
|
1795
|
+
if (report.ok !== true) {
|
|
1796
|
+
issues.push(`Proof trend report is ${report.status}; recommendations need a fresh passing trend artifact.`);
|
|
1797
|
+
}
|
|
1798
|
+
recommendations.push({
|
|
1799
|
+
evidence: {
|
|
1800
|
+
bestProviderId: bestProvider?.id,
|
|
1801
|
+
bestProviderP95Ms: bestProvider?.p95Ms,
|
|
1802
|
+
budgetMs: budgets.maxProviderP95Ms,
|
|
1803
|
+
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
1804
|
+
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
1805
|
+
providerComparisonCount: providers.length,
|
|
1806
|
+
providerP95Ms: maxProviderP95Ms
|
|
1807
|
+
},
|
|
1808
|
+
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.",
|
|
1809
|
+
providerId: bestProvider?.id,
|
|
1810
|
+
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",
|
|
1811
|
+
role: bestProvider?.role,
|
|
1812
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1813
|
+
surface: "provider-path"
|
|
1814
|
+
});
|
|
1815
|
+
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);
|
|
1816
|
+
recommendations.push({
|
|
1817
|
+
evidence: {
|
|
1818
|
+
backpressureEvents: runtimeChannel.maxBackpressureEvents,
|
|
1819
|
+
firstAudioBudgetMs: budgets.maxRuntimeFirstAudioLatencyMs,
|
|
1820
|
+
firstAudioMs: runtimeChannel.maxFirstAudioLatencyMs,
|
|
1821
|
+
interruptionBudgetMs: budgets.maxRuntimeInterruptionP95Ms,
|
|
1822
|
+
interruptionP95Ms: runtimeChannel.maxInterruptionP95Ms,
|
|
1823
|
+
jitterBudgetMs: budgets.maxRuntimeJitterMs,
|
|
1824
|
+
jitterMs: runtimeChannel.maxJitterMs,
|
|
1825
|
+
samples: runtimeChannel.samples,
|
|
1826
|
+
timestampDriftMs: runtimeChannel.maxTimestampDriftMs
|
|
1827
|
+
},
|
|
1828
|
+
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.",
|
|
1829
|
+
recommendation: runtimePass ? "Keep current runtime channel" : "Tune runtime channel before promotion",
|
|
1830
|
+
status: runtimePass ? "pass" : runtimeChannel.samples === undefined ? "fail" : "warn",
|
|
1831
|
+
surface: "runtime-channel"
|
|
1832
|
+
});
|
|
1833
|
+
recommendations.push({
|
|
1834
|
+
evidence: {
|
|
1835
|
+
budgetMs: budgets.maxLiveP95Ms,
|
|
1836
|
+
liveP95Ms: maxLiveP95Ms
|
|
1837
|
+
},
|
|
1838
|
+
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.",
|
|
1839
|
+
recommendation: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep live-latency settings" : "Tune live-latency path",
|
|
1840
|
+
status: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "pass" : maxLiveP95Ms === undefined ? "fail" : "warn",
|
|
1841
|
+
surface: "live-latency"
|
|
1842
|
+
});
|
|
1843
|
+
recommendations.push({
|
|
1844
|
+
evidence: {
|
|
1845
|
+
budgetMs: budgets.maxTurnP95Ms,
|
|
1846
|
+
turnP95Ms: maxTurnP95Ms
|
|
1847
|
+
},
|
|
1848
|
+
nextMove: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep current turn pipeline defaults." : "Reduce tool/provider latency or split the turn pipeline before promotion.",
|
|
1849
|
+
recommendation: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep turn pipeline" : "Tune turn pipeline",
|
|
1850
|
+
status: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "pass" : maxTurnP95Ms === undefined ? "fail" : "warn",
|
|
1851
|
+
surface: "turn-latency"
|
|
1852
|
+
});
|
|
1853
|
+
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
1854
|
+
return {
|
|
1855
|
+
bestProvider,
|
|
1856
|
+
generatedAt: new Date().toISOString(),
|
|
1857
|
+
issues,
|
|
1858
|
+
ok: status !== "fail",
|
|
1859
|
+
providers,
|
|
1860
|
+
recommendations,
|
|
1861
|
+
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
1862
|
+
status,
|
|
1863
|
+
summary: {
|
|
1864
|
+
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
1865
|
+
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
1866
|
+
providerComparisonCount: providers.length,
|
|
1867
|
+
recommendedActions: recommendations.filter((item) => item.status !== "pass").length,
|
|
1868
|
+
switchRecommended: providerSwitchRecommended
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
};
|
|
1872
|
+
var escapeHtml5 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1873
|
+
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
1874
|
+
var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
|
|
1875
|
+
`# ${title}`,
|
|
1876
|
+
"",
|
|
1877
|
+
`- Status: ${report.status}`,
|
|
1878
|
+
`- Source: ${report.source}`,
|
|
1879
|
+
`- Best provider: ${report.bestProvider?.label ?? report.bestProvider?.id ?? "n/a"}`,
|
|
1880
|
+
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
1881
|
+
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
1882
|
+
"",
|
|
1883
|
+
"| Surface | Status | Recommendation | Next move |",
|
|
1884
|
+
"| --- | --- | --- | --- |",
|
|
1885
|
+
...report.recommendations.map((recommendation) => `| ${escapeMarkdown(recommendation.surface)} | ${recommendation.status} | ${escapeMarkdown(recommendation.recommendation)} | ${escapeMarkdown(recommendation.nextMove)} |`),
|
|
1886
|
+
"",
|
|
1887
|
+
"## Provider Comparison",
|
|
1888
|
+
"",
|
|
1889
|
+
"| Rank | Provider | Role | Status | P95 | Samples | Next move |",
|
|
1890
|
+
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
1891
|
+
...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. |"],
|
|
1892
|
+
"",
|
|
1893
|
+
"## Issues",
|
|
1894
|
+
"",
|
|
1895
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
1896
|
+
].join(`
|
|
1897
|
+
`);
|
|
1898
|
+
var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
|
|
1899
|
+
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("");
|
|
1900
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
|
|
1901
|
+
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("");
|
|
1902
|
+
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>`;
|
|
1903
|
+
};
|
|
1904
|
+
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
1905
|
+
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
|
1906
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/proof-trend-recommendations" : options.htmlPath;
|
|
1907
|
+
const markdownPath = options.markdownPath === undefined ? "/voice/proof-trend-recommendations.md" : options.markdownPath;
|
|
1908
|
+
const title = options.title ?? "Voice Provider Runtime Recommendations";
|
|
1909
|
+
const routes = new Elysia({
|
|
1910
|
+
name: options.name ?? "absolutejs-voice-proof-trend-recommendations"
|
|
1911
|
+
});
|
|
1912
|
+
const loadReport = async () => {
|
|
1913
|
+
const value = options.source !== undefined ? typeof options.source === "function" ? await options.source() : options.source : options.jsonPath ? await readVoiceProofTrendReportFile(options.jsonPath, {
|
|
1914
|
+
maxAgeMs: options.maxAgeMs
|
|
1915
|
+
}) : buildEmptyVoiceProofTrendReport("", options.maxAgeMs);
|
|
1916
|
+
return buildVoiceProofTrendRecommendationReport(normalizeVoiceProofTrendReport(value, {
|
|
1917
|
+
maxAgeMs: options.maxAgeMs,
|
|
1918
|
+
source: options.jsonPath
|
|
1919
|
+
}), options);
|
|
1920
|
+
};
|
|
1921
|
+
routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
|
|
1922
|
+
if (htmlPath !== false) {
|
|
1923
|
+
routes.get(htmlPath, async () => {
|
|
1924
|
+
const report = await loadReport();
|
|
1925
|
+
return new Response(renderVoiceProofTrendRecommendationHTML(report, title), {
|
|
1926
|
+
headers: {
|
|
1927
|
+
"content-type": "text/html; charset=utf-8",
|
|
1928
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
if (markdownPath !== false) {
|
|
1934
|
+
routes.get(markdownPath, async () => {
|
|
1935
|
+
const report = await loadReport();
|
|
1936
|
+
return new Response(renderVoiceProofTrendRecommendationMarkdown(report, title), {
|
|
1937
|
+
headers: {
|
|
1938
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
1939
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
return routes;
|
|
1945
|
+
};
|
|
1681
1946
|
var createVoiceProofTrendRoutes = (options) => {
|
|
1682
1947
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
1683
1948
|
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}`;
|
|
@@ -1967,7 +2232,7 @@ var DEFAULT_LINKS3 = [
|
|
|
1967
2232
|
{ href: "/production-readiness", label: "Readiness page" },
|
|
1968
2233
|
{ href: "/voice/slo-readiness-thresholds", label: "Gate thresholds" }
|
|
1969
2234
|
];
|
|
1970
|
-
var
|
|
2235
|
+
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1971
2236
|
var formatExplanationValue = (value, unit) => {
|
|
1972
2237
|
if (value === undefined || value === null) {
|
|
1973
2238
|
return "n/a";
|
|
@@ -2008,23 +2273,23 @@ var createVoiceReadinessFailuresViewModel = (snapshot, options = {}) => {
|
|
|
2008
2273
|
};
|
|
2009
2274
|
var renderVoiceReadinessFailuresHTML = (snapshot, options = {}) => {
|
|
2010
2275
|
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--${
|
|
2012
|
-
<span>${
|
|
2013
|
-
<strong>${
|
|
2014
|
-
<p>Observed ${
|
|
2015
|
-
<p>${
|
|
2016
|
-
<p class="absolute-voice-readiness-failures__links">${failure.evidenceHref ? `<a href="${
|
|
2017
|
-
</article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ?
|
|
2018
|
-
const links = model.links.length ? `<p class="absolute-voice-readiness-failures__links">${model.links.map((link) => `<a href="${
|
|
2019
|
-
return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${
|
|
2276
|
+
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)}">
|
|
2277
|
+
<span>${escapeHtml7(failure.status.toUpperCase())}</span>
|
|
2278
|
+
<strong>${escapeHtml7(failure.label)}</strong>
|
|
2279
|
+
<p>Observed ${escapeHtml7(failure.observed)} against ${escapeHtml7(failure.thresholdLabel)} ${escapeHtml7(failure.threshold)}.</p>
|
|
2280
|
+
<p>${escapeHtml7(failure.remediation)}</p>
|
|
2281
|
+
<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>
|
|
2282
|
+
</article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ? escapeHtml7(model.error) : "No calibrated readiness gate explanations are open."}</p>`;
|
|
2283
|
+
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>` : "";
|
|
2284
|
+
return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${escapeHtml7(model.status)}">
|
|
2020
2285
|
<header class="absolute-voice-readiness-failures__header">
|
|
2021
|
-
<span class="absolute-voice-readiness-failures__eyebrow">${
|
|
2022
|
-
<strong class="absolute-voice-readiness-failures__label">${
|
|
2286
|
+
<span class="absolute-voice-readiness-failures__eyebrow">${escapeHtml7(model.title)}</span>
|
|
2287
|
+
<strong class="absolute-voice-readiness-failures__label">${escapeHtml7(model.label)}</strong>
|
|
2023
2288
|
</header>
|
|
2024
|
-
<p class="absolute-voice-readiness-failures__description">${
|
|
2289
|
+
<p class="absolute-voice-readiness-failures__description">${escapeHtml7(model.description)}</p>
|
|
2025
2290
|
${failures}
|
|
2026
2291
|
${links}
|
|
2027
|
-
${model.error ? `<p class="absolute-voice-readiness-failures__error">${
|
|
2292
|
+
${model.error ? `<p class="absolute-voice-readiness-failures__error">${escapeHtml7(model.error)}</p>` : ""}
|
|
2028
2293
|
</section>`;
|
|
2029
2294
|
};
|
|
2030
2295
|
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 +2518,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
|
|
|
2253
2518
|
};
|
|
2254
2519
|
|
|
2255
2520
|
// src/client/providerSimulationControlsWidget.ts
|
|
2256
|
-
var
|
|
2521
|
+
var escapeHtml8 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2257
2522
|
var formatKind = (kind) => (kind ?? "stt").toUpperCase();
|
|
2258
2523
|
var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
2259
2524
|
const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
|
|
@@ -2273,18 +2538,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
|
2273
2538
|
};
|
|
2274
2539
|
var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
|
|
2275
2540
|
const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
|
|
2276
|
-
const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${
|
|
2277
|
-
const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${
|
|
2541
|
+
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("");
|
|
2542
|
+
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
2543
|
return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
|
|
2279
2544
|
<header class="absolute-voice-provider-simulation__header">
|
|
2280
|
-
<span class="absolute-voice-provider-simulation__eyebrow">${
|
|
2281
|
-
<strong class="absolute-voice-provider-simulation__label">${
|
|
2545
|
+
<span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml8(model.title)}</span>
|
|
2546
|
+
<strong class="absolute-voice-provider-simulation__label">${escapeHtml8(model.label)}</strong>
|
|
2282
2547
|
</header>
|
|
2283
|
-
<p class="absolute-voice-provider-simulation__description">${
|
|
2284
|
-
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${
|
|
2548
|
+
<p class="absolute-voice-provider-simulation__description">${escapeHtml8(model.description)}</p>
|
|
2549
|
+
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml8(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
|
|
2285
2550
|
<div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
|
|
2286
|
-
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${
|
|
2287
|
-
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${
|
|
2551
|
+
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml8(snapshot.error)}</p>` : ""}
|
|
2552
|
+
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml8(model.resultText)}</pre>` : ""}
|
|
2288
2553
|
</section>`;
|
|
2289
2554
|
};
|
|
2290
2555
|
var bindVoiceProviderSimulationControls = (element, store) => {
|
|
@@ -2544,7 +2809,7 @@ var useVoiceProviderCapabilities = (path = "/api/provider-capabilities", options
|
|
|
2544
2809
|
// src/client/providerCapabilitiesWidget.ts
|
|
2545
2810
|
var DEFAULT_TITLE7 = "Provider Capabilities";
|
|
2546
2811
|
var DEFAULT_DESCRIPTION7 = "Configured, selected, and healthy voice providers for this deployment.";
|
|
2547
|
-
var
|
|
2812
|
+
var escapeHtml9 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2548
2813
|
var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
2549
2814
|
var formatKind2 = (kind) => kind.toUpperCase();
|
|
2550
2815
|
var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
@@ -2599,25 +2864,25 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
|
|
|
2599
2864
|
};
|
|
2600
2865
|
var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
|
|
2601
2866
|
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--${
|
|
2867
|
+
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
2868
|
<header>
|
|
2604
|
-
<strong>${
|
|
2605
|
-
<span>${
|
|
2869
|
+
<strong>${escapeHtml9(capability.label)}</strong>
|
|
2870
|
+
<span>${escapeHtml9(formatStatus2(capability.status))}</span>
|
|
2606
2871
|
</header>
|
|
2607
|
-
<p>${
|
|
2872
|
+
<p>${escapeHtml9(capability.detail)}</p>
|
|
2608
2873
|
<dl>${capability.rows.map((row) => `<div>
|
|
2609
|
-
<dt>${
|
|
2610
|
-
<dd>${
|
|
2874
|
+
<dt>${escapeHtml9(row.label)}</dt>
|
|
2875
|
+
<dd>${escapeHtml9(row.value)}</dd>
|
|
2611
2876
|
</div>`).join("")}</dl>
|
|
2612
2877
|
</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--${
|
|
2878
|
+
return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml9(model.status)}">
|
|
2614
2879
|
<header class="absolute-voice-provider-capabilities__header">
|
|
2615
|
-
<span class="absolute-voice-provider-capabilities__eyebrow">${
|
|
2616
|
-
<strong class="absolute-voice-provider-capabilities__label">${
|
|
2880
|
+
<span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml9(model.title)}</span>
|
|
2881
|
+
<strong class="absolute-voice-provider-capabilities__label">${escapeHtml9(model.label)}</strong>
|
|
2617
2882
|
</header>
|
|
2618
|
-
<p class="absolute-voice-provider-capabilities__description">${
|
|
2883
|
+
<p class="absolute-voice-provider-capabilities__description">${escapeHtml9(model.description)}</p>
|
|
2619
2884
|
${capabilities}
|
|
2620
|
-
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${
|
|
2885
|
+
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml9(model.error)}</p>` : ""}
|
|
2621
2886
|
</section>`;
|
|
2622
2887
|
};
|
|
2623
2888
|
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 +3100,7 @@ var useVoiceProviderContracts = (path = "/api/provider-contracts", options = {})
|
|
|
2835
3100
|
// src/client/providerContractsWidget.ts
|
|
2836
3101
|
var DEFAULT_TITLE8 = "Provider Contracts";
|
|
2837
3102
|
var DEFAULT_DESCRIPTION8 = "Production contract coverage for provider env, latency, fallback, streaming, and capabilities.";
|
|
2838
|
-
var
|
|
3103
|
+
var escapeHtml10 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2839
3104
|
var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
2840
3105
|
var formatStatus3 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
2841
3106
|
var contractDetail = (row) => {
|
|
@@ -2879,26 +3144,26 @@ var createVoiceProviderContractsViewModel = (snapshot, options = {}) => {
|
|
|
2879
3144
|
};
|
|
2880
3145
|
var renderVoiceProviderContractsHTML = (snapshot, options = {}) => {
|
|
2881
3146
|
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--${
|
|
3147
|
+
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
3148
|
<header>
|
|
2884
|
-
<strong>${
|
|
2885
|
-
<span>${
|
|
3149
|
+
<strong>${escapeHtml10(row.label)}</strong>
|
|
3150
|
+
<span>${escapeHtml10(formatStatus3(row.status))}</span>
|
|
2886
3151
|
</header>
|
|
2887
|
-
<p>${
|
|
2888
|
-
${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${
|
|
3152
|
+
<p>${escapeHtml10(row.detail)}</p>
|
|
3153
|
+
${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
3154
|
<dl>${row.rows.map((item) => `<div>
|
|
2890
|
-
<dt>${
|
|
2891
|
-
<dd>${
|
|
3155
|
+
<dt>${escapeHtml10(item.label)}</dt>
|
|
3156
|
+
<dd>${escapeHtml10(item.value)}</dd>
|
|
2892
3157
|
</div>`).join("")}</dl>
|
|
2893
3158
|
</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--${
|
|
3159
|
+
return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml10(model.status)}">
|
|
2895
3160
|
<header class="absolute-voice-provider-contracts__header">
|
|
2896
|
-
<span class="absolute-voice-provider-contracts__eyebrow">${
|
|
2897
|
-
<strong class="absolute-voice-provider-contracts__label">${
|
|
3161
|
+
<span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml10(model.title)}</span>
|
|
3162
|
+
<strong class="absolute-voice-provider-contracts__label">${escapeHtml10(model.label)}</strong>
|
|
2898
3163
|
</header>
|
|
2899
|
-
<p class="absolute-voice-provider-contracts__description">${
|
|
3164
|
+
<p class="absolute-voice-provider-contracts__description">${escapeHtml10(model.description)}</p>
|
|
2900
3165
|
${rows}
|
|
2901
|
-
${model.error ? `<p class="absolute-voice-provider-contracts__error">${
|
|
3166
|
+
${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml10(model.error)}</p>` : ""}
|
|
2902
3167
|
</section>`;
|
|
2903
3168
|
};
|
|
2904
3169
|
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 +3402,7 @@ var useVoiceProviderStatus = (path = "/api/provider-status", options = {}) => {
|
|
|
3137
3402
|
// src/client/providerStatusWidget.ts
|
|
3138
3403
|
var DEFAULT_TITLE9 = "Voice Providers";
|
|
3139
3404
|
var DEFAULT_DESCRIPTION9 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
|
|
3140
|
-
var
|
|
3405
|
+
var escapeHtml11 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3141
3406
|
var formatProvider3 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
3142
3407
|
var formatStatus4 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
3143
3408
|
var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
|
|
@@ -3193,25 +3458,25 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
3193
3458
|
};
|
|
3194
3459
|
var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
|
|
3195
3460
|
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--${
|
|
3461
|
+
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
3462
|
<header>
|
|
3198
|
-
<strong>${
|
|
3199
|
-
<span>${
|
|
3463
|
+
<strong>${escapeHtml11(provider.label)}</strong>
|
|
3464
|
+
<span>${escapeHtml11(formatStatus4(provider.status))}</span>
|
|
3200
3465
|
</header>
|
|
3201
|
-
<p>${
|
|
3466
|
+
<p>${escapeHtml11(provider.detail)}</p>
|
|
3202
3467
|
<dl>${provider.rows.map((row) => `<div>
|
|
3203
|
-
<dt>${
|
|
3204
|
-
<dd>${
|
|
3468
|
+
<dt>${escapeHtml11(row.label)}</dt>
|
|
3469
|
+
<dd>${escapeHtml11(row.value)}</dd>
|
|
3205
3470
|
</div>`).join("")}</dl>
|
|
3206
3471
|
</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--${
|
|
3472
|
+
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml11(model.status)}">
|
|
3208
3473
|
<header class="absolute-voice-provider-status__header">
|
|
3209
|
-
<span class="absolute-voice-provider-status__eyebrow">${
|
|
3210
|
-
<strong class="absolute-voice-provider-status__label">${
|
|
3474
|
+
<span class="absolute-voice-provider-status__eyebrow">${escapeHtml11(model.title)}</span>
|
|
3475
|
+
<strong class="absolute-voice-provider-status__label">${escapeHtml11(model.label)}</strong>
|
|
3211
3476
|
</header>
|
|
3212
|
-
<p class="absolute-voice-provider-status__description">${
|
|
3477
|
+
<p class="absolute-voice-provider-status__description">${escapeHtml11(model.description)}</p>
|
|
3213
3478
|
${providers}
|
|
3214
|
-
${model.error ? `<p class="absolute-voice-provider-status__error">${
|
|
3479
|
+
${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml11(model.error)}</p>` : ""}
|
|
3215
3480
|
</section>`;
|
|
3216
3481
|
};
|
|
3217
3482
|
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 +3699,7 @@ var useVoiceRoutingStatus = (path = "/api/routing/latest", options = {}) => {
|
|
|
3434
3699
|
// src/client/routingStatusWidget.ts
|
|
3435
3700
|
var DEFAULT_TITLE10 = "Voice Routing";
|
|
3436
3701
|
var DEFAULT_DESCRIPTION10 = "Latest provider routing decision from the self-hosted trace store.";
|
|
3437
|
-
var
|
|
3702
|
+
var escapeHtml12 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3438
3703
|
var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
|
|
3439
3704
|
var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
3440
3705
|
const decision = snapshot.decision;
|
|
@@ -3471,17 +3736,17 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
|
3471
3736
|
var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
|
|
3472
3737
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
3473
3738
|
const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
|
|
3474
|
-
<span>${
|
|
3475
|
-
<strong>${
|
|
3739
|
+
<span>${escapeHtml12(row.label)}</span>
|
|
3740
|
+
<strong>${escapeHtml12(row.value)}</strong>
|
|
3476
3741
|
</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--${
|
|
3742
|
+
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml12(model.status)}">
|
|
3478
3743
|
<header class="absolute-voice-routing-status__header">
|
|
3479
|
-
<span class="absolute-voice-routing-status__eyebrow">${
|
|
3480
|
-
<strong class="absolute-voice-routing-status__label">${
|
|
3744
|
+
<span class="absolute-voice-routing-status__eyebrow">${escapeHtml12(model.title)}</span>
|
|
3745
|
+
<strong class="absolute-voice-routing-status__label">${escapeHtml12(model.label)}</strong>
|
|
3481
3746
|
</header>
|
|
3482
|
-
<p class="absolute-voice-routing-status__description">${
|
|
3747
|
+
<p class="absolute-voice-routing-status__description">${escapeHtml12(model.description)}</p>
|
|
3483
3748
|
${rows}
|
|
3484
|
-
${model.error ? `<p class="absolute-voice-routing-status__error">${
|
|
3749
|
+
${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml12(model.error)}</p>` : ""}
|
|
3485
3750
|
</section>`;
|
|
3486
3751
|
};
|
|
3487
3752
|
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 +3926,7 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
|
|
|
3661
3926
|
// src/client/traceTimelineWidget.ts
|
|
3662
3927
|
var DEFAULT_TITLE11 = "Voice Traces";
|
|
3663
3928
|
var DEFAULT_DESCRIPTION11 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
|
|
3664
|
-
var
|
|
3929
|
+
var escapeHtml13 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3665
3930
|
var formatMs2 = (value) => typeof value === "number" ? `${value}ms` : "n/a";
|
|
3666
3931
|
var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
|
|
3667
3932
|
var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
|
|
@@ -3691,27 +3956,27 @@ var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
|
|
|
3691
3956
|
const model = createVoiceTraceTimelineViewModel(snapshot, options);
|
|
3692
3957
|
const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => {
|
|
3693
3958
|
const supportLinks = [
|
|
3694
|
-
`<a href="${
|
|
3695
|
-
session.operationsRecordHref ? `<a href="${
|
|
3696
|
-
session.incidentBundleHref ? `<a href="${
|
|
3959
|
+
`<a href="${escapeHtml13(session.detailHref)}">Open timeline</a>`,
|
|
3960
|
+
session.operationsRecordHref ? `<a href="${escapeHtml13(session.operationsRecordHref)}">Open operations record</a>` : undefined,
|
|
3961
|
+
session.incidentBundleHref ? `<a href="${escapeHtml13(session.incidentBundleHref)}">Export incident bundle</a>` : undefined
|
|
3697
3962
|
].filter(Boolean).join("");
|
|
3698
|
-
return `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${
|
|
3963
|
+
return `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml13(session.status)}">
|
|
3699
3964
|
<header>
|
|
3700
|
-
<strong>${
|
|
3701
|
-
<span>${
|
|
3965
|
+
<strong>${escapeHtml13(session.sessionId)}</strong>
|
|
3966
|
+
<span>${escapeHtml13(session.status)}</span>
|
|
3702
3967
|
</header>
|
|
3703
|
-
<p>${
|
|
3968
|
+
<p>${escapeHtml13(session.label)} \xB7 ${escapeHtml13(session.durationLabel)} \xB7 ${escapeHtml13(session.providerLabel)}</p>
|
|
3704
3969
|
<p class="absolute-voice-trace-timeline__actions">${supportLinks}</p>
|
|
3705
3970
|
</article>`;
|
|
3706
3971
|
}).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--${
|
|
3972
|
+
return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml13(model.status)}">
|
|
3708
3973
|
<header class="absolute-voice-trace-timeline__header">
|
|
3709
|
-
<span class="absolute-voice-trace-timeline__eyebrow">${
|
|
3710
|
-
<strong class="absolute-voice-trace-timeline__label">${
|
|
3974
|
+
<span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml13(model.title)}</span>
|
|
3975
|
+
<strong class="absolute-voice-trace-timeline__label">${escapeHtml13(model.label)}</strong>
|
|
3711
3976
|
</header>
|
|
3712
|
-
<p class="absolute-voice-trace-timeline__description">${
|
|
3977
|
+
<p class="absolute-voice-trace-timeline__description">${escapeHtml13(model.description)}</p>
|
|
3713
3978
|
${sessions}
|
|
3714
|
-
${model.error ? `<p class="absolute-voice-trace-timeline__error">${
|
|
3979
|
+
${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml13(model.error)}</p>` : ""}
|
|
3715
3980
|
</section>`;
|
|
3716
3981
|
};
|
|
3717
3982
|
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 +4228,7 @@ var useVoiceAgentSquadStatus = (path = "/api/voice-traces", options = {}) => {
|
|
|
3963
4228
|
// src/client/agentSquadStatusWidget.ts
|
|
3964
4229
|
var DEFAULT_TITLE12 = "Voice Agent Squad";
|
|
3965
4230
|
var DEFAULT_DESCRIPTION12 = "Current specialist and recent handoffs from your self-hosted voice traces.";
|
|
3966
|
-
var
|
|
4231
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3967
4232
|
var labelFor = (current) => {
|
|
3968
4233
|
if (!current)
|
|
3969
4234
|
return "Waiting for specialist activity";
|
|
@@ -3990,24 +4255,24 @@ var renderVoiceAgentSquadStatusHTML = (snapshot, options = {}) => {
|
|
|
3990
4255
|
const model = createVoiceAgentSquadStatusViewModel(snapshot, options);
|
|
3991
4256
|
const current = model.current;
|
|
3992
4257
|
const rows = model.sessions.length ? model.sessions.slice(0, 5).map((session) => `<li>
|
|
3993
|
-
<span>${
|
|
3994
|
-
<strong>${
|
|
3995
|
-
<em>${
|
|
3996
|
-
${session.summary || session.reason ? `<p>${
|
|
4258
|
+
<span>${escapeHtml14(session.sessionId)}</span>
|
|
4259
|
+
<strong>${escapeHtml14(session.targetAgentId ?? "none")}</strong>
|
|
4260
|
+
<em>${escapeHtml14(session.status)}</em>
|
|
4261
|
+
${session.summary || session.reason ? `<p>${escapeHtml14(session.summary ?? session.reason ?? "")}</p>` : ""}
|
|
3997
4262
|
</li>`).join("") : "<li><span>No squad traces yet.</span><strong>Waiting</strong></li>";
|
|
3998
4263
|
return `<section class="absolute-voice-agent-squad-status">
|
|
3999
4264
|
<header>
|
|
4000
|
-
<span>${
|
|
4001
|
-
<strong>${
|
|
4265
|
+
<span>${escapeHtml14(model.title)}</span>
|
|
4266
|
+
<strong>${escapeHtml14(model.label)}</strong>
|
|
4002
4267
|
</header>
|
|
4003
|
-
<p>${
|
|
4268
|
+
<p>${escapeHtml14(model.description)}</p>
|
|
4004
4269
|
<div>
|
|
4005
|
-
<span>Session</span><strong>${
|
|
4006
|
-
<span>From</span><strong>${
|
|
4007
|
-
<span>Status</span><strong>${
|
|
4270
|
+
<span>Session</span><strong>${escapeHtml14(current?.sessionId ?? "n/a")}</strong>
|
|
4271
|
+
<span>From</span><strong>${escapeHtml14(current?.fromAgentId ?? "n/a")}</strong>
|
|
4272
|
+
<span>Status</span><strong>${escapeHtml14(current?.status ?? "idle")}</strong>
|
|
4008
4273
|
</div>
|
|
4009
4274
|
<ul>${rows}</ul>
|
|
4010
|
-
${model.error ? `<p class="absolute-voice-agent-squad-status__error">${
|
|
4275
|
+
${model.error ? `<p class="absolute-voice-agent-squad-status__error">${escapeHtml14(model.error)}</p>` : ""}
|
|
4011
4276
|
</section>`;
|
|
4012
4277
|
};
|
|
4013
4278
|
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 +4509,7 @@ var useVoiceTurnLatency = (path = "/api/turn-latency", options = {}) => {
|
|
|
4244
4509
|
var DEFAULT_TITLE13 = "Turn Latency";
|
|
4245
4510
|
var DEFAULT_DESCRIPTION13 = "Per-turn timing from first transcript to commit and assistant response start.";
|
|
4246
4511
|
var DEFAULT_PROOF_LABEL = "Run latency proof";
|
|
4247
|
-
var
|
|
4512
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
4248
4513
|
var formatMs3 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
4249
4514
|
var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
4250
4515
|
const turns = (snapshot.report?.turns ?? []).map((turn) => ({
|
|
@@ -4272,25 +4537,25 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
|
4272
4537
|
};
|
|
4273
4538
|
var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
|
|
4274
4539
|
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--${
|
|
4540
|
+
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
4541
|
<header>
|
|
4277
|
-
<strong>${
|
|
4278
|
-
<span>${
|
|
4542
|
+
<strong>${escapeHtml15(turn.label)}</strong>
|
|
4543
|
+
<span>${escapeHtml15(turn.status)}</span>
|
|
4279
4544
|
</header>
|
|
4280
4545
|
<dl>${turn.rows.map((row) => `<div>
|
|
4281
|
-
<dt>${
|
|
4282
|
-
<dd>${
|
|
4546
|
+
<dt>${escapeHtml15(row.label)}</dt>
|
|
4547
|
+
<dd>${escapeHtml15(row.value)}</dd>
|
|
4283
4548
|
</div>`).join("")}</dl>
|
|
4284
4549
|
</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--${
|
|
4550
|
+
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml15(model.status)}">
|
|
4286
4551
|
<header class="absolute-voice-turn-latency__header">
|
|
4287
|
-
<span class="absolute-voice-turn-latency__eyebrow">${
|
|
4288
|
-
<strong class="absolute-voice-turn-latency__label">${
|
|
4552
|
+
<span class="absolute-voice-turn-latency__eyebrow">${escapeHtml15(model.title)}</span>
|
|
4553
|
+
<strong class="absolute-voice-turn-latency__label">${escapeHtml15(model.label)}</strong>
|
|
4289
4554
|
</header>
|
|
4290
|
-
<p class="absolute-voice-turn-latency__description">${
|
|
4291
|
-
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${
|
|
4555
|
+
<p class="absolute-voice-turn-latency__description">${escapeHtml15(model.description)}</p>
|
|
4556
|
+
${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
4557
|
${turns}
|
|
4293
|
-
${model.error ? `<p class="absolute-voice-turn-latency__error">${
|
|
4558
|
+
${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml15(model.error)}</p>` : ""}
|
|
4294
4559
|
</section>`;
|
|
4295
4560
|
};
|
|
4296
4561
|
var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
|
|
@@ -4526,7 +4791,7 @@ var useVoiceTurnQuality = (path = "/api/turn-quality", options = {}) => {
|
|
|
4526
4791
|
// src/client/turnQualityWidget.ts
|
|
4527
4792
|
var DEFAULT_TITLE14 = "Turn Quality";
|
|
4528
4793
|
var DEFAULT_DESCRIPTION14 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
|
|
4529
|
-
var
|
|
4794
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
4530
4795
|
var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
|
|
4531
4796
|
var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
|
|
4532
4797
|
var getTurnDetail = (turn) => {
|
|
@@ -4576,25 +4841,25 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
|
|
|
4576
4841
|
};
|
|
4577
4842
|
var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
|
|
4578
4843
|
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--${
|
|
4844
|
+
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
4845
|
<header>
|
|
4581
|
-
<strong>${
|
|
4582
|
-
<span>${
|
|
4846
|
+
<strong>${escapeHtml16(turn.label)}</strong>
|
|
4847
|
+
<span>${escapeHtml16(turn.status)}</span>
|
|
4583
4848
|
</header>
|
|
4584
|
-
<p>${
|
|
4849
|
+
<p>${escapeHtml16(turn.detail)}</p>
|
|
4585
4850
|
<dl>${turn.rows.map((row) => `<div>
|
|
4586
|
-
<dt>${
|
|
4587
|
-
<dd>${
|
|
4851
|
+
<dt>${escapeHtml16(row.label)}</dt>
|
|
4852
|
+
<dd>${escapeHtml16(row.value)}</dd>
|
|
4588
4853
|
</div>`).join("")}</dl>
|
|
4589
4854
|
</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--${
|
|
4855
|
+
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml16(model.status)}">
|
|
4591
4856
|
<header class="absolute-voice-turn-quality__header">
|
|
4592
|
-
<span class="absolute-voice-turn-quality__eyebrow">${
|
|
4593
|
-
<strong class="absolute-voice-turn-quality__label">${
|
|
4857
|
+
<span class="absolute-voice-turn-quality__eyebrow">${escapeHtml16(model.title)}</span>
|
|
4858
|
+
<strong class="absolute-voice-turn-quality__label">${escapeHtml16(model.label)}</strong>
|
|
4594
4859
|
</header>
|
|
4595
|
-
<p class="absolute-voice-turn-quality__description">${
|
|
4860
|
+
<p class="absolute-voice-turn-quality__description">${escapeHtml16(model.description)}</p>
|
|
4596
4861
|
${turns}
|
|
4597
|
-
${model.error ? `<p class="absolute-voice-turn-quality__error">${
|
|
4862
|
+
${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml16(model.error)}</p>` : ""}
|
|
4598
4863
|
</section>`;
|
|
4599
4864
|
};
|
|
4600
4865
|
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}`;
|