@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/index.js
CHANGED
|
@@ -14538,7 +14538,7 @@ var maxNumber = (values) => {
|
|
|
14538
14538
|
return finite.length > 0 ? Math.max(...finite) : undefined;
|
|
14539
14539
|
};
|
|
14540
14540
|
var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
|
|
14541
|
-
var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms;
|
|
14541
|
+
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)));
|
|
14542
14542
|
var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
|
|
14543
14543
|
var readRuntimeChannelMetric = (report, key) => {
|
|
14544
14544
|
const summaryValue = report.summary.runtimeChannel?.[key];
|
|
@@ -14556,6 +14556,91 @@ var readProofTrendRuntimeChannel = (report) => ({
|
|
|
14556
14556
|
samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
|
|
14557
14557
|
status: report.summary.runtimeChannel?.status
|
|
14558
14558
|
});
|
|
14559
|
+
var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
|
|
14560
|
+
var providerSortScore = (provider) => [
|
|
14561
|
+
recommendationStatusRank[provider.status],
|
|
14562
|
+
provider.p95Ms ?? Number.POSITIVE_INFINITY,
|
|
14563
|
+
provider.averageMs ?? Number.POSITIVE_INFINITY,
|
|
14564
|
+
provider.samples === undefined ? Number.POSITIVE_INFINITY : -provider.samples,
|
|
14565
|
+
provider.id
|
|
14566
|
+
];
|
|
14567
|
+
var compareProviders = (left, right) => {
|
|
14568
|
+
const leftScore = providerSortScore(left);
|
|
14569
|
+
const rightScore = providerSortScore(right);
|
|
14570
|
+
for (let index = 0;index < leftScore.length; index += 1) {
|
|
14571
|
+
const leftValue = leftScore[index];
|
|
14572
|
+
const rightValue = rightScore[index];
|
|
14573
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
14574
|
+
if (leftValue !== rightValue) {
|
|
14575
|
+
return leftValue - rightValue;
|
|
14576
|
+
}
|
|
14577
|
+
continue;
|
|
14578
|
+
}
|
|
14579
|
+
const compared = String(leftValue).localeCompare(String(rightValue));
|
|
14580
|
+
if (compared !== 0) {
|
|
14581
|
+
return compared;
|
|
14582
|
+
}
|
|
14583
|
+
}
|
|
14584
|
+
return 0;
|
|
14585
|
+
};
|
|
14586
|
+
var summarizeProofTrendProviders = (report, budgetMs) => {
|
|
14587
|
+
const sourceProviders = report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : undefined;
|
|
14588
|
+
const providersById = new Map;
|
|
14589
|
+
if (sourceProviders) {
|
|
14590
|
+
for (const provider of sourceProviders) {
|
|
14591
|
+
if (provider.id) {
|
|
14592
|
+
providersById.set(provider.id, provider);
|
|
14593
|
+
}
|
|
14594
|
+
}
|
|
14595
|
+
} else {
|
|
14596
|
+
for (const cycle of report.cycles) {
|
|
14597
|
+
for (const provider of cycle.providers ?? []) {
|
|
14598
|
+
if (!provider.id) {
|
|
14599
|
+
continue;
|
|
14600
|
+
}
|
|
14601
|
+
const existing = providersById.get(provider.id);
|
|
14602
|
+
providersById.set(provider.id, {
|
|
14603
|
+
averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
|
|
14604
|
+
id: provider.id,
|
|
14605
|
+
label: existing?.label ?? provider.label,
|
|
14606
|
+
p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
|
|
14607
|
+
p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
|
|
14608
|
+
role: existing?.role ?? provider.role,
|
|
14609
|
+
samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
|
|
14610
|
+
status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
|
|
14611
|
+
});
|
|
14612
|
+
}
|
|
14613
|
+
}
|
|
14614
|
+
}
|
|
14615
|
+
return [...providersById.values()].map((provider) => {
|
|
14616
|
+
const status = provider.p95Ms === undefined ? normalizeProviderStatus(provider.status) : withinBudget(provider.p95Ms, budgetMs) ? normalizeProviderStatus(provider.status) === "fail" ? "fail" : "pass" : normalizeProviderStatus(provider.status) === "fail" ? "fail" : "warn";
|
|
14617
|
+
return {
|
|
14618
|
+
averageMs: provider.averageMs,
|
|
14619
|
+
id: provider.id,
|
|
14620
|
+
label: provider.label,
|
|
14621
|
+
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.",
|
|
14622
|
+
p50Ms: provider.p50Ms,
|
|
14623
|
+
p95Ms: provider.p95Ms,
|
|
14624
|
+
rank: 0,
|
|
14625
|
+
role: provider.role,
|
|
14626
|
+
samples: provider.samples,
|
|
14627
|
+
status
|
|
14628
|
+
};
|
|
14629
|
+
}).sort(compareProviders).map((provider, index) => ({ ...provider, rank: index + 1 }));
|
|
14630
|
+
};
|
|
14631
|
+
var shouldSwitchProvider = (current, best, options) => {
|
|
14632
|
+
if (!current || !best || current.id === best.id || best.status !== "pass") {
|
|
14633
|
+
return false;
|
|
14634
|
+
}
|
|
14635
|
+
if (current.p95Ms === undefined || best.p95Ms === undefined) {
|
|
14636
|
+
return false;
|
|
14637
|
+
}
|
|
14638
|
+
const minImprovementMs = options.providerSwitchMinImprovementMs ?? 100;
|
|
14639
|
+
const minImprovementRatio = options.providerSwitchMinImprovementRatio ?? 0.1;
|
|
14640
|
+
const improvementMs = current.p95Ms - best.p95Ms;
|
|
14641
|
+
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
14642
|
+
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
14643
|
+
};
|
|
14559
14644
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
14560
14645
|
const issues = [];
|
|
14561
14646
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -14647,6 +14732,186 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
14647
14732
|
}
|
|
14648
14733
|
return assertion;
|
|
14649
14734
|
};
|
|
14735
|
+
var DEFAULT_RECOMMENDATION_BUDGETS = {
|
|
14736
|
+
maxLiveP95Ms: 800,
|
|
14737
|
+
maxProviderP95Ms: 1000,
|
|
14738
|
+
maxRuntimeBackpressureEvents: 0,
|
|
14739
|
+
maxRuntimeFirstAudioLatencyMs: 600,
|
|
14740
|
+
maxRuntimeInterruptionP95Ms: 300,
|
|
14741
|
+
maxRuntimeJitterMs: 30,
|
|
14742
|
+
maxRuntimeTimestampDriftMs: 800,
|
|
14743
|
+
maxTurnP95Ms: 700
|
|
14744
|
+
};
|
|
14745
|
+
var withinBudget = (value, budget) => typeof value === "number" && Number.isFinite(value) && value <= budget;
|
|
14746
|
+
var recommendationStatusRank = {
|
|
14747
|
+
pass: 0,
|
|
14748
|
+
warn: 1,
|
|
14749
|
+
fail: 2
|
|
14750
|
+
};
|
|
14751
|
+
var worstRecommendationStatus = (recommendations) => recommendations.reduce((status, recommendation) => recommendationStatusRank[recommendation.status] > recommendationStatusRank[status] ? recommendation.status : status, "pass");
|
|
14752
|
+
var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
14753
|
+
const budgets = { ...DEFAULT_RECOMMENDATION_BUDGETS, ...options };
|
|
14754
|
+
const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
|
|
14755
|
+
const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
|
|
14756
|
+
const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
|
|
14757
|
+
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
14758
|
+
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
14759
|
+
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
14760
|
+
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
14761
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestProvider, options);
|
|
14762
|
+
const recommendations = [];
|
|
14763
|
+
const issues = [];
|
|
14764
|
+
if (report.ok !== true) {
|
|
14765
|
+
issues.push(`Proof trend report is ${report.status}; recommendations need a fresh passing trend artifact.`);
|
|
14766
|
+
}
|
|
14767
|
+
recommendations.push({
|
|
14768
|
+
evidence: {
|
|
14769
|
+
bestProviderId: bestProvider?.id,
|
|
14770
|
+
bestProviderP95Ms: bestProvider?.p95Ms,
|
|
14771
|
+
budgetMs: budgets.maxProviderP95Ms,
|
|
14772
|
+
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
14773
|
+
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
14774
|
+
providerComparisonCount: providers.length,
|
|
14775
|
+
providerP95Ms: maxProviderP95Ms
|
|
14776
|
+
},
|
|
14777
|
+
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.",
|
|
14778
|
+
providerId: bestProvider?.id,
|
|
14779
|
+
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",
|
|
14780
|
+
role: bestProvider?.role,
|
|
14781
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
14782
|
+
surface: "provider-path"
|
|
14783
|
+
});
|
|
14784
|
+
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);
|
|
14785
|
+
recommendations.push({
|
|
14786
|
+
evidence: {
|
|
14787
|
+
backpressureEvents: runtimeChannel.maxBackpressureEvents,
|
|
14788
|
+
firstAudioBudgetMs: budgets.maxRuntimeFirstAudioLatencyMs,
|
|
14789
|
+
firstAudioMs: runtimeChannel.maxFirstAudioLatencyMs,
|
|
14790
|
+
interruptionBudgetMs: budgets.maxRuntimeInterruptionP95Ms,
|
|
14791
|
+
interruptionP95Ms: runtimeChannel.maxInterruptionP95Ms,
|
|
14792
|
+
jitterBudgetMs: budgets.maxRuntimeJitterMs,
|
|
14793
|
+
jitterMs: runtimeChannel.maxJitterMs,
|
|
14794
|
+
samples: runtimeChannel.samples,
|
|
14795
|
+
timestampDriftMs: runtimeChannel.maxTimestampDriftMs
|
|
14796
|
+
},
|
|
14797
|
+
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.",
|
|
14798
|
+
recommendation: runtimePass ? "Keep current runtime channel" : "Tune runtime channel before promotion",
|
|
14799
|
+
status: runtimePass ? "pass" : runtimeChannel.samples === undefined ? "fail" : "warn",
|
|
14800
|
+
surface: "runtime-channel"
|
|
14801
|
+
});
|
|
14802
|
+
recommendations.push({
|
|
14803
|
+
evidence: {
|
|
14804
|
+
budgetMs: budgets.maxLiveP95Ms,
|
|
14805
|
+
liveP95Ms: maxLiveP95Ms
|
|
14806
|
+
},
|
|
14807
|
+
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.",
|
|
14808
|
+
recommendation: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep live-latency settings" : "Tune live-latency path",
|
|
14809
|
+
status: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "pass" : maxLiveP95Ms === undefined ? "fail" : "warn",
|
|
14810
|
+
surface: "live-latency"
|
|
14811
|
+
});
|
|
14812
|
+
recommendations.push({
|
|
14813
|
+
evidence: {
|
|
14814
|
+
budgetMs: budgets.maxTurnP95Ms,
|
|
14815
|
+
turnP95Ms: maxTurnP95Ms
|
|
14816
|
+
},
|
|
14817
|
+
nextMove: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep current turn pipeline defaults." : "Reduce tool/provider latency or split the turn pipeline before promotion.",
|
|
14818
|
+
recommendation: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep turn pipeline" : "Tune turn pipeline",
|
|
14819
|
+
status: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "pass" : maxTurnP95Ms === undefined ? "fail" : "warn",
|
|
14820
|
+
surface: "turn-latency"
|
|
14821
|
+
});
|
|
14822
|
+
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
14823
|
+
return {
|
|
14824
|
+
bestProvider,
|
|
14825
|
+
generatedAt: new Date().toISOString(),
|
|
14826
|
+
issues,
|
|
14827
|
+
ok: status !== "fail",
|
|
14828
|
+
providers,
|
|
14829
|
+
recommendations,
|
|
14830
|
+
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
14831
|
+
status,
|
|
14832
|
+
summary: {
|
|
14833
|
+
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
14834
|
+
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
14835
|
+
providerComparisonCount: providers.length,
|
|
14836
|
+
recommendedActions: recommendations.filter((item) => item.status !== "pass").length,
|
|
14837
|
+
switchRecommended: providerSwitchRecommended
|
|
14838
|
+
}
|
|
14839
|
+
};
|
|
14840
|
+
};
|
|
14841
|
+
var escapeHtml22 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14842
|
+
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
14843
|
+
var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
|
|
14844
|
+
`# ${title}`,
|
|
14845
|
+
"",
|
|
14846
|
+
`- Status: ${report.status}`,
|
|
14847
|
+
`- Source: ${report.source}`,
|
|
14848
|
+
`- Best provider: ${report.bestProvider?.label ?? report.bestProvider?.id ?? "n/a"}`,
|
|
14849
|
+
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
14850
|
+
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
14851
|
+
"",
|
|
14852
|
+
"| Surface | Status | Recommendation | Next move |",
|
|
14853
|
+
"| --- | --- | --- | --- |",
|
|
14854
|
+
...report.recommendations.map((recommendation) => `| ${escapeMarkdown2(recommendation.surface)} | ${recommendation.status} | ${escapeMarkdown2(recommendation.recommendation)} | ${escapeMarkdown2(recommendation.nextMove)} |`),
|
|
14855
|
+
"",
|
|
14856
|
+
"## Provider Comparison",
|
|
14857
|
+
"",
|
|
14858
|
+
"| Rank | Provider | Role | Status | P95 | Samples | Next move |",
|
|
14859
|
+
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
14860
|
+
...report.providers.length ? report.providers.map((provider) => `| ${String(provider.rank)} | ${escapeMarkdown2(provider.label ?? provider.id)} | ${escapeMarkdown2(provider.role ?? "n/a")} | ${provider.status} | ${provider.p95Ms === undefined ? "n/a" : String(provider.p95Ms)} | ${provider.samples === undefined ? "n/a" : String(provider.samples)} | ${escapeMarkdown2(provider.nextMove)} |`) : ["| n/a | n/a | n/a | n/a | n/a | n/a | No provider-specific samples were present. |"],
|
|
14861
|
+
"",
|
|
14862
|
+
"## Issues",
|
|
14863
|
+
"",
|
|
14864
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
14865
|
+
].join(`
|
|
14866
|
+
`);
|
|
14867
|
+
var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
|
|
14868
|
+
const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml22(recommendation.status)}"><p class="eyebrow">${escapeHtml22(recommendation.surface)} \xB7 ${escapeHtml22(recommendation.status)}</p><h2>${escapeHtml22(recommendation.recommendation)}</h2><p>${escapeHtml22(recommendation.nextMove)}</p><pre>${escapeHtml22(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
|
|
14869
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml22(issue)}</li>`).join("");
|
|
14870
|
+
const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml22(provider.label ?? provider.id)}</strong><span>${escapeHtml22(provider.role ?? "provider")} \xB7 ${escapeHtml22(provider.status)} \xB7 p95 ${escapeHtml22(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml22(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml22(provider.nextMove)}</small></li>`).join("");
|
|
14871
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml22(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>${escapeHtml22(title)}</h1><p>Generated ${escapeHtml22(report.generatedAt)} from ${escapeHtml22(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml22(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best ${escapeHtml22(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>`;
|
|
14872
|
+
};
|
|
14873
|
+
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
14874
|
+
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
|
14875
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/proof-trend-recommendations" : options.htmlPath;
|
|
14876
|
+
const markdownPath = options.markdownPath === undefined ? "/voice/proof-trend-recommendations.md" : options.markdownPath;
|
|
14877
|
+
const title = options.title ?? "Voice Provider Runtime Recommendations";
|
|
14878
|
+
const routes = new Elysia20({
|
|
14879
|
+
name: options.name ?? "absolutejs-voice-proof-trend-recommendations"
|
|
14880
|
+
});
|
|
14881
|
+
const loadReport = async () => {
|
|
14882
|
+
const value = options.source !== undefined ? typeof options.source === "function" ? await options.source() : options.source : options.jsonPath ? await readVoiceProofTrendReportFile(options.jsonPath, {
|
|
14883
|
+
maxAgeMs: options.maxAgeMs
|
|
14884
|
+
}) : buildEmptyVoiceProofTrendReport("", options.maxAgeMs);
|
|
14885
|
+
return buildVoiceProofTrendRecommendationReport(normalizeVoiceProofTrendReport(value, {
|
|
14886
|
+
maxAgeMs: options.maxAgeMs,
|
|
14887
|
+
source: options.jsonPath
|
|
14888
|
+
}), options);
|
|
14889
|
+
};
|
|
14890
|
+
routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
|
|
14891
|
+
if (htmlPath !== false) {
|
|
14892
|
+
routes.get(htmlPath, async () => {
|
|
14893
|
+
const report = await loadReport();
|
|
14894
|
+
return new Response(renderVoiceProofTrendRecommendationHTML(report, title), {
|
|
14895
|
+
headers: {
|
|
14896
|
+
"content-type": "text/html; charset=utf-8",
|
|
14897
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
14898
|
+
}
|
|
14899
|
+
});
|
|
14900
|
+
});
|
|
14901
|
+
}
|
|
14902
|
+
if (markdownPath !== false) {
|
|
14903
|
+
routes.get(markdownPath, async () => {
|
|
14904
|
+
const report = await loadReport();
|
|
14905
|
+
return new Response(renderVoiceProofTrendRecommendationMarkdown(report, title), {
|
|
14906
|
+
headers: {
|
|
14907
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
14908
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
14909
|
+
}
|
|
14910
|
+
});
|
|
14911
|
+
});
|
|
14912
|
+
}
|
|
14913
|
+
return routes;
|
|
14914
|
+
};
|
|
14650
14915
|
var createVoiceProofTrendRoutes = (options) => {
|
|
14651
14916
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
14652
14917
|
const routes = new Elysia20({
|
|
@@ -14686,7 +14951,7 @@ import { Elysia as Elysia22 } from "elysia";
|
|
|
14686
14951
|
|
|
14687
14952
|
// src/resilienceRoutes.ts
|
|
14688
14953
|
import { Elysia as Elysia21 } from "elysia";
|
|
14689
|
-
var
|
|
14954
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14690
14955
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
14691
14956
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14692
14957
|
var getBoolean2 = (value) => value === true;
|
|
@@ -14834,13 +15099,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
14834
15099
|
};
|
|
14835
15100
|
var renderProviderCards = (title, providers) => {
|
|
14836
15101
|
if (providers.length === 0) {
|
|
14837
|
-
return `<p class="muted">No ${
|
|
15102
|
+
return `<p class="muted">No ${escapeHtml23(title)} provider health yet.</p>`;
|
|
14838
15103
|
}
|
|
14839
15104
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
14840
|
-
<article class="card provider ${
|
|
15105
|
+
<article class="card provider ${escapeHtml23(provider.status)}">
|
|
14841
15106
|
<div class="card-header">
|
|
14842
|
-
<strong>${
|
|
14843
|
-
<span>${
|
|
15107
|
+
<strong>${escapeHtml23(provider.provider)}</strong>
|
|
15108
|
+
<span>${escapeHtml23(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
14844
15109
|
</div>
|
|
14845
15110
|
<dl>
|
|
14846
15111
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -14849,7 +15114,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
14849
15114
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
14850
15115
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
14851
15116
|
</dl>
|
|
14852
|
-
${provider.lastError ? `<p class="muted">${
|
|
15117
|
+
${provider.lastError ? `<p class="muted">${escapeHtml23(provider.lastError)}</p>` : ""}
|
|
14853
15118
|
</article>
|
|
14854
15119
|
`).join("")}</div>`;
|
|
14855
15120
|
};
|
|
@@ -14858,24 +15123,24 @@ var renderTimeline2 = (events) => {
|
|
|
14858
15123
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
14859
15124
|
}
|
|
14860
15125
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
14861
|
-
<article class="card event ${
|
|
15126
|
+
<article class="card event ${escapeHtml23(event.status ?? "unknown")}">
|
|
14862
15127
|
<div class="card-header">
|
|
14863
|
-
<strong>${
|
|
15128
|
+
<strong>${escapeHtml23(event.kind.toUpperCase())} ${escapeHtml23(event.operation ?? "generate")}</strong>
|
|
14864
15129
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
14865
15130
|
</div>
|
|
14866
15131
|
<p>
|
|
14867
|
-
<span class="pill">${
|
|
14868
|
-
<span class="pill">provider: ${
|
|
14869
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
15132
|
+
<span class="pill">${escapeHtml23(event.status ?? "unknown")}</span>
|
|
15133
|
+
<span class="pill">provider: ${escapeHtml23(event.provider ?? "unknown")}</span>
|
|
15134
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml23(event.fallbackProvider)}</span>` : ""}
|
|
14870
15135
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
14871
15136
|
</p>
|
|
14872
15137
|
<dl>
|
|
14873
15138
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
14874
15139
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
14875
15140
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
14876
|
-
<div><dt>Session</dt><dd>${
|
|
15141
|
+
<div><dt>Session</dt><dd>${escapeHtml23(event.sessionId)}</dd></div>
|
|
14877
15142
|
</dl>
|
|
14878
|
-
${event.error ? `<p class="muted">${
|
|
15143
|
+
${event.error ? `<p class="muted">${escapeHtml23(event.error)}</p>` : ""}
|
|
14879
15144
|
</article>
|
|
14880
15145
|
`).join("")}</div>`;
|
|
14881
15146
|
};
|
|
@@ -14885,9 +15150,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
14885
15150
|
const status = latest?.status ?? "idle";
|
|
14886
15151
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
14887
15152
|
return `<div>
|
|
14888
|
-
<dt>${
|
|
14889
|
-
<dd>${
|
|
14890
|
-
<small>${
|
|
15153
|
+
<dt>${escapeHtml23(kind.toUpperCase())}</dt>
|
|
15154
|
+
<dd>${escapeHtml23(provider)}${escapeHtml23(fallback)}</dd>
|
|
15155
|
+
<small>${escapeHtml23(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
|
|
14891
15156
|
</div>`;
|
|
14892
15157
|
};
|
|
14893
15158
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -14895,10 +15160,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
14895
15160
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
14896
15161
|
}
|
|
14897
15162
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
14898
|
-
<article class="card session ${
|
|
15163
|
+
<article class="card session ${escapeHtml23(session.status)}">
|
|
14899
15164
|
<div class="card-header">
|
|
14900
|
-
<strong>${
|
|
14901
|
-
<span>${
|
|
15165
|
+
<strong>${escapeHtml23(session.sessionId)}</strong>
|
|
15166
|
+
<span>${escapeHtml23(session.status)}</span>
|
|
14902
15167
|
</div>
|
|
14903
15168
|
<p>
|
|
14904
15169
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -14925,21 +15190,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
14925
15190
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
14926
15191
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
14927
15192
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
14928
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
14929
|
-
<p class="muted">${
|
|
15193
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml23(pathPrefix)}">
|
|
15194
|
+
<p class="muted">${escapeHtml23(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
14930
15195
|
<div class="simulate-actions">
|
|
14931
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
14932
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
15196
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml23(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml23(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
15197
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml23(provider.provider)}">Mark ${escapeHtml23(provider.provider)} recovered</button>`).join("")}
|
|
14933
15198
|
</div>
|
|
14934
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
15199
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml23(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
14935
15200
|
<pre class="simulate-output" hidden></pre>
|
|
14936
15201
|
</div>`;
|
|
14937
15202
|
};
|
|
14938
15203
|
var renderVoiceResilienceHTML = (input) => {
|
|
14939
15204
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
14940
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
14941
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
14942
|
-
const snippet =
|
|
15205
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml23(kind)}: ${String(count)}</span>`).join("");
|
|
15206
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml23(link.href)}">${escapeHtml23(link.label)}</a>`).join(" \xB7 ") : "";
|
|
15207
|
+
const snippet = escapeHtml23(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
14943
15208
|
kind: 'stt',
|
|
14944
15209
|
providers: ['deepgram', 'assemblyai'],
|
|
14945
15210
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -14977,7 +15242,7 @@ app.use(
|
|
|
14977
15242
|
<head>
|
|
14978
15243
|
<meta charset="utf-8" />
|
|
14979
15244
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14980
|
-
<title>${
|
|
15245
|
+
<title>${escapeHtml23(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
14981
15246
|
<style>
|
|
14982
15247
|
:root { color-scheme: dark; }
|
|
14983
15248
|
body { background: radial-gradient(circle at top left, #172554, #09090b 36%, #050505); color: #f4f4f5; font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; }
|
|
@@ -15170,7 +15435,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
15170
15435
|
};
|
|
15171
15436
|
|
|
15172
15437
|
// src/providerDecisionTraces.ts
|
|
15173
|
-
var
|
|
15438
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15174
15439
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
15175
15440
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
15176
15441
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -15411,7 +15676,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
15411
15676
|
<head>
|
|
15412
15677
|
<meta charset="utf-8" />
|
|
15413
15678
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15414
|
-
<title>${
|
|
15679
|
+
<title>${escapeHtml24(title)}</title>
|
|
15415
15680
|
<style>
|
|
15416
15681
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
15417
15682
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -15425,8 +15690,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
15425
15690
|
</head>
|
|
15426
15691
|
<body>
|
|
15427
15692
|
<main>
|
|
15428
|
-
<p class="status ${report.status}">${
|
|
15429
|
-
<h1>${
|
|
15693
|
+
<p class="status ${report.status}">${escapeHtml24(report.status)}</p>
|
|
15694
|
+
<h1>${escapeHtml24(title)}</h1>
|
|
15430
15695
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
15431
15696
|
<section class="grid">
|
|
15432
15697
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -15437,10 +15702,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
15437
15702
|
</section>
|
|
15438
15703
|
<section class="surfaces">
|
|
15439
15704
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
15440
|
-
<header><strong>${
|
|
15705
|
+
<header><strong>${escapeHtml24(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml24(surface.status)}</span></header>
|
|
15441
15706
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
15442
|
-
<p class="muted">Providers: ${
|
|
15443
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
15707
|
+
<p class="muted">Providers: ${escapeHtml24(surface.providers.join(", ") || "none")}</p>
|
|
15708
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml24(reason)}</code>`).join(" ")}</p>
|
|
15444
15709
|
</article>`).join(`
|
|
15445
15710
|
`)}
|
|
15446
15711
|
</section>
|
|
@@ -15662,8 +15927,8 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
15662
15927
|
status: profile.status
|
|
15663
15928
|
};
|
|
15664
15929
|
};
|
|
15665
|
-
var
|
|
15666
|
-
var
|
|
15930
|
+
var escapeMarkdown3 = (value) => value.replaceAll("|", "\\|");
|
|
15931
|
+
var escapeHtml25 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15667
15932
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
15668
15933
|
var readinessThresholdRows = (report) => [
|
|
15669
15934
|
{
|
|
@@ -15708,7 +15973,7 @@ var readinessThresholdRows = (report) => [
|
|
|
15708
15973
|
}
|
|
15709
15974
|
];
|
|
15710
15975
|
var renderVoiceSloCalibrationMarkdown = (report, options = {}) => {
|
|
15711
|
-
const rows = Object.values(report.thresholds).map((threshold) => `| ${
|
|
15976
|
+
const rows = Object.values(report.thresholds).map((threshold) => `| ${escapeMarkdown3(threshold.metric)} | ${threshold.status} | ${threshold.samples} | ${threshold.baselineP95Ms ?? "n/a"} | ${threshold.warnAfterMs ?? "n/a"} | ${threshold.failAfterMs ?? "n/a"} |`).join(`
|
|
15712
15977
|
`);
|
|
15713
15978
|
return `# ${options.title ?? "Voice SLO Calibration"}
|
|
15714
15979
|
|
|
@@ -15729,7 +15994,7 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
15729
15994
|
`;
|
|
15730
15995
|
};
|
|
15731
15996
|
var renderVoiceSloReadinessThresholdMarkdown = (report, options = {}) => {
|
|
15732
|
-
const rows = readinessThresholdRows(report).map((row) => `| ${
|
|
15997
|
+
const rows = readinessThresholdRows(report).map((row) => `| ${escapeMarkdown3(row.control)} | ${formatMs(row.value)} | ${escapeMarkdown3(row.usedBy)} |`).join(`
|
|
15733
15998
|
`);
|
|
15734
15999
|
return `# ${options.title ?? "Calibration -> Active Readiness Gate"}
|
|
15735
16000
|
|
|
@@ -15754,10 +16019,10 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
15754
16019
|
};
|
|
15755
16020
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
15756
16021
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
15757
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
15758
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
15759
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
15760
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
16022
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml25(row.control)}</td><td>${escapeHtml25(formatMs(row.value))}</td><td>${escapeHtml25(row.usedBy)}</td></tr>`).join("");
|
|
16023
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml25(issue)}</li>`).join("");
|
|
16024
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml25(source)}</code></li>`).join("");
|
|
16025
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1040px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}.status{font-size:1.6rem;font-weight:800;text-transform:uppercase}</style></head><body><main><h1>${escapeHtml25(title)}</h1><p>This page shows the calibrated thresholds currently driving production readiness gates.</p><section class="summary"><div class="card"><strong>Status</strong><br><span class="status">${escapeHtml25(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml25(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml25(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml25(formatMs(report.bargeIn.thresholdMs))}</div></section><h2>Active Readiness Thresholds</h2><table><thead><tr><th>Threshold</th><th>Active value</th><th>Used by</th></tr></thead><tbody>${rows}</tbody></table><h2>Sources</h2><ul>${sources}</ul><h2>Issues</h2><ul>${issues}</ul></main></body></html>`;
|
|
15761
16026
|
};
|
|
15762
16027
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
15763
16028
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
@@ -16155,12 +16420,12 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
16155
16420
|
import { Elysia as Elysia25 } from "elysia";
|
|
16156
16421
|
import { mkdir } from "fs/promises";
|
|
16157
16422
|
import { dirname, join } from "path";
|
|
16158
|
-
var
|
|
16423
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16159
16424
|
var renderSummaryCard = (label, summary) => {
|
|
16160
16425
|
if (!summary) {
|
|
16161
|
-
return `<article><span>${
|
|
16426
|
+
return `<article><span>${escapeHtml26(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
16162
16427
|
}
|
|
16163
|
-
return `<article><span>${
|
|
16428
|
+
return `<article><span>${escapeHtml26(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending · ${String(summary.failed)} failed · ${String(summary.deadLettered)} dead-lettered</p></article>`;
|
|
16164
16429
|
};
|
|
16165
16430
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
16166
16431
|
audit: leases,
|
|
@@ -16371,9 +16636,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
16371
16636
|
});
|
|
16372
16637
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
16373
16638
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
16374
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
16375
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
16376
|
-
const snippet =
|
|
16639
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml26(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
16640
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml26(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
16641
|
+
const snippet = escapeHtml26(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
16377
16642
|
createVoiceDeliveryRuntimePresetConfig({
|
|
16378
16643
|
audit: {
|
|
16379
16644
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -16399,7 +16664,7 @@ app.use(
|
|
|
16399
16664
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
16400
16665
|
})
|
|
16401
16666
|
);`);
|
|
16402
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16667
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{background:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}.primitive{background:#111a15;border-color:#41604a}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}.primitive p{color:#c8d8ca;line-height:1.55}.primitive code{color:#bbf7d0}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml26(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml26(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceDeliveryRuntimeRoutes(...)</code> builds this control plane</h2><p>Own the audit and trace delivery queues in your app, mount one runtime route group, and pass the same runtime into production readiness so failed or dead-lettered exports block deploys.</p><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
16403
16668
|
};
|
|
16404
16669
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
16405
16670
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
@@ -16681,7 +16946,7 @@ var parseRetentionScopes = (value) => {
|
|
|
16681
16946
|
const allowed = new Set(allRetentionScopes);
|
|
16682
16947
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
16683
16948
|
};
|
|
16684
|
-
var
|
|
16949
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16685
16950
|
var buildStorageSurfaces = (options) => [
|
|
16686
16951
|
{
|
|
16687
16952
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -16918,12 +17183,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
16918
17183
|
zeroRetentionAvailable: true
|
|
16919
17184
|
};
|
|
16920
17185
|
};
|
|
16921
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
17186
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml27(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml27(scope.skippedReason ?? "")}</td><td><code>${escapeHtml27(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
16922
17187
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
16923
17188
|
const title = options.title ?? "Voice Data Control";
|
|
16924
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
16925
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
16926
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
17189
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml27(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml27(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
17190
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml27(key.name)}</td><td><code>${escapeHtml27(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml27(key.recommendation)}</td></tr>`).join("");
|
|
17191
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml27(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1120px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml27(title)}</h1><p>Self-hosted data-control proof for retention, redaction, audit export, deletion planning, customer-owned storage, and provider key handling.</p><section class="summary"><div class="card"><strong>Redaction</strong><br>${report.redaction.enabled ? "enabled" : "disabled"}</div><div class="card"><strong>Retention dry-run deletes</strong><br>${report.retentionPlan.deletedCount}</div><div class="card"><strong>Audit export events</strong><br>${report.auditExport?.events.length ?? 0}</div><div class="card"><strong>Zero retention recipe</strong><br>${report.zeroRetentionAvailable ? "available" : "missing"}</div></section><h2>Customer-Owned Storage</h2><table><thead><tr><th>Surface</th><th>Status</th><th>Control</th><th>Self-hosted</th></tr></thead><tbody>${storageRows}</tbody></table><h2>Retention Plan</h2><table><thead><tr><th>Scope</th><th>Scanned</th><th>Would delete</th><th>Skipped</th><th>Ids</th></tr></thead><tbody>${renderDataRetentionReportRows(report.retentionPlan)}</tbody></table><h2>Provider Keys</h2><table><thead><tr><th>Provider</th><th>Env</th><th>Required</th><th>Recommendation</th></tr></thead><tbody>${keyRows}</tbody></table><p><a href="./data-control/audit.md">Redacted audit Markdown</a> \xB7 <a href="./data-control/audit.html">Redacted audit HTML</a></p></main></body></html>`;
|
|
16927
17192
|
};
|
|
16928
17193
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
16929
17194
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -17066,7 +17331,7 @@ import { Elysia as Elysia28 } from "elysia";
|
|
|
17066
17331
|
|
|
17067
17332
|
// src/handoffHealth.ts
|
|
17068
17333
|
import { Elysia as Elysia27 } from "elysia";
|
|
17069
|
-
var
|
|
17334
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17070
17335
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
17071
17336
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
17072
17337
|
var increment3 = (record, key) => {
|
|
@@ -17184,10 +17449,10 @@ var renderActionSummary = (summary) => {
|
|
|
17184
17449
|
return [
|
|
17185
17450
|
'<section class="voice-handoff-health-columns">',
|
|
17186
17451
|
"<article><h3>Actions</h3>",
|
|
17187
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
17452
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml28(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
17188
17453
|
"</article>",
|
|
17189
17454
|
"<article><h3>Adapters</h3>",
|
|
17190
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
17455
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml28(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
17191
17456
|
"</article>",
|
|
17192
17457
|
"</section>"
|
|
17193
17458
|
].join("");
|
|
@@ -17201,22 +17466,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
17201
17466
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
17202
17467
|
'<div class="voice-handoff-health-events">',
|
|
17203
17468
|
...summary.events.map((event) => [
|
|
17204
|
-
`<article class="${
|
|
17469
|
+
`<article class="${escapeHtml28(event.status)}">`,
|
|
17205
17470
|
'<div class="voice-handoff-health-event-header">',
|
|
17206
|
-
`<strong>${
|
|
17207
|
-
`<span>${
|
|
17471
|
+
`<strong>${escapeHtml28(event.action ?? "handoff")}</strong>`,
|
|
17472
|
+
`<span>${escapeHtml28(event.status)}</span>`,
|
|
17208
17473
|
"</div>",
|
|
17209
|
-
`<p><small>${
|
|
17210
|
-
event.target ? `<p>Target: ${
|
|
17211
|
-
event.reason ? `<p>Reason: ${
|
|
17474
|
+
`<p><small>${escapeHtml28(event.sessionId)}</small></p>`,
|
|
17475
|
+
event.target ? `<p>Target: ${escapeHtml28(event.target)}</p>` : "",
|
|
17476
|
+
event.reason ? `<p>Reason: ${escapeHtml28(event.reason)}</p>` : "",
|
|
17212
17477
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
17213
17478
|
"<li>",
|
|
17214
|
-
`${
|
|
17215
|
-
delivery.deliveredTo ? ` to ${
|
|
17216
|
-
delivery.error ? ` (${
|
|
17479
|
+
`${escapeHtml28(delivery.adapterId)}: ${escapeHtml28(delivery.status)}`,
|
|
17480
|
+
delivery.deliveredTo ? ` to ${escapeHtml28(delivery.deliveredTo)}` : "",
|
|
17481
|
+
delivery.error ? ` (${escapeHtml28(delivery.error)})` : "",
|
|
17217
17482
|
"</li>"
|
|
17218
17483
|
].join("")).join("")}</ul>` : "",
|
|
17219
|
-
event.replayHref ? `<p><a href="${
|
|
17484
|
+
event.replayHref ? `<p><a href="${escapeHtml28(event.replayHref)}">Open replay</a></p>` : "",
|
|
17220
17485
|
"</article>"
|
|
17221
17486
|
].join("")),
|
|
17222
17487
|
"</div>"
|
|
@@ -17369,12 +17634,12 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
17369
17634
|
thresholds
|
|
17370
17635
|
};
|
|
17371
17636
|
};
|
|
17372
|
-
var
|
|
17637
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17373
17638
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
17374
17639
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
17375
17640
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
17376
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
17377
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17641
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml29(metric.label)}</td><td>${escapeHtml29(formatMetricValue(metric))}</td><td>${escapeHtml29(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml29(key)}</code></td></tr>`).join("");
|
|
17642
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml29(link.href)}">${escapeHtml29(link.label)}</a>`).join("")}</nav>` : "";
|
|
17378
17643
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>AbsoluteJS Voice Quality</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}nav{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 1.25rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;padding:.35rem .75rem;font-weight:800}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}table{border-collapse:collapse;width:100%;background:white;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}.pass td{border-left:4px solid #16a34a}.fail td{border-left:4px solid #dc2626}code{background:#f3f4f6;padding:.15rem .3rem;border-radius:.3rem}</style></head><body><main>${links}<h1>Voice quality gates</h1><p class="status ${report.status}">${report.status}</p><p>${report.eventCount} event(s) checked.</p><table><thead><tr><th>Metric</th><th>Actual</th><th>Threshold</th><th>Status</th><th>Key</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
17379
17644
|
};
|
|
17380
17645
|
var createVoiceQualityRoutes = (options) => {
|
|
@@ -17408,7 +17673,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
17408
17673
|
};
|
|
17409
17674
|
|
|
17410
17675
|
// src/evalRoutes.ts
|
|
17411
|
-
var
|
|
17676
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17412
17677
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
17413
17678
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
17414
17679
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -17730,7 +17995,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
17730
17995
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
17731
17996
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
17732
17997
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
17733
|
-
const snippet =
|
|
17998
|
+
const snippet = escapeHtml30(`app.use(
|
|
17734
17999
|
createVoiceEvalRoutes({
|
|
17735
18000
|
path: '/evals',
|
|
17736
18001
|
store: traceStore,
|
|
@@ -17751,44 +18016,44 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
17751
18016
|
};
|
|
17752
18017
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
17753
18018
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
17754
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17755
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
18019
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
18020
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml30(bucket.key)}</td><td>${bucket.total}</td><td>${bucket.passed}</td><td>${bucket.failed}</td></tr>`).join("") : '<tr><td colspan="4">No eval buckets yet.</td></tr>';
|
|
17756
18021
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
17757
18022
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
17758
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17759
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
18023
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml30(session.operationsRecordHref)}">${escapeHtml30(session.sessionId)}</a>` : escapeHtml30(session.sessionId);
|
|
18024
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml30(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml30(formatTime(session.endedAt))}</td><td>${escapeHtml30(failedMetrics || "none")}</td></tr>`;
|
|
17760
18025
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
17761
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18026
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,.primitive{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3;margin:1rem 0}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml30(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}<h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
17762
18027
|
};
|
|
17763
18028
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
17764
18029
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
17765
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17766
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
17767
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
17768
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
17769
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18030
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
18031
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml30(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
18032
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml30(id)}</li>`).join("") : "<li>none</li>";
|
|
18033
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml30(id)}</li>`).join("") : "<li>none</li>";
|
|
18034
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1000px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{background:#dcfce7;color:#166534}.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{background:white;border:1px solid #e7e5e4;border-radius:1rem;margin:1rem 0;padding:1rem}</style></head><body><main>${links}<h1>${escapeHtml30(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml30(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml30(formatPercent(comparison.current.passRate))}</strong></article><article class="card"><span>Failed delta</span><strong>${comparison.deltas.failed}</strong></article><article class="card"><span>Pass rate delta</span><strong>${escapeHtml30(formatPercent(comparison.deltas.passRate))}</strong></article></div><section><h2>Regression Reasons</h2><ul>${reasons}</ul></section><section><h2>New Failed Sessions</h2><ul>${newFailures}</ul></section><section><h2>Recovered Sessions</h2><ul>${recovered}</ul></section></main></body></html>`;
|
|
17770
18035
|
};
|
|
17771
18036
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
17772
18037
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
17773
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
18038
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
17774
18039
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
17775
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
18040
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml30(issue)}</li>`).join("")}</ul>` : "";
|
|
17776
18041
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
17777
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17778
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
18042
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml30(session.operationsRecordHref)}">${escapeHtml30(session.sessionId)}</a>` : escapeHtml30(session.sessionId);
|
|
18043
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml30(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml30(session.issues.join(", ") || "none")}</td></tr>`;
|
|
17779
18044
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
17780
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
18045
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml30(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml30(scenario.description)}</p>` : ""}<p class="status ${scenario.status}">${scenario.status}</p><p>${scenario.passed} passed, ${scenario.failed} failed, ${scenario.matchedSessions} matched.</p>${scenarioIssues}<table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Issues</th></tr></thead><tbody>${sessions}</tbody></table></section>`;
|
|
17781
18046
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
17782
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18047
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml30(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${scenarios}</main></body></html>`;
|
|
17783
18048
|
};
|
|
17784
18049
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
17785
18050
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
17786
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
18051
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
17787
18052
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
17788
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
17789
|
-
return `<section class="${fixture.status}"><h2>${
|
|
18053
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml30(scenario.label)}</td><td>${escapeHtml30(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml30([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
18054
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml30(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml30(fixture.description)}</p>` : ""}<p class="status ${fixture.status}">${fixture.status}</p><table><thead><tr><th>Scenario</th><th>Status</th><th>Sessions</th><th>Issues</th></tr></thead><tbody>${scenarios}</tbody></table></section>`;
|
|
17790
18055
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
17791
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18056
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml30(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${fixtures}</main></body></html>`;
|
|
17792
18057
|
};
|
|
17793
18058
|
var createVoiceEvalRoutes = (options) => {
|
|
17794
18059
|
const path = options.path ?? "/evals";
|
|
@@ -17933,7 +18198,7 @@ import { Elysia as Elysia32 } from "elysia";
|
|
|
17933
18198
|
|
|
17934
18199
|
// src/outcomeContract.ts
|
|
17935
18200
|
import { Elysia as Elysia30 } from "elysia";
|
|
17936
|
-
var
|
|
18201
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17937
18202
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
17938
18203
|
if (value === false) {
|
|
17939
18204
|
return;
|
|
@@ -18144,13 +18409,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
18144
18409
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
18145
18410
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
18146
18411
|
const contracts = report.contracts.map((contract) => {
|
|
18147
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
18412
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml31(href)}">${escapeHtml31(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
18148
18413
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
18149
18414
|
<div class="contract-header">
|
|
18150
18415
|
<div>
|
|
18151
|
-
<p class="eyebrow">${
|
|
18152
|
-
<h2>${
|
|
18153
|
-
${contract.description ? `<p>${
|
|
18416
|
+
<p class="eyebrow">${escapeHtml31(contract.contractId)}</p>
|
|
18417
|
+
<h2>${escapeHtml31(contract.label ?? contract.contractId)}</h2>
|
|
18418
|
+
${contract.description ? `<p>${escapeHtml31(contract.description)}</p>` : ""}
|
|
18154
18419
|
${sessionLinks}
|
|
18155
18420
|
</div>
|
|
18156
18421
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -18162,10 +18427,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
18162
18427
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
18163
18428
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
18164
18429
|
</div>
|
|
18165
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
18430
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml31(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
18166
18431
|
</section>`;
|
|
18167
18432
|
}).join("");
|
|
18168
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18433
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(14,165,233,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary,.grid{display:flex;flex-wrap:wrap;gap:10px}.pill,.grid span{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}li{margin:8px 0}@media(max-width:800px){main{padding:18px}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Business Outcome Verification</p><h1>${escapeHtml31(title)}</h1><div class="summary"><span class="pill ${report.status}">${report.status}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No outcome contracts configured.</p></section>'}</main></body></html>`;
|
|
18169
18434
|
};
|
|
18170
18435
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
18171
18436
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -18400,7 +18665,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
18400
18665
|
});
|
|
18401
18666
|
var defaultApi = {};
|
|
18402
18667
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
18403
|
-
var
|
|
18668
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18404
18669
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
18405
18670
|
if (value === false) {
|
|
18406
18671
|
return;
|
|
@@ -18649,7 +18914,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
18649
18914
|
};
|
|
18650
18915
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
18651
18916
|
const title = options.title ?? "Voice Tool Contracts";
|
|
18652
|
-
const snippet =
|
|
18917
|
+
const snippet = escapeHtml32(`app.use(
|
|
18653
18918
|
createVoiceToolContractRoutes({
|
|
18654
18919
|
htmlPath: '/tool-contracts',
|
|
18655
18920
|
path: '/api/tool-contracts',
|
|
@@ -18675,20 +18940,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18675
18940
|
);`);
|
|
18676
18941
|
const contracts = report.contracts.map((contract) => {
|
|
18677
18942
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
18678
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
18943
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml32(testCase.operationsRecordHref)}">${escapeHtml32(testCase.label ?? testCase.caseId)}</a>` : escapeHtml32(testCase.label ?? testCase.caseId)}</td>
|
|
18679
18944
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
18680
|
-
<td>${
|
|
18681
|
-
<td>${
|
|
18945
|
+
<td>${escapeHtml32(testCase.status)}</td>
|
|
18946
|
+
<td>${escapeHtml32(testCase.sessionId)}</td>
|
|
18682
18947
|
<td>${String(testCase.attempts)}</td>
|
|
18683
18948
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
18684
18949
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
18685
|
-
<td>${
|
|
18950
|
+
<td>${escapeHtml32(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
18686
18951
|
</tr>`).join("");
|
|
18687
18952
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
18688
18953
|
<div class="contract-header">
|
|
18689
18954
|
<div>
|
|
18690
|
-
<p class="eyebrow">${
|
|
18691
|
-
<h2>${
|
|
18955
|
+
<p class="eyebrow">${escapeHtml32(contract.toolName)}</p>
|
|
18956
|
+
<h2>${escapeHtml32(contract.label ?? contract.contractId)}</h2>
|
|
18692
18957
|
</div>
|
|
18693
18958
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
18694
18959
|
</div>
|
|
@@ -18698,7 +18963,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18698
18963
|
</table>
|
|
18699
18964
|
</section>`;
|
|
18700
18965
|
}).join("");
|
|
18701
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18966
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.primitive{background:#151b20;border-color:#5a4421}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}.primitive p{color:#d8dee6;line-height:1.55}.primitive pre{background:#0f1217;border:1px solid #2a323a;border-radius:16px;color:#fef3c7;overflow:auto;padding:14px}.primitive code{color:#fef3c7}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml32(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml32(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceToolContractRoutes(...)</code> certifies tool behavior</h2><p>Define deterministic tool cases for retries, idempotency, timeouts, result shape, and error handling so assistant tools fail in pre-production instead of live calls.</p><pre><code>${snippet}</code></pre></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
|
|
18702
18967
|
};
|
|
18703
18968
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
18704
18969
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -18725,7 +18990,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
18725
18990
|
};
|
|
18726
18991
|
|
|
18727
18992
|
// src/simulationSuite.ts
|
|
18728
|
-
var
|
|
18993
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18729
18994
|
var summarizeSection = (report) => ({
|
|
18730
18995
|
failed: report.failed,
|
|
18731
18996
|
passed: report.passed,
|
|
@@ -18921,15 +19186,15 @@ var renderSection = (label, summary) => {
|
|
|
18921
19186
|
if (!summary) {
|
|
18922
19187
|
return "";
|
|
18923
19188
|
}
|
|
18924
|
-
return `<article class="${
|
|
19189
|
+
return `<article class="${escapeHtml33(summary.status)}"><span>${escapeHtml33(label)}</span><strong>${escapeHtml33(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
18925
19190
|
};
|
|
18926
19191
|
var renderAction = (action) => {
|
|
18927
|
-
const content = `<strong>${
|
|
18928
|
-
return action.href ? `<a class="action" href="${
|
|
19192
|
+
const content = `<strong>${escapeHtml33(action.label)}</strong><p>${escapeHtml33(action.description)}</p><span>${escapeHtml33(action.section)} / ${escapeHtml33(action.severity)}</span>`;
|
|
19193
|
+
return action.href ? `<a class="action" href="${escapeHtml33(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
18929
19194
|
};
|
|
18930
19195
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
18931
19196
|
const title = options.title ?? "Voice Simulation Suite";
|
|
18932
|
-
const snippet =
|
|
19197
|
+
const snippet = escapeHtml33(`app.use(
|
|
18933
19198
|
createVoiceSimulationSuiteRoutes({
|
|
18934
19199
|
htmlPath: '/voice/simulations',
|
|
18935
19200
|
path: '/api/voice/simulations',
|
|
@@ -18962,7 +19227,7 @@ app.use(
|
|
|
18962
19227
|
store: traceStore
|
|
18963
19228
|
})
|
|
18964
19229
|
);`);
|
|
18965
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19230
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#355078}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p,.primitive p{color:#d8dee6;line-height:1.55;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}.primitive pre{background:#0b1118;color:#dbeafe}.primitive code{color:#bfdbfe}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml33(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml33(report.status)}">Status: ${escapeHtml33(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceSimulationSuiteRoutes(...)</code> builds this pre-production proof surface</h2><p>Run session quality checks, scenario evals, fixture-backed simulations, tool contracts, and outcome contracts from one route group before live traffic sees a regression.</p><pre><code>${snippet}</code></pre></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml33(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
18966
19231
|
};
|
|
18967
19232
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
18968
19233
|
const path = options.path ?? "/api/voice/simulations";
|
|
@@ -19281,7 +19546,7 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
19281
19546
|
// src/sessionReplay.ts
|
|
19282
19547
|
import { Elysia as Elysia33 } from "elysia";
|
|
19283
19548
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
19284
|
-
var
|
|
19549
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19285
19550
|
var increment4 = (record, key) => {
|
|
19286
19551
|
record[key] = (record[key] ?? 0) + 1;
|
|
19287
19552
|
};
|
|
@@ -19475,10 +19740,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
19475
19740
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
19476
19741
|
'<div class="voice-sessions-list">',
|
|
19477
19742
|
...sessions.map((session) => [
|
|
19478
|
-
`<article class="voice-session-card ${
|
|
19743
|
+
`<article class="voice-session-card ${escapeHtml34(session.status)}">`,
|
|
19479
19744
|
'<div class="voice-session-card-header">',
|
|
19480
|
-
`<strong>${
|
|
19481
|
-
`<span>${
|
|
19745
|
+
`<strong>${escapeHtml34(session.sessionId)}</strong>`,
|
|
19746
|
+
`<span>${escapeHtml34(session.status)}</span>`,
|
|
19482
19747
|
"</div>",
|
|
19483
19748
|
"<dl>",
|
|
19484
19749
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -19486,9 +19751,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
19486
19751
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
19487
19752
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
19488
19753
|
"</dl>",
|
|
19489
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
19490
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
19491
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
19754
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml34(session.latestOutcome)}</p>` : "",
|
|
19755
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml34).join(", ")}</p>` : "",
|
|
19756
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml34(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml34(session.replayHref)}">Open replay</a></p>` : "",
|
|
19492
19757
|
"</article>"
|
|
19493
19758
|
].join("")),
|
|
19494
19759
|
"</div>"
|
|
@@ -19864,7 +20129,7 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
19864
20129
|
import { Elysia as Elysia34 } from "elysia";
|
|
19865
20130
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
19866
20131
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
19867
|
-
var
|
|
20132
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19868
20133
|
var firstNumber2 = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19869
20134
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
19870
20135
|
var createTraceStageIndex = (events) => {
|
|
@@ -19996,11 +20261,11 @@ await traceStore.append({
|
|
|
19996
20261
|
turnId,
|
|
19997
20262
|
type: 'turn_latency.stage'
|
|
19998
20263
|
});`;
|
|
19999
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
20000
|
-
<header><div><p class="eyebrow">${
|
|
20001
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
20264
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml35(turn.status)}">
|
|
20265
|
+
<header><div><p class="eyebrow">${escapeHtml35(turn.sessionId)} \xB7 ${escapeHtml35(turn.turnId)}</p><h2>${escapeHtml35(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml35(turn.status)}</strong></header>
|
|
20266
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml35(stage.label)}</dt><dd>${escapeHtml35(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
20002
20267
|
</article>`).join("");
|
|
20003
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20268
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn,.primitive{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml35(title)}</h1><div class="summary"><span class="pill ${escapeHtml35(report.status)}">${escapeHtml35(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml35(formatMs2(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml35(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
20004
20269
|
};
|
|
20005
20270
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
20006
20271
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -20027,7 +20292,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
20027
20292
|
};
|
|
20028
20293
|
// src/liveLatency.ts
|
|
20029
20294
|
import { Elysia as Elysia35 } from "elysia";
|
|
20030
|
-
var
|
|
20295
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20031
20296
|
var percentile3 = (values, percentileValue) => {
|
|
20032
20297
|
if (values.length === 0) {
|
|
20033
20298
|
return;
|
|
@@ -20094,8 +20359,8 @@ await traceStore.append({
|
|
|
20094
20359
|
sessionId,
|
|
20095
20360
|
type: 'client.live_latency'
|
|
20096
20361
|
});`;
|
|
20097
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
20098
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20362
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml36(sample.sessionId)}</td><td>${escapeHtml36(formatMs3(sample.latencyMs))}</td><td>${escapeHtml36(sample.status ?? "unknown")}</td><td>${escapeHtml36(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
20363
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml36(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml36(report.status)}">Status: ${escapeHtml36(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml36(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml36(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml36(formatMs3(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml36(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
20099
20364
|
};
|
|
20100
20365
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
20101
20366
|
const path = options.path ?? "/api/live-latency";
|
|
@@ -20421,7 +20686,7 @@ None.
|
|
|
20421
20686
|
// src/turnQuality.ts
|
|
20422
20687
|
import { Elysia as Elysia36 } from "elysia";
|
|
20423
20688
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
20424
|
-
var
|
|
20689
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20425
20690
|
var getTurnLatencyMs = (turn) => {
|
|
20426
20691
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
20427
20692
|
if (firstTranscriptAt === undefined) {
|
|
@@ -20492,24 +20757,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
20492
20757
|
};
|
|
20493
20758
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
20494
20759
|
const title = options.title ?? "Voice Turn Quality";
|
|
20495
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
20760
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml37(turn.status)}">
|
|
20496
20761
|
<div class="turn-header">
|
|
20497
20762
|
<div>
|
|
20498
|
-
<p class="eyebrow">${
|
|
20499
|
-
<h2>${
|
|
20763
|
+
<p class="eyebrow">${escapeHtml37(turn.sessionId)} \xB7 ${escapeHtml37(turn.turnId)}</p>
|
|
20764
|
+
<h2>${escapeHtml37(turn.text || "Empty turn")}</h2>
|
|
20500
20765
|
</div>
|
|
20501
|
-
<strong>${
|
|
20766
|
+
<strong>${escapeHtml37(turn.status)}</strong>
|
|
20502
20767
|
</div>
|
|
20503
20768
|
<dl>
|
|
20504
|
-
<div><dt>Source</dt><dd>${
|
|
20769
|
+
<div><dt>Source</dt><dd>${escapeHtml37(turn.source ?? "unknown")}</dd></div>
|
|
20505
20770
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
20506
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
20507
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
20771
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml37(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
20772
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml37(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
20508
20773
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
20509
20774
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
20510
20775
|
</dl>
|
|
20511
20776
|
</article>`).join("");
|
|
20512
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20777
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.unknown{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml37(title)}</h1><div class="summary"><span class="pill ${escapeHtml37(report.status)}">${escapeHtml37(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
20513
20778
|
};
|
|
20514
20779
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
20515
20780
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -21436,7 +21701,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
21436
21701
|
return parameters;
|
|
21437
21702
|
};
|
|
21438
21703
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21439
|
-
var
|
|
21704
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21440
21705
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
21441
21706
|
if (!webhook?.verificationUrl) {
|
|
21442
21707
|
return;
|
|
@@ -21479,23 +21744,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
21479
21744
|
};
|
|
21480
21745
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21481
21746
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
21482
|
-
<h1>${
|
|
21747
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
21483
21748
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21484
21749
|
<section>
|
|
21485
21750
|
<h2>URLs</h2>
|
|
21486
21751
|
<ul>
|
|
21487
|
-
<li><strong>TwiML:</strong> <code>${
|
|
21488
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21489
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21752
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml38(status.urls.twiml)}</code></li>
|
|
21753
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml38(status.urls.stream)}</code></li>
|
|
21754
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml38(status.urls.webhook)}</code></li>
|
|
21490
21755
|
</ul>
|
|
21491
21756
|
</section>
|
|
21492
21757
|
<section>
|
|
21493
21758
|
<h2>Signing</h2>
|
|
21494
21759
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
21495
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
21760
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml38(status.signing.verificationUrl)}</code></p>` : ""}
|
|
21496
21761
|
</section>
|
|
21497
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21498
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21762
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml38(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
21763
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml38(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
21499
21764
|
</main>`;
|
|
21500
21765
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
21501
21766
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -21506,20 +21771,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
21506
21771
|
});
|
|
21507
21772
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21508
21773
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
21509
|
-
<h1>${
|
|
21774
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
21510
21775
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21511
21776
|
<section>
|
|
21512
21777
|
<h2>Checks</h2>
|
|
21513
21778
|
<ul>
|
|
21514
|
-
${report.checks.map((check) => `<li><strong>${
|
|
21779
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml38(check.name)}</strong>: ${escapeHtml38(check.status)}${check.message ? ` - ${escapeHtml38(check.message)}` : ""}</li>`).join("")}
|
|
21515
21780
|
</ul>
|
|
21516
21781
|
</section>
|
|
21517
21782
|
<section>
|
|
21518
21783
|
<h2>Observed URLs</h2>
|
|
21519
21784
|
<ul>
|
|
21520
|
-
<li><strong>TwiML:</strong> <code>${
|
|
21521
|
-
<li><strong>Stream:</strong> <code>${
|
|
21522
|
-
<li><strong>Webhook:</strong> <code>${
|
|
21785
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml38(report.setup.urls.twiml)}</code></li>
|
|
21786
|
+
<li><strong>Stream:</strong> <code>${escapeHtml38(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
21787
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml38(report.setup.urls.webhook)}</code></li>
|
|
21523
21788
|
</ul>
|
|
21524
21789
|
</section>
|
|
21525
21790
|
</main>`;
|
|
@@ -22202,7 +22467,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
22202
22467
|
|
|
22203
22468
|
// src/telephony/plivo.ts
|
|
22204
22469
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22205
|
-
var
|
|
22470
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22206
22471
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22207
22472
|
var resolveRequestOrigin2 = (request) => {
|
|
22208
22473
|
const url = new URL(request.url);
|
|
@@ -22633,21 +22898,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
22633
22898
|
};
|
|
22634
22899
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22635
22900
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
22636
|
-
<h1>${
|
|
22901
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22637
22902
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
22638
22903
|
<ul>
|
|
22639
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
22640
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
22641
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
22904
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml39(status.urls.answer)}</code></li>
|
|
22905
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml39(status.urls.stream)}</code></li>
|
|
22906
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml39(status.urls.webhook)}</code></li>
|
|
22642
22907
|
</ul>
|
|
22643
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
22644
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
22908
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml39(name)}</code></li>`).join("")}</ul>` : ""}
|
|
22909
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml39(warning)}</li>`).join("")}</ul>` : ""}
|
|
22645
22910
|
</main>`;
|
|
22646
22911
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22647
22912
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
22648
|
-
<h1>${
|
|
22913
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22649
22914
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
22650
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
22915
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml39(check.name)}</strong>: ${escapeHtml39(check.status)}${check.message ? ` - ${escapeHtml39(check.message)}` : ""}</li>`).join("")}</ul>
|
|
22651
22916
|
</main>`;
|
|
22652
22917
|
var runPlivoSmokeTest = async (input) => {
|
|
22653
22918
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -22851,7 +23116,7 @@ import { Buffer as Buffer6 } from "buffer";
|
|
|
22851
23116
|
import { Database as Database2 } from "bun:sqlite";
|
|
22852
23117
|
import { Elysia as Elysia40 } from "elysia";
|
|
22853
23118
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22854
|
-
var
|
|
23119
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22855
23120
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22856
23121
|
var resolveRequestOrigin3 = (request) => {
|
|
22857
23122
|
const url = new URL(request.url);
|
|
@@ -23245,21 +23510,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
23245
23510
|
};
|
|
23246
23511
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
23247
23512
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
23248
|
-
<h1>${
|
|
23513
|
+
<h1>${escapeHtml40(title)}</h1>
|
|
23249
23514
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
23250
23515
|
<ul>
|
|
23251
|
-
<li><strong>TeXML:</strong> <code>${
|
|
23252
|
-
<li><strong>Media stream:</strong> <code>${
|
|
23253
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
23516
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml40(status.urls.texml)}</code></li>
|
|
23517
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml40(status.urls.stream)}</code></li>
|
|
23518
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml40(status.urls.webhook)}</code></li>
|
|
23254
23519
|
</ul>
|
|
23255
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
23256
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
23520
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml40(name)}</code></li>`).join("")}</ul>` : ""}
|
|
23521
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml40(warning)}</li>`).join("")}</ul>` : ""}
|
|
23257
23522
|
</main>`;
|
|
23258
23523
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
23259
23524
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
23260
|
-
<h1>${
|
|
23525
|
+
<h1>${escapeHtml40(title)}</h1>
|
|
23261
23526
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
23262
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
23527
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml40(check.name)}</strong>: ${escapeHtml40(check.status)}${check.message ? ` - ${escapeHtml40(check.message)}` : ""}</li>`).join("")}</ul>
|
|
23263
23528
|
</main>`;
|
|
23264
23529
|
var runTelnyxSmokeTest = async (input) => {
|
|
23265
23530
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -23463,7 +23728,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
23463
23728
|
|
|
23464
23729
|
// src/telephony/matrix.ts
|
|
23465
23730
|
import { Elysia as Elysia41 } from "elysia";
|
|
23466
|
-
var
|
|
23731
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23467
23732
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
23468
23733
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
23469
23734
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -23524,13 +23789,13 @@ var badgeStyles = {
|
|
|
23524
23789
|
};
|
|
23525
23790
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
23526
23791
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
23527
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
23792
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml41(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
23528
23793
|
<p style="color:#52606d; margin: 0 0 24px;">${matrix.summary.ready}/${matrix.summary.providers} ready, ${matrix.summary.contractsPassing}/${matrix.summary.providers} contract passing, ${matrix.summary.smokePassing}/${matrix.summary.providers} smoke passing.</p>
|
|
23529
23794
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
23530
23795
|
${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; border-radius:18px; padding:18px; background:#fff; box-shadow:0 18px 48px rgba(15,23,42,.08);">
|
|
23531
23796
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
23532
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
23533
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
23797
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml41(entry.name)}</h2>
|
|
23798
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml41(entry.status.toUpperCase())}</span>
|
|
23534
23799
|
</div>
|
|
23535
23800
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
23536
23801
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -23538,9 +23803,9 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
23538
23803
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
23539
23804
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
23540
23805
|
</dl>
|
|
23541
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
23542
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
23543
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
23806
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml41(entry.setup.urls.stream || "missing")}</code></p>
|
|
23807
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml41(entry.setup.urls.webhook || "missing")}</code></p>
|
|
23808
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml41(issue.severity)}: ${escapeHtml41(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
23544
23809
|
</article>`).join("")}
|
|
23545
23810
|
</section>
|
|
23546
23811
|
</main>`;
|
|
@@ -23576,7 +23841,7 @@ var defaultRequirements = [
|
|
|
23576
23841
|
"lifecycle-outcome",
|
|
23577
23842
|
"no-session-error"
|
|
23578
23843
|
];
|
|
23579
|
-
var
|
|
23844
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23580
23845
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
23581
23846
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
23582
23847
|
const value = event.payload[key];
|
|
@@ -23685,10 +23950,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
23685
23950
|
});
|
|
23686
23951
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
23687
23952
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
23688
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
23689
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
23690
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
23691
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
23953
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml42(issue.requirement)}</strong>: ${escapeHtml42(issue.message)}</li>`).join("");
|
|
23954
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml42(outcome)}</span>`).join("");
|
|
23955
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml42(requirement)}</span>`).join("");
|
|
23956
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#0e141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1050px;padding:32px}.hero,.panel{background:#151d26;border:1px solid #283544;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:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.metric{background:#0f151d;border:1px solid #283544;border-radius:16px;padding:14px}.metric strong{display:block;font-size:1.8rem}.pill{background:#0f151d;border:1px solid #3f3f46;border-radius:999px;display:inline-flex;margin:4px;padding:7px 10px}.issues{color:#fca5a5}code{color:#fde68a}@media(max-width:720px){main{padding:18px}}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent production smoke</p><h1>${escapeHtml42(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml42(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml42(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml42(report.sessionId)}</code>` : ""}.</p></section><section class="panel"><h2>Observed Trace Evidence</h2><div class="grid"><div class="metric"><span>Media starts</span><strong>${String(report.observed.mediaStarts)}</strong></div><div class="metric"><span>Transcripts</span><strong>${String(report.observed.transcripts)}</strong></div><div class="metric"><span>Assistant responses</span><strong>${String(report.observed.assistantResponses)}</strong></div><div class="metric"><span>Session errors</span><strong>${String(report.observed.sessionErrors)}</strong></div></div><p>${outcomes || '<span class="pill">No lifecycle outcome</span>'}</p></section><section class="panel"><h2>Requirements</h2><p>${requirements}</p>${issues ? `<ul class="issues">${issues}</ul>` : '<p class="pass">All required phone-agent smoke evidence is present.</p>'}</section></main></body></html>`;
|
|
23692
23957
|
};
|
|
23693
23958
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
23694
23959
|
query,
|
|
@@ -23754,7 +24019,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
23754
24019
|
"completed",
|
|
23755
24020
|
"failed"
|
|
23756
24021
|
];
|
|
23757
|
-
var
|
|
24022
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23758
24023
|
var loadRouteJson = async (input) => {
|
|
23759
24024
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
23760
24025
|
headers: {
|
|
@@ -23992,10 +24257,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
23992
24257
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
23993
24258
|
const urls = entry?.setup.urls;
|
|
23994
24259
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
23995
|
-
return `<tr><td>${
|
|
24260
|
+
return `<tr><td>${escapeHtml43(carrier.name ?? carrier.provider)}</td><td>${escapeHtml43(carrier.provider)}</td><td><code>${escapeHtml43(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml43(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml43(entry.status)}">${escapeHtml43(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml43(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml43(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml43(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
23996
24261
|
}).join("");
|
|
23997
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
23998
|
-
const snippet =
|
|
24262
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml43(stage)}</code></li>`).join("");
|
|
24263
|
+
const snippet = escapeHtml43(`const phoneAgent = createVoicePhoneAgent({
|
|
23999
24264
|
carriers: [
|
|
24000
24265
|
{
|
|
24001
24266
|
provider: 'twilio',
|
|
@@ -24029,11 +24294,11 @@ app.use(
|
|
|
24029
24294
|
);`);
|
|
24030
24295
|
const checklist = report.carriers.map((carrier) => {
|
|
24031
24296
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
24032
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
24033
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
24034
|
-
return `<article><h3>${
|
|
24297
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml43(issue)}</li>`).join("") ?? "";
|
|
24298
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml43(step)}</li>`).join("") ?? "";
|
|
24299
|
+
return `<article><h3>${escapeHtml43(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
24035
24300
|
}).join("");
|
|
24036
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24301
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#365a60}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.primitive p{color:#cbd5de;line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #283544;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml43(report.title)}</h1><p>One self-hosted entrypoint for carrier routes, setup reports, smoke checks, and normalized call lifecycle stages.</p><p class="badge ${report.ready ? "pass" : "fail"}">Ready: ${String(report.ready)}</p>${report.matrixPath ? `<p><a href="${escapeHtml43(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoicePhoneAgent(...)</code> builds this carrier control plane</h2><p>Mount carrier routes once, expose setup and smoke proof, then feed the same carrier matrix and phone-agent smoke reports into production readiness so carrier regressions block deploys.</p><pre><code>${snippet}</code></pre></section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
|
|
24037
24302
|
};
|
|
24038
24303
|
var createVoicePhoneAgent = (options) => {
|
|
24039
24304
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -25673,7 +25938,7 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
25673
25938
|
};
|
|
25674
25939
|
// src/providerCapabilities.ts
|
|
25675
25940
|
import { Elysia as Elysia44 } from "elysia";
|
|
25676
|
-
var
|
|
25941
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25677
25942
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
25678
25943
|
configured: true,
|
|
25679
25944
|
features: options.features?.[provider],
|
|
@@ -25736,27 +26001,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
25736
26001
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
25737
26002
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
25738
26003
|
const cards = report.capabilities.map((capability) => {
|
|
25739
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
25740
|
-
return `<article class="card ${
|
|
26004
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml44(feature)}</span>`).join("");
|
|
26005
|
+
return `<article class="card ${escapeHtml44(capability.status)}">
|
|
25741
26006
|
<div class="card-header">
|
|
25742
26007
|
<div>
|
|
25743
|
-
<p class="eyebrow">${
|
|
25744
|
-
<h2>${
|
|
26008
|
+
<p class="eyebrow">${escapeHtml44(capability.kind)}</p>
|
|
26009
|
+
<h2>${escapeHtml44(capability.label ?? capability.provider)}</h2>
|
|
25745
26010
|
</div>
|
|
25746
|
-
<strong>${
|
|
26011
|
+
<strong>${escapeHtml44(capability.status)}</strong>
|
|
25747
26012
|
</div>
|
|
25748
|
-
${capability.description ? `<p>${
|
|
26013
|
+
${capability.description ? `<p>${escapeHtml44(capability.description)}</p>` : ""}
|
|
25749
26014
|
<dl>
|
|
25750
26015
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
25751
26016
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
25752
|
-
<div><dt>Model</dt><dd>${
|
|
26017
|
+
<div><dt>Model</dt><dd>${escapeHtml44(capability.model ?? "default")}</dd></div>
|
|
25753
26018
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
25754
26019
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
25755
26020
|
</dl>
|
|
25756
26021
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
25757
26022
|
</article>`;
|
|
25758
26023
|
}).join("");
|
|
25759
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26024
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.16),rgba(34,197,94,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary,.features{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.selected,.healthy{color:#86efac}.unconfigured,.degraded,.rate-limited,.suppressed{color:#fca5a5}.idle,.recoverable{color:#fde68a}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Discovery</p><h1>${escapeHtml44(title)}</h1><div class="summary"><span class="pill">${String(report.configured)} configured</span><span class="pill">${String(report.selected)} selected</span><span class="pill">${String(report.unconfigured)} missing</span><span class="pill">${String(report.total)} total</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider capabilities configured.</p></article>'}</section></main></body></html>`;
|
|
25760
26025
|
};
|
|
25761
26026
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
25762
26027
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -25795,7 +26060,7 @@ var statusRank4 = {
|
|
|
25795
26060
|
warn: 1,
|
|
25796
26061
|
fail: 2
|
|
25797
26062
|
};
|
|
25798
|
-
var
|
|
26063
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25799
26064
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
25800
26065
|
var uniqueSorted6 = (values) => [
|
|
25801
26066
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -25938,21 +26203,21 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
25938
26203
|
};
|
|
25939
26204
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
25940
26205
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
25941
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
25942
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
26206
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml45(surface.status)}">
|
|
26207
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml45(surface.surface)}</p><h2>${escapeHtml45(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml45(surface.status)}</strong></div>
|
|
25943
26208
|
<dl>
|
|
25944
|
-
<div><dt>Providers</dt><dd>${
|
|
25945
|
-
<div><dt>Fallback</dt><dd>${
|
|
26209
|
+
<div><dt>Providers</dt><dd>${escapeHtml45(surface.providers.join(", ") || "none")}</dd></div>
|
|
26210
|
+
<div><dt>Fallback</dt><dd>${escapeHtml45(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
25946
26211
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
25947
26212
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
25948
26213
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
25949
26214
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
25950
26215
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
25951
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
26216
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml45(surface.fallbackMode || "default")}</dd></div>
|
|
25952
26217
|
</dl>
|
|
25953
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
26218
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml45(issue.status)}</strong> ${escapeHtml45(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
25954
26219
|
</article>`).join("");
|
|
25955
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26220
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml45(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#172033;border:1px solid #2d3b55;border-radius:22px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(59,130,246,.18),rgba(20,184,166,.12))}.eyebrow{color:#93c5fd;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f172a;border:1px solid #334155;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass strong{color:#86efac}.warn strong{color:#fde68a}.fail strong{color:#fca5a5}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0;overflow-wrap:anywhere}li{margin:.35rem 0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Policy Proof</p><h1>${escapeHtml45(title)}</h1><div class="summary"><span class="pill">${escapeHtml45(report.profileId)}</span><span class="pill">${escapeHtml45(report.status)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.providers)} providers</span><span class="pill">${String(report.issues.length)} issues</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider orchestration surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
25956
26221
|
};
|
|
25957
26222
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
25958
26223
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
@@ -26162,7 +26427,7 @@ var statusRank5 = {
|
|
|
26162
26427
|
warn: 1,
|
|
26163
26428
|
fail: 2
|
|
26164
26429
|
};
|
|
26165
|
-
var
|
|
26430
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26166
26431
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
26167
26432
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
26168
26433
|
var uniqueSorted7 = (values) => [
|
|
@@ -26458,11 +26723,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
26458
26723
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
26459
26724
|
const kindCards = providerKinds.map((kind) => {
|
|
26460
26725
|
const kindReport = report.kinds[kind];
|
|
26461
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
26726
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml46(metric.label)}</dt><dd>${escapeHtml46(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml46(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
26462
26727
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
26463
|
-
return `<article class="${
|
|
26728
|
+
return `<article class="${escapeHtml46(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml46(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml46(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
26464
26729
|
}).join("");
|
|
26465
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
26730
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml46(issue.status)}"><strong>${escapeHtml46(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml46(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
26466
26731
|
const snippet = `createVoiceProviderSloRoutes({
|
|
26467
26732
|
store: runtimeStorage.traces,
|
|
26468
26733
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -26472,7 +26737,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
26472
26737
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
26473
26738
|
}
|
|
26474
26739
|
})`;
|
|
26475
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26740
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{background:#101318;color:#f8f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,article,.primitive{background:#171b22;border:1px solid #2c3340;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.2),rgba(245,158,11,.12))}.eyebrow{color:#7dd3fc;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.9rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status,article h2 span{border:1px solid #475569;border-radius:999px;display:inline-flex;font-size:.85rem;padding:6px 10px}.pass{border-color:rgba(34,197,94,.65)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}dt{color:#cbd5e1;font-size:.78rem;text-transform:uppercase}dd{font-size:1.7rem;font-weight:900;margin:0}small{color:#a8b3c2}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#101318;border:1px solid #2c3340;border-radius:16px;padding:12px}li span{color:#cbd5e1;display:block;margin-top:4px}.primitive{background:#11161d}.primitive code{color:#bae6fd}.primitive pre{background:#070b10;border:1px solid #243041;border-radius:16px;color:#e0f2fe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Provider latency and fallback proof</p><h1>${escapeHtml46(title)}</h1><p class="status ${escapeHtml46(report.status)}">${escapeHtml46(report.status)}</p><p>${report.events} provider routing event(s), ${report.eventsWithLatency} latency sample(s).</p></section><section class="grid">${kindCards}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderSloRoutes(...)</code> turns provider speed into release evidence</h2><p>Pair this report with production readiness so LLM/STT/TTS latency, timeout, fallback, and unresolved error regressions block deploys.</p><pre><code>${escapeHtml46(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
26476
26741
|
};
|
|
26477
26742
|
var createVoiceProviderSloRoutes = (options) => {
|
|
26478
26743
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -27312,7 +27577,7 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
27312
27577
|
|
|
27313
27578
|
// src/opsRecovery.ts
|
|
27314
27579
|
import { Elysia as Elysia48 } from "elysia";
|
|
27315
|
-
var
|
|
27580
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27316
27581
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
27317
27582
|
var hrefForSession = (value, sessionId) => {
|
|
27318
27583
|
if (typeof value === "function") {
|
|
@@ -27526,13 +27791,13 @@ ${failedSessions || "None."}
|
|
|
27526
27791
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
27527
27792
|
`;
|
|
27528
27793
|
};
|
|
27529
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
27794
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml47(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml47(label)}</span><strong>not configured</strong></article>`;
|
|
27530
27795
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
27531
27796
|
const title = options.title ?? "Voice Ops Recovery";
|
|
27532
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
27533
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
27534
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
27535
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27797
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml47(issue.severity)}</td><td><code>${escapeHtml47(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml47(issue.href)}">${escapeHtml47(issue.label)}</a>` : escapeHtml47(issue.label)}</td><td>${escapeHtml47(String(issue.value ?? ""))}</td><td>${escapeHtml47(issue.detail ?? "")}</td></tr>`).join("");
|
|
27798
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml47(provider.provider)}</td><td>${escapeHtml47(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml47(provider.lastError ?? "")}</td></tr>`).join("");
|
|
27799
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml47(session.operationsRecordHref)}">${escapeHtml47(session.sessionId)}</a>` : escapeHtml47(session.sessionId)}${session.provider ? ` via ${escapeHtml47(session.provider)}` : ""}${session.error ? `: ${escapeHtml47(session.error)}` : ""}</li>`).join("");
|
|
27800
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml47(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml47(title)}</h1><p><span class="status">${escapeHtml47(report.status)}</span> Checked ${escapeHtml47(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml47(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
27536
27801
|
};
|
|
27537
27802
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
27538
27803
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
@@ -27579,7 +27844,7 @@ import { Elysia as Elysia50 } from "elysia";
|
|
|
27579
27844
|
|
|
27580
27845
|
// src/traceTimeline.ts
|
|
27581
27846
|
import { Elysia as Elysia49 } from "elysia";
|
|
27582
|
-
var
|
|
27847
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27583
27848
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
27584
27849
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
27585
27850
|
var firstString4 = (payload, keys) => {
|
|
@@ -27762,17 +28027,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
27762
28027
|
};
|
|
27763
28028
|
};
|
|
27764
28029
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27765
|
-
var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${
|
|
28030
|
+
var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml48(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs4(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs4(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
|
|
27766
28031
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
27767
|
-
const events = session.events.map((event) => `<tr class="${
|
|
27768
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
27769
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
27770
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
28032
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml48(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml48(event.type)}</td><td>${escapeHtml48(event.label)}</td><td>${escapeHtml48(event.provider ?? "")}</td><td>${escapeHtml48(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
28033
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml48(issue.severity)}">${escapeHtml48(issue.code)}: ${escapeHtml48(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
28034
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml48(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
28035
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml48(session.sessionId)}</h1><p class="status ${escapeHtml48(session.status)}">${escapeHtml48(session.status)}</p>${supportLinks}</header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs4(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
|
|
27771
28036
|
};
|
|
27772
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
28037
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml48(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml48(session.operationsRecordHref)}">${escapeHtml48(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml48(session.sessionId)}</a>`}</td><td>${escapeHtml48(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs4(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml48(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
27773
28038
|
var timelineCSS = "body{background:#0f1318;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}a{color:#fbbf24}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.metrics,.providers{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.providers article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span,dt,.muted{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:12px 0 0}dd{font-weight:800;margin:4px 0 0}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}section{margin-top:28px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}";
|
|
27774
28039
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
27775
|
-
const snippet =
|
|
28040
|
+
const snippet = escapeHtml48(`const traceStore = createVoiceTraceSinkStore({
|
|
27776
28041
|
store: runtimeStorage.traces,
|
|
27777
28042
|
sinks: [
|
|
27778
28043
|
createVoiceTraceHTTPSink({
|
|
@@ -27798,7 +28063,7 @@ app.use(
|
|
|
27798
28063
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
27799
28064
|
})
|
|
27800
28065
|
);`);
|
|
27801
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
28066
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml48(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
|
|
27802
28067
|
};
|
|
27803
28068
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
27804
28069
|
const path = options.path ?? "/api/voice-traces";
|
|
@@ -28434,7 +28699,7 @@ var renderVoiceFailureReplayMarkdown = (report) => {
|
|
|
28434
28699
|
].join(`
|
|
28435
28700
|
`);
|
|
28436
28701
|
};
|
|
28437
|
-
var
|
|
28702
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28438
28703
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
28439
28704
|
var outcomeLabels = (outcome) => [
|
|
28440
28705
|
outcome.complete ? "complete" : undefined,
|
|
@@ -28544,18 +28809,18 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
28544
28809
|
`);
|
|
28545
28810
|
};
|
|
28546
28811
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
28547
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
28548
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
28549
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
28812
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml49(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs5(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
28813
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml49(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml49(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml49(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml49(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
28814
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml49(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml49(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml49(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml49(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml49(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml49(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml49(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml49(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
28550
28815
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
28551
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
28552
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
28553
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
28554
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
28555
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
28816
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml49(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml49(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml49(handoff.status ?? "")}</span><p>${escapeHtml49(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
28817
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml49(tool.toolName ?? "tool")}</strong> <span>${escapeHtml49(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml49(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
28818
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml49(review.title)}</strong> <span>${escapeHtml49(review.summary.outcome ?? "")}</span><p>${escapeHtml49(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
28819
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml49(task.title)}</strong> <span>${escapeHtml49(task.status)}</span><p>${escapeHtml49(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
28820
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml49(event.type)}</strong> <span>${escapeHtml49(event.deliveryStatus ?? "local")}</span><p>${escapeHtml49(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
28556
28821
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
28557
28822
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
28558
|
-
return `<li><strong>assistant.guardrail ${
|
|
28823
|
+
return `<li><strong>assistant.guardrail ${escapeHtml49(decision.stage ?? "unknown")}</strong> <span>${escapeHtml49(decision.status ?? "")}</span><p>Allowed: ${escapeHtml49(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml49(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml49(decision.turnId)}` : ""}</p><p>${escapeHtml49(findings)}</p></li>`;
|
|
28559
28824
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
28560
28825
|
const telephonyMedia = record.telephonyMedia.events.length ? record.telephonyMedia.events.slice(0, 50).map((event) => {
|
|
28561
28826
|
const details = [
|
|
@@ -28566,9 +28831,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
28566
28831
|
event.sequenceNumber ? `Seq: ${event.sequenceNumber}` : undefined,
|
|
28567
28832
|
`Audio bytes: ${String(event.audioBytes)}`
|
|
28568
28833
|
].filter((detail) => typeof detail === "string");
|
|
28569
|
-
return `<li><strong>${
|
|
28834
|
+
return `<li><strong>${escapeHtml49(event.event)}</strong> <span>${escapeHtml49(new Date(event.at).toLocaleString())}</span><p>${escapeHtml49(details.join(" \xB7 "))}</p></li>`;
|
|
28570
28835
|
}).join("") : "<li>No telephony media trace events recorded.</li>";
|
|
28571
|
-
const snippet =
|
|
28836
|
+
const snippet = escapeHtml49(`app.use(
|
|
28572
28837
|
createVoiceOperationsRecordRoutes({
|
|
28573
28838
|
audit: auditStore,
|
|
28574
28839
|
integrationEvents: opsEvents,
|
|
@@ -28582,9 +28847,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
28582
28847
|
tasks: opsTasks
|
|
28583
28848
|
})
|
|
28584
28849
|
);`);
|
|
28585
|
-
const incidentMarkdown =
|
|
28586
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
28587
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
28850
|
+
const incidentMarkdown = escapeHtml49(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
28851
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml49(options.incidentHref)}">Download incident.md</a>` : "";
|
|
28852
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml49(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml49(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml49(record.status)}">${escapeHtml49(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#telephony-media">Telephony media</a><a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs5(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml49(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Telephony media</span><strong>${String(record.telephonyMedia.media)}</strong><span>${String(record.telephonyMedia.inbound)} inbound / ${String(record.telephonyMedia.outbound)} outbound / ${String(record.telephonyMedia.clears)} clears</span></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="telephony-media"><h2>Telephony Media</h2><p class="muted">Live <code>client.telephony_media</code> stream lifecycle evidence attached to this session. Carriers: ${escapeHtml49(record.telephonyMedia.carriers.join(", ") || "none")}. Streams: ${escapeHtml49(record.telephonyMedia.streamIds.join(", ") || "none")}. Inbound: ${String(record.telephonyMedia.inbound)}. Outbound: ${String(record.telephonyMedia.outbound)}. Marks: ${String(record.telephonyMedia.marks)}. Clears: ${String(record.telephonyMedia.clears)}.</p><ul>${telephonyMedia}</ul></section><section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, media streams, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
|
|
28588
28853
|
};
|
|
28589
28854
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
28590
28855
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -30128,7 +30393,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
30128
30393
|
};
|
|
30129
30394
|
|
|
30130
30395
|
// src/productionReadiness.ts
|
|
30131
|
-
var
|
|
30396
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30132
30397
|
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
30133
30398
|
var readinessGateCodes = {
|
|
30134
30399
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -31766,25 +32031,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
31766
32031
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
31767
32032
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
31768
32033
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
31769
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
31770
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
32034
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml50(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
32035
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml50(report.profile.name)}</h2><p>${escapeHtml50(report.profile.description)}</p><p>${escapeHtml50(report.profile.purpose)}</p><div class="profile-surfaces">${report.profile.surfaces.map((surface) => `<article class="${surface.configured ? "pass" : "warn"}"><span>${surface.configured ? "CONFIGURED" : "EXPECTED"}</span><strong>${surface.href ? `<a href="${escapeHtml50(surface.href)}">${escapeHtml50(surface.label)}</a>` : escapeHtml50(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
31771
32036
|
const checks = report.checks.map((check, index) => {
|
|
31772
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
31773
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
31774
|
-
return `<article class="check ${
|
|
32037
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml50(action.href)}">${escapeHtml50(action.label)}</button>` : `<a href="${escapeHtml50(action.href)}">${escapeHtml50(action.label)}</a>`).join("");
|
|
32038
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml50(check.status)}: observed ${escapeHtml50(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml50(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml50(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml50(check.gateExplanation.unit)}` : ""}. ${escapeHtml50(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml50(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
32039
|
+
return `<article class="check ${escapeHtml50(check.status)}">
|
|
31775
32040
|
<div>
|
|
31776
|
-
<span>${
|
|
31777
|
-
<h2>${
|
|
31778
|
-
${check.detail ? `<p>${
|
|
32041
|
+
<span>${escapeHtml50(check.status.toUpperCase())}</span>
|
|
32042
|
+
<h2>${escapeHtml50(check.label)}</h2>
|
|
32043
|
+
${check.detail ? `<p>${escapeHtml50(check.detail)}</p>` : ""}
|
|
31779
32044
|
${explanation}
|
|
31780
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
32045
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml50(check.proofSource.href)}">${escapeHtml50(check.proofSource.sourceLabel)}</a>` : escapeHtml50(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml50(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
31781
32046
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
31782
32047
|
</div>
|
|
31783
|
-
<strong>${
|
|
31784
|
-
${check.href ? `<a href="${
|
|
32048
|
+
<strong>${escapeHtml50(String(check.value ?? check.status))}</strong>
|
|
32049
|
+
${check.href ? `<a href="${escapeHtml50(check.href)}">Open surface</a>` : ""}
|
|
31785
32050
|
</article>`;
|
|
31786
32051
|
}).join("");
|
|
31787
|
-
const snippet =
|
|
32052
|
+
const snippet = escapeHtml50(`createVoiceProductionReadinessRoutes({
|
|
31788
32053
|
htmlPath: '/production-readiness',
|
|
31789
32054
|
path: '/api/production-readiness',
|
|
31790
32055
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -31800,7 +32065,7 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
31800
32065
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
31801
32066
|
store: traceStore
|
|
31802
32067
|
});`);
|
|
31803
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32068
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml50(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero,.primitive,.profile{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.primitive,.profile{background:#111722}.primitive{border-color:#3a3f2d}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.primitive code{color:#fde68a}.primitive p{color:#c8ccd3;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#0b0f16;border:1px solid #2c3440;border-radius:18px;color:#fef3c7;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.check.pass,.profile-surfaces .pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn,.profile-surfaces .warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span,.profile-surfaces span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p,.profile p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check .gate-explanation{background:#0b0f16;border:1px solid #2c3440;border-radius:14px;color:#fef3c7;margin-top:10px;padding:10px}.check strong{font-size:1.5rem}.profile-surfaces{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}.profile-surfaces article{background:#141922;border:1px solid #26313d;border-radius:16px;padding:14px}.profile-surfaces strong{display:block;margin-top:6px}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml50(title)}</h1><p>One deployable pass/fail report for quality gates, provider failover, session health, handoffs, routing evidence, and optional carrier readiness.</p><p class="status ${escapeHtml50(report.status)}">Overall: ${escapeHtml50(report.status.toUpperCase())}</p><p>Checked ${escapeHtml50(new Date(report.checkedAt).toLocaleString())}</p>${thresholdLink}</section>${profile}<section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProductionReadinessRoutes(...)</code> builds this deploy gate</h2><p>Mount one package primitive to expose JSON readiness, HTML readiness, and a machine-readable gate route. Feed it the proof stores and contract reports your app already owns.</p><pre><code>${snippet}</code></pre></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
|
|
31804
32069
|
};
|
|
31805
32070
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
31806
32071
|
const path = options.path ?? "/api/production-readiness";
|
|
@@ -31855,7 +32120,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
31855
32120
|
};
|
|
31856
32121
|
// src/voiceMonitoring.ts
|
|
31857
32122
|
import { Elysia as Elysia53 } from "elysia";
|
|
31858
|
-
var
|
|
32123
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31859
32124
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
31860
32125
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
31861
32126
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -32108,14 +32373,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
32108
32373
|
};
|
|
32109
32374
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
32110
32375
|
const title = options.title ?? "Voice Monitors";
|
|
32111
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
32112
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
32113
|
-
const snippet =
|
|
32376
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml51(run.label)}</td><td class="${escapeHtml51(run.status)}">${escapeHtml51(run.status)}</td><td>${escapeHtml51(run.severity)}</td><td>${escapeHtml51(String(run.value ?? ""))}</td><td>${escapeHtml51(String(run.threshold ?? ""))}</td><td>${escapeHtml51(run.detail ?? "")}</td></tr>`).join("");
|
|
32377
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml51(issue.label)}</strong> <span class="${escapeHtml51(issue.status)}">${escapeHtml51(issue.status)}</span> ${escapeHtml51(issue.detail ?? "")}</li>`).join("");
|
|
32378
|
+
const snippet = escapeHtml51(`app.use(createVoiceMonitorRoutes({
|
|
32114
32379
|
evidence,
|
|
32115
32380
|
issueStore,
|
|
32116
32381
|
monitors: [defineVoiceMonitor(...)]
|
|
32117
32382
|
}));`);
|
|
32118
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32383
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml51(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml51(title)}</h1><p class="pill ${escapeHtml51(report.status)}">Status: ${escapeHtml51(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
32119
32384
|
};
|
|
32120
32385
|
var actorFromRequest = async (request) => {
|
|
32121
32386
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -32563,7 +32828,7 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
32563
32828
|
};
|
|
32564
32829
|
// src/providerStackRecommendations.ts
|
|
32565
32830
|
import { Elysia as Elysia54 } from "elysia";
|
|
32566
|
-
var
|
|
32831
|
+
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32567
32832
|
var profileProviderPriorities = {
|
|
32568
32833
|
"meeting-recorder": {
|
|
32569
32834
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -32882,17 +33147,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
32882
33147
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
32883
33148
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
32884
33149
|
const rows = report.rows.map((row) => {
|
|
32885
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
32886
|
-
return `<article class="row ${
|
|
33150
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml52(check.status)}"><strong>${escapeHtml52(check.label)}</strong><span>${escapeHtml52(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml52(check.remediation.href)}">${escapeHtml52(check.remediation.label)}</a>` : escapeHtml52(check.remediation.label)}: ${escapeHtml52(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
33151
|
+
return `<article class="row ${escapeHtml52(row.status)}">
|
|
32887
33152
|
<div>
|
|
32888
|
-
<p class="eyebrow">${
|
|
32889
|
-
<h2>${
|
|
32890
|
-
<p class="status ${
|
|
33153
|
+
<p class="eyebrow">${escapeHtml52(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
33154
|
+
<h2>${escapeHtml52(row.provider)}</h2>
|
|
33155
|
+
<p class="status ${escapeHtml52(row.status)}">${escapeHtml52(row.status.toUpperCase())}</p>
|
|
32891
33156
|
</div>
|
|
32892
33157
|
<ul>${checks}</ul>
|
|
32893
33158
|
</article>`;
|
|
32894
33159
|
}).join("");
|
|
32895
|
-
const snippet =
|
|
33160
|
+
const snippet = escapeHtml52(`const providerContracts = () =>
|
|
32896
33161
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
32897
33162
|
env: process.env,
|
|
32898
33163
|
providers: {
|
|
@@ -32913,7 +33178,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
32913
33178
|
providerContractMatrix: () =>
|
|
32914
33179
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
32915
33180
|
});`);
|
|
32916
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33181
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml52(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml52(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
32917
33182
|
};
|
|
32918
33183
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
32919
33184
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -33081,7 +33346,7 @@ var DEFAULT_LINKS = [
|
|
|
33081
33346
|
label: "Handoffs"
|
|
33082
33347
|
}
|
|
33083
33348
|
];
|
|
33084
|
-
var
|
|
33349
|
+
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33085
33350
|
var countProviderStatuses = (providers) => {
|
|
33086
33351
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
33087
33352
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -33150,16 +33415,16 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
33150
33415
|
trace
|
|
33151
33416
|
};
|
|
33152
33417
|
};
|
|
33153
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
33418
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml53(input.label)}</span><strong>${escapeHtml53(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml53(input.status)}">${escapeHtml53(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml53(input.href)}">Open</a>` : ""}</article>`;
|
|
33154
33419
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
33155
33420
|
const links = report.links.map((link) => `<article class="surface">
|
|
33156
|
-
<div><h2>${
|
|
33157
|
-
<p><a href="${
|
|
33421
|
+
<div><h2>${escapeHtml53(link.label)}</h2>${link.description ? `<p>${escapeHtml53(link.description)}</p>` : ""}</div>
|
|
33422
|
+
<p><a href="${escapeHtml53(link.href)}">Open ${escapeHtml53(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml53(link.statusHref)}">Status</a>` : ""}</p>
|
|
33158
33423
|
</article>`).join("");
|
|
33159
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
33160
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
33424
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml53(session.sessionId)}</td><td>${escapeHtml53(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml53(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
33425
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml53(event.kind)}</td><td>${escapeHtml53(event.provider ?? "unknown")}</td><td>${escapeHtml53(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml53(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
33161
33426
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
33162
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33427
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml53(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml53(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml53(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
|
|
33163
33428
|
};
|
|
33164
33429
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
33165
33430
|
const path = options.path ?? "/ops-console";
|
|
@@ -33583,14 +33848,14 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
33583
33848
|
};
|
|
33584
33849
|
// src/opsStatusRoutes.ts
|
|
33585
33850
|
import { Elysia as Elysia57 } from "elysia";
|
|
33586
|
-
var
|
|
33851
|
+
var escapeHtml54 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33587
33852
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
33588
33853
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
33589
33854
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
33590
33855
|
const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
|
|
33591
|
-
return `<article class="surface ${
|
|
33856
|
+
return `<article class="surface ${escapeHtml54(surface.status)}"><span>${escapeHtml54(surface.status.toUpperCase())}</span><h2>${escapeHtml54(key)}</h2><strong>${escapeHtml54(value)}</strong></article>`;
|
|
33592
33857
|
}).join("");
|
|
33593
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33858
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml54(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml54(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml54(report.status)}">Overall: ${escapeHtml54(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
|
|
33594
33859
|
};
|
|
33595
33860
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
33596
33861
|
const path = options.path ?? "/api/voice/ops-status";
|
|
@@ -34028,7 +34293,7 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
34028
34293
|
};
|
|
34029
34294
|
// src/traceDeliveryRoutes.ts
|
|
34030
34295
|
import { Elysia as Elysia58 } from "elysia";
|
|
34031
|
-
var
|
|
34296
|
+
var escapeHtml55 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34032
34297
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
34033
34298
|
var getNumber12 = (value) => {
|
|
34034
34299
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -34109,14 +34374,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
34109
34374
|
if (entries.length === 0) {
|
|
34110
34375
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
34111
34376
|
}
|
|
34112
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
34377
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml55(sinkId)}</strong>: ${escapeHtml55(result.status)}${result.deliveredTo ? ` to ${escapeHtml55(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml55(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
34113
34378
|
};
|
|
34114
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
34379
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml55(event.type)} <small>${escapeHtml55(event.id)}</small>${event.sessionId ? ` session=${escapeHtml55(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
34115
34380
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
34116
34381
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
34117
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
34118
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
34119
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
34382
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml55(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
34383
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml55(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml55(delivery.deliveryStatus)}</span><h2>${escapeHtml55(delivery.id)}</h2><p>${escapeHtml55(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml55(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml55(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
34384
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml55(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml55(title)}</h1><p>Checked ${escapeHtml55(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
|
|
34120
34385
|
};
|
|
34121
34386
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
34122
34387
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -36228,6 +36493,8 @@ export {
|
|
|
36228
36493
|
renderVoiceProviderDecisionTraceHTML,
|
|
36229
36494
|
renderVoiceProviderContractMatrixHTML,
|
|
36230
36495
|
renderVoiceProviderCapabilityHTML,
|
|
36496
|
+
renderVoiceProofTrendRecommendationMarkdown,
|
|
36497
|
+
renderVoiceProofTrendRecommendationHTML,
|
|
36231
36498
|
renderVoiceProductionReadinessHTML,
|
|
36232
36499
|
renderVoicePostCallAnalysisMarkdown,
|
|
36233
36500
|
renderVoicePhoneAgentProductionSmokeHTML,
|
|
@@ -36475,6 +36742,7 @@ export {
|
|
|
36475
36742
|
createVoiceProviderCapabilityJSONHandler,
|
|
36476
36743
|
createVoiceProviderCapabilityHTMLHandler,
|
|
36477
36744
|
createVoiceProofTrendRoutes,
|
|
36745
|
+
createVoiceProofTrendRecommendationRoutes,
|
|
36478
36746
|
createVoiceProductionReadinessRoutes,
|
|
36479
36747
|
createVoicePostgresTraceSinkDeliveryStore,
|
|
36480
36748
|
createVoicePostgresTraceEventStore,
|
|
@@ -36669,6 +36937,7 @@ export {
|
|
|
36669
36937
|
buildVoiceProviderDecisionTraceReport,
|
|
36670
36938
|
buildVoiceProviderContractMatrix,
|
|
36671
36939
|
buildVoiceProofTrendReport,
|
|
36940
|
+
buildVoiceProofTrendRecommendationReport,
|
|
36672
36941
|
buildVoiceProductionReadinessReport,
|
|
36673
36942
|
buildVoiceProductionReadinessGate,
|
|
36674
36943
|
buildVoicePostCallAnalysisReport,
|