@absolutejs/voice 0.0.22-beta.333 → 0.0.22-beta.334
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.js +323 -167
- package/dist/index.d.ts +2 -2
- package/dist/index.js +445 -285
- package/dist/proofTrends.d.ts +74 -0
- package/dist/react/index.js +283 -127
- package/dist/vue/index.js +258 -102
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14647,6 +14647,162 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
14647
14647
|
}
|
|
14648
14648
|
return assertion;
|
|
14649
14649
|
};
|
|
14650
|
+
var DEFAULT_RECOMMENDATION_BUDGETS = {
|
|
14651
|
+
maxLiveP95Ms: 800,
|
|
14652
|
+
maxProviderP95Ms: 1000,
|
|
14653
|
+
maxRuntimeBackpressureEvents: 0,
|
|
14654
|
+
maxRuntimeFirstAudioLatencyMs: 600,
|
|
14655
|
+
maxRuntimeInterruptionP95Ms: 300,
|
|
14656
|
+
maxRuntimeJitterMs: 30,
|
|
14657
|
+
maxRuntimeTimestampDriftMs: 800,
|
|
14658
|
+
maxTurnP95Ms: 700
|
|
14659
|
+
};
|
|
14660
|
+
var withinBudget = (value, budget) => typeof value === "number" && Number.isFinite(value) && value <= budget;
|
|
14661
|
+
var recommendationStatusRank = {
|
|
14662
|
+
pass: 0,
|
|
14663
|
+
warn: 1,
|
|
14664
|
+
fail: 2
|
|
14665
|
+
};
|
|
14666
|
+
var worstRecommendationStatus = (recommendations) => recommendations.reduce((status, recommendation) => recommendationStatusRank[recommendation.status] > recommendationStatusRank[status] ? recommendation.status : status, "pass");
|
|
14667
|
+
var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
14668
|
+
const budgets = { ...DEFAULT_RECOMMENDATION_BUDGETS, ...options };
|
|
14669
|
+
const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
|
|
14670
|
+
const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
|
|
14671
|
+
const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
|
|
14672
|
+
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
14673
|
+
const recommendations = [];
|
|
14674
|
+
const issues = [];
|
|
14675
|
+
if (report.ok !== true) {
|
|
14676
|
+
issues.push(`Proof trend report is ${report.status}; recommendations need a fresh passing trend artifact.`);
|
|
14677
|
+
}
|
|
14678
|
+
recommendations.push({
|
|
14679
|
+
evidence: {
|
|
14680
|
+
budgetMs: budgets.maxProviderP95Ms,
|
|
14681
|
+
providerP95Ms: maxProviderP95Ms
|
|
14682
|
+
},
|
|
14683
|
+
nextMove: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
|
|
14684
|
+
recommendation: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
|
|
14685
|
+
status: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
14686
|
+
surface: "provider-path"
|
|
14687
|
+
});
|
|
14688
|
+
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);
|
|
14689
|
+
recommendations.push({
|
|
14690
|
+
evidence: {
|
|
14691
|
+
backpressureEvents: runtimeChannel.maxBackpressureEvents,
|
|
14692
|
+
firstAudioBudgetMs: budgets.maxRuntimeFirstAudioLatencyMs,
|
|
14693
|
+
firstAudioMs: runtimeChannel.maxFirstAudioLatencyMs,
|
|
14694
|
+
interruptionBudgetMs: budgets.maxRuntimeInterruptionP95Ms,
|
|
14695
|
+
interruptionP95Ms: runtimeChannel.maxInterruptionP95Ms,
|
|
14696
|
+
jitterBudgetMs: budgets.maxRuntimeJitterMs,
|
|
14697
|
+
jitterMs: runtimeChannel.maxJitterMs,
|
|
14698
|
+
samples: runtimeChannel.samples,
|
|
14699
|
+
timestampDriftMs: runtimeChannel.maxTimestampDriftMs
|
|
14700
|
+
},
|
|
14701
|
+
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.",
|
|
14702
|
+
recommendation: runtimePass ? "Keep current runtime channel" : "Tune runtime channel before promotion",
|
|
14703
|
+
status: runtimePass ? "pass" : runtimeChannel.samples === undefined ? "fail" : "warn",
|
|
14704
|
+
surface: "runtime-channel"
|
|
14705
|
+
});
|
|
14706
|
+
recommendations.push({
|
|
14707
|
+
evidence: {
|
|
14708
|
+
budgetMs: budgets.maxLiveP95Ms,
|
|
14709
|
+
liveP95Ms: maxLiveP95Ms
|
|
14710
|
+
},
|
|
14711
|
+
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.",
|
|
14712
|
+
recommendation: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep live-latency settings" : "Tune live-latency path",
|
|
14713
|
+
status: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "pass" : maxLiveP95Ms === undefined ? "fail" : "warn",
|
|
14714
|
+
surface: "live-latency"
|
|
14715
|
+
});
|
|
14716
|
+
recommendations.push({
|
|
14717
|
+
evidence: {
|
|
14718
|
+
budgetMs: budgets.maxTurnP95Ms,
|
|
14719
|
+
turnP95Ms: maxTurnP95Ms
|
|
14720
|
+
},
|
|
14721
|
+
nextMove: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep current turn pipeline defaults." : "Reduce tool/provider latency or split the turn pipeline before promotion.",
|
|
14722
|
+
recommendation: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep turn pipeline" : "Tune turn pipeline",
|
|
14723
|
+
status: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "pass" : maxTurnP95Ms === undefined ? "fail" : "warn",
|
|
14724
|
+
surface: "turn-latency"
|
|
14725
|
+
});
|
|
14726
|
+
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
14727
|
+
return {
|
|
14728
|
+
generatedAt: new Date().toISOString(),
|
|
14729
|
+
issues,
|
|
14730
|
+
ok: status !== "fail",
|
|
14731
|
+
recommendations,
|
|
14732
|
+
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
14733
|
+
status,
|
|
14734
|
+
summary: {
|
|
14735
|
+
keepCurrentProviderPath: recommendations.find((item) => item.surface === "provider-path")?.status === "pass",
|
|
14736
|
+
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
14737
|
+
recommendedActions: recommendations.filter((item) => item.status !== "pass").length
|
|
14738
|
+
}
|
|
14739
|
+
};
|
|
14740
|
+
};
|
|
14741
|
+
var escapeHtml22 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14742
|
+
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
14743
|
+
var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
|
|
14744
|
+
`# ${title}`,
|
|
14745
|
+
"",
|
|
14746
|
+
`- Status: ${report.status}`,
|
|
14747
|
+
`- Source: ${report.source}`,
|
|
14748
|
+
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
14749
|
+
"",
|
|
14750
|
+
"| Surface | Status | Recommendation | Next move |",
|
|
14751
|
+
"| --- | --- | --- | --- |",
|
|
14752
|
+
...report.recommendations.map((recommendation) => `| ${escapeMarkdown2(recommendation.surface)} | ${recommendation.status} | ${escapeMarkdown2(recommendation.recommendation)} | ${escapeMarkdown2(recommendation.nextMove)} |`),
|
|
14753
|
+
"",
|
|
14754
|
+
"## Issues",
|
|
14755
|
+
"",
|
|
14756
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
14757
|
+
].join(`
|
|
14758
|
+
`);
|
|
14759
|
+
var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
|
|
14760
|
+
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("");
|
|
14761
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml22(issue)}</li>`).join("");
|
|
14762
|
+
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}</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">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
|
|
14763
|
+
};
|
|
14764
|
+
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
14765
|
+
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
|
14766
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/proof-trend-recommendations" : options.htmlPath;
|
|
14767
|
+
const markdownPath = options.markdownPath === undefined ? "/voice/proof-trend-recommendations.md" : options.markdownPath;
|
|
14768
|
+
const title = options.title ?? "Voice Provider Runtime Recommendations";
|
|
14769
|
+
const routes = new Elysia20({
|
|
14770
|
+
name: options.name ?? "absolutejs-voice-proof-trend-recommendations"
|
|
14771
|
+
});
|
|
14772
|
+
const loadReport = async () => {
|
|
14773
|
+
const value = options.source !== undefined ? typeof options.source === "function" ? await options.source() : options.source : options.jsonPath ? await readVoiceProofTrendReportFile(options.jsonPath, {
|
|
14774
|
+
maxAgeMs: options.maxAgeMs
|
|
14775
|
+
}) : buildEmptyVoiceProofTrendReport("", options.maxAgeMs);
|
|
14776
|
+
return buildVoiceProofTrendRecommendationReport(normalizeVoiceProofTrendReport(value, {
|
|
14777
|
+
maxAgeMs: options.maxAgeMs,
|
|
14778
|
+
source: options.jsonPath
|
|
14779
|
+
}), options);
|
|
14780
|
+
};
|
|
14781
|
+
routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
|
|
14782
|
+
if (htmlPath !== false) {
|
|
14783
|
+
routes.get(htmlPath, async () => {
|
|
14784
|
+
const report = await loadReport();
|
|
14785
|
+
return new Response(renderVoiceProofTrendRecommendationHTML(report, title), {
|
|
14786
|
+
headers: {
|
|
14787
|
+
"content-type": "text/html; charset=utf-8",
|
|
14788
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
14789
|
+
}
|
|
14790
|
+
});
|
|
14791
|
+
});
|
|
14792
|
+
}
|
|
14793
|
+
if (markdownPath !== false) {
|
|
14794
|
+
routes.get(markdownPath, async () => {
|
|
14795
|
+
const report = await loadReport();
|
|
14796
|
+
return new Response(renderVoiceProofTrendRecommendationMarkdown(report, title), {
|
|
14797
|
+
headers: {
|
|
14798
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
14799
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
14800
|
+
}
|
|
14801
|
+
});
|
|
14802
|
+
});
|
|
14803
|
+
}
|
|
14804
|
+
return routes;
|
|
14805
|
+
};
|
|
14650
14806
|
var createVoiceProofTrendRoutes = (options) => {
|
|
14651
14807
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
14652
14808
|
const routes = new Elysia20({
|
|
@@ -14686,7 +14842,7 @@ import { Elysia as Elysia22 } from "elysia";
|
|
|
14686
14842
|
|
|
14687
14843
|
// src/resilienceRoutes.ts
|
|
14688
14844
|
import { Elysia as Elysia21 } from "elysia";
|
|
14689
|
-
var
|
|
14845
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14690
14846
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
14691
14847
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14692
14848
|
var getBoolean2 = (value) => value === true;
|
|
@@ -14834,13 +14990,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
14834
14990
|
};
|
|
14835
14991
|
var renderProviderCards = (title, providers) => {
|
|
14836
14992
|
if (providers.length === 0) {
|
|
14837
|
-
return `<p class="muted">No ${
|
|
14993
|
+
return `<p class="muted">No ${escapeHtml23(title)} provider health yet.</p>`;
|
|
14838
14994
|
}
|
|
14839
14995
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
14840
|
-
<article class="card provider ${
|
|
14996
|
+
<article class="card provider ${escapeHtml23(provider.status)}">
|
|
14841
14997
|
<div class="card-header">
|
|
14842
|
-
<strong>${
|
|
14843
|
-
<span>${
|
|
14998
|
+
<strong>${escapeHtml23(provider.provider)}</strong>
|
|
14999
|
+
<span>${escapeHtml23(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
14844
15000
|
</div>
|
|
14845
15001
|
<dl>
|
|
14846
15002
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -14849,7 +15005,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
14849
15005
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
14850
15006
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
14851
15007
|
</dl>
|
|
14852
|
-
${provider.lastError ? `<p class="muted">${
|
|
15008
|
+
${provider.lastError ? `<p class="muted">${escapeHtml23(provider.lastError)}</p>` : ""}
|
|
14853
15009
|
</article>
|
|
14854
15010
|
`).join("")}</div>`;
|
|
14855
15011
|
};
|
|
@@ -14858,24 +15014,24 @@ var renderTimeline2 = (events) => {
|
|
|
14858
15014
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
14859
15015
|
}
|
|
14860
15016
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
14861
|
-
<article class="card event ${
|
|
15017
|
+
<article class="card event ${escapeHtml23(event.status ?? "unknown")}">
|
|
14862
15018
|
<div class="card-header">
|
|
14863
|
-
<strong>${
|
|
15019
|
+
<strong>${escapeHtml23(event.kind.toUpperCase())} ${escapeHtml23(event.operation ?? "generate")}</strong>
|
|
14864
15020
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
14865
15021
|
</div>
|
|
14866
15022
|
<p>
|
|
14867
|
-
<span class="pill">${
|
|
14868
|
-
<span class="pill">provider: ${
|
|
14869
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
15023
|
+
<span class="pill">${escapeHtml23(event.status ?? "unknown")}</span>
|
|
15024
|
+
<span class="pill">provider: ${escapeHtml23(event.provider ?? "unknown")}</span>
|
|
15025
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml23(event.fallbackProvider)}</span>` : ""}
|
|
14870
15026
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
14871
15027
|
</p>
|
|
14872
15028
|
<dl>
|
|
14873
15029
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
14874
15030
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
14875
15031
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
14876
|
-
<div><dt>Session</dt><dd>${
|
|
15032
|
+
<div><dt>Session</dt><dd>${escapeHtml23(event.sessionId)}</dd></div>
|
|
14877
15033
|
</dl>
|
|
14878
|
-
${event.error ? `<p class="muted">${
|
|
15034
|
+
${event.error ? `<p class="muted">${escapeHtml23(event.error)}</p>` : ""}
|
|
14879
15035
|
</article>
|
|
14880
15036
|
`).join("")}</div>`;
|
|
14881
15037
|
};
|
|
@@ -14885,9 +15041,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
14885
15041
|
const status = latest?.status ?? "idle";
|
|
14886
15042
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
14887
15043
|
return `<div>
|
|
14888
|
-
<dt>${
|
|
14889
|
-
<dd>${
|
|
14890
|
-
<small>${
|
|
15044
|
+
<dt>${escapeHtml23(kind.toUpperCase())}</dt>
|
|
15045
|
+
<dd>${escapeHtml23(provider)}${escapeHtml23(fallback)}</dd>
|
|
15046
|
+
<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
15047
|
</div>`;
|
|
14892
15048
|
};
|
|
14893
15049
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -14895,10 +15051,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
14895
15051
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
14896
15052
|
}
|
|
14897
15053
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
14898
|
-
<article class="card session ${
|
|
15054
|
+
<article class="card session ${escapeHtml23(session.status)}">
|
|
14899
15055
|
<div class="card-header">
|
|
14900
|
-
<strong>${
|
|
14901
|
-
<span>${
|
|
15056
|
+
<strong>${escapeHtml23(session.sessionId)}</strong>
|
|
15057
|
+
<span>${escapeHtml23(session.status)}</span>
|
|
14902
15058
|
</div>
|
|
14903
15059
|
<p>
|
|
14904
15060
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -14925,21 +15081,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
14925
15081
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
14926
15082
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
14927
15083
|
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">${
|
|
15084
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml23(pathPrefix)}">
|
|
15085
|
+
<p class="muted">${escapeHtml23(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
14930
15086
|
<div class="simulate-actions">
|
|
14931
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
14932
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
15087
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml23(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml23(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
15088
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml23(provider.provider)}">Mark ${escapeHtml23(provider.provider)} recovered</button>`).join("")}
|
|
14933
15089
|
</div>
|
|
14934
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
15090
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml23(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
14935
15091
|
<pre class="simulate-output" hidden></pre>
|
|
14936
15092
|
</div>`;
|
|
14937
15093
|
};
|
|
14938
15094
|
var renderVoiceResilienceHTML = (input) => {
|
|
14939
15095
|
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 =
|
|
15096
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml23(kind)}: ${String(count)}</span>`).join("");
|
|
15097
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml23(link.href)}">${escapeHtml23(link.label)}</a>`).join(" \xB7 ") : "";
|
|
15098
|
+
const snippet = escapeHtml23(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
14943
15099
|
kind: 'stt',
|
|
14944
15100
|
providers: ['deepgram', 'assemblyai'],
|
|
14945
15101
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -14977,7 +15133,7 @@ app.use(
|
|
|
14977
15133
|
<head>
|
|
14978
15134
|
<meta charset="utf-8" />
|
|
14979
15135
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14980
|
-
<title>${
|
|
15136
|
+
<title>${escapeHtml23(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
14981
15137
|
<style>
|
|
14982
15138
|
:root { color-scheme: dark; }
|
|
14983
15139
|
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 +15326,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
15170
15326
|
};
|
|
15171
15327
|
|
|
15172
15328
|
// src/providerDecisionTraces.ts
|
|
15173
|
-
var
|
|
15329
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15174
15330
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
15175
15331
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
15176
15332
|
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 +15567,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
15411
15567
|
<head>
|
|
15412
15568
|
<meta charset="utf-8" />
|
|
15413
15569
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15414
|
-
<title>${
|
|
15570
|
+
<title>${escapeHtml24(title)}</title>
|
|
15415
15571
|
<style>
|
|
15416
15572
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
15417
15573
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -15425,8 +15581,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
15425
15581
|
</head>
|
|
15426
15582
|
<body>
|
|
15427
15583
|
<main>
|
|
15428
|
-
<p class="status ${report.status}">${
|
|
15429
|
-
<h1>${
|
|
15584
|
+
<p class="status ${report.status}">${escapeHtml24(report.status)}</p>
|
|
15585
|
+
<h1>${escapeHtml24(title)}</h1>
|
|
15430
15586
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
15431
15587
|
<section class="grid">
|
|
15432
15588
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -15437,10 +15593,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
15437
15593
|
</section>
|
|
15438
15594
|
<section class="surfaces">
|
|
15439
15595
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
15440
|
-
<header><strong>${
|
|
15596
|
+
<header><strong>${escapeHtml24(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml24(surface.status)}</span></header>
|
|
15441
15597
|
<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>${
|
|
15598
|
+
<p class="muted">Providers: ${escapeHtml24(surface.providers.join(", ") || "none")}</p>
|
|
15599
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml24(reason)}</code>`).join(" ")}</p>
|
|
15444
15600
|
</article>`).join(`
|
|
15445
15601
|
`)}
|
|
15446
15602
|
</section>
|
|
@@ -15662,8 +15818,8 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
15662
15818
|
status: profile.status
|
|
15663
15819
|
};
|
|
15664
15820
|
};
|
|
15665
|
-
var
|
|
15666
|
-
var
|
|
15821
|
+
var escapeMarkdown3 = (value) => value.replaceAll("|", "\\|");
|
|
15822
|
+
var escapeHtml25 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15667
15823
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
15668
15824
|
var readinessThresholdRows = (report) => [
|
|
15669
15825
|
{
|
|
@@ -15708,7 +15864,7 @@ var readinessThresholdRows = (report) => [
|
|
|
15708
15864
|
}
|
|
15709
15865
|
];
|
|
15710
15866
|
var renderVoiceSloCalibrationMarkdown = (report, options = {}) => {
|
|
15711
|
-
const rows = Object.values(report.thresholds).map((threshold) => `| ${
|
|
15867
|
+
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
15868
|
`);
|
|
15713
15869
|
return `# ${options.title ?? "Voice SLO Calibration"}
|
|
15714
15870
|
|
|
@@ -15729,7 +15885,7 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
15729
15885
|
`;
|
|
15730
15886
|
};
|
|
15731
15887
|
var renderVoiceSloReadinessThresholdMarkdown = (report, options = {}) => {
|
|
15732
|
-
const rows = readinessThresholdRows(report).map((row) => `| ${
|
|
15888
|
+
const rows = readinessThresholdRows(report).map((row) => `| ${escapeMarkdown3(row.control)} | ${formatMs(row.value)} | ${escapeMarkdown3(row.usedBy)} |`).join(`
|
|
15733
15889
|
`);
|
|
15734
15890
|
return `# ${options.title ?? "Calibration -> Active Readiness Gate"}
|
|
15735
15891
|
|
|
@@ -15754,10 +15910,10 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
15754
15910
|
};
|
|
15755
15911
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
15756
15912
|
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>${
|
|
15913
|
+
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("");
|
|
15914
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml25(issue)}</li>`).join("");
|
|
15915
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml25(source)}</code></li>`).join("");
|
|
15916
|
+
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
15917
|
};
|
|
15762
15918
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
15763
15919
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
@@ -16155,12 +16311,12 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
16155
16311
|
import { Elysia as Elysia25 } from "elysia";
|
|
16156
16312
|
import { mkdir } from "fs/promises";
|
|
16157
16313
|
import { dirname, join } from "path";
|
|
16158
|
-
var
|
|
16314
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16159
16315
|
var renderSummaryCard = (label, summary) => {
|
|
16160
16316
|
if (!summary) {
|
|
16161
|
-
return `<article><span>${
|
|
16317
|
+
return `<article><span>${escapeHtml26(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
16162
16318
|
}
|
|
16163
|
-
return `<article><span>${
|
|
16319
|
+
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
16320
|
};
|
|
16165
16321
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
16166
16322
|
audit: leases,
|
|
@@ -16371,9 +16527,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
16371
16527
|
});
|
|
16372
16528
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
16373
16529
|
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 =
|
|
16530
|
+
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>`;
|
|
16531
|
+
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>`;
|
|
16532
|
+
const snippet = escapeHtml26(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
16377
16533
|
createVoiceDeliveryRuntimePresetConfig({
|
|
16378
16534
|
audit: {
|
|
16379
16535
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -16399,7 +16555,7 @@ app.use(
|
|
|
16399
16555
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
16400
16556
|
})
|
|
16401
16557
|
);`);
|
|
16402
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16558
|
+
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
16559
|
};
|
|
16404
16560
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
16405
16561
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
@@ -16681,7 +16837,7 @@ var parseRetentionScopes = (value) => {
|
|
|
16681
16837
|
const allowed = new Set(allRetentionScopes);
|
|
16682
16838
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
16683
16839
|
};
|
|
16684
|
-
var
|
|
16840
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16685
16841
|
var buildStorageSurfaces = (options) => [
|
|
16686
16842
|
{
|
|
16687
16843
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -16918,12 +17074,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
16918
17074
|
zeroRetentionAvailable: true
|
|
16919
17075
|
};
|
|
16920
17076
|
};
|
|
16921
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
17077
|
+
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
17078
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
16923
17079
|
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>${
|
|
17080
|
+
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("");
|
|
17081
|
+
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("");
|
|
17082
|
+
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
17083
|
};
|
|
16928
17084
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
16929
17085
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -17066,7 +17222,7 @@ import { Elysia as Elysia28 } from "elysia";
|
|
|
17066
17222
|
|
|
17067
17223
|
// src/handoffHealth.ts
|
|
17068
17224
|
import { Elysia as Elysia27 } from "elysia";
|
|
17069
|
-
var
|
|
17225
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17070
17226
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
17071
17227
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
17072
17228
|
var increment3 = (record, key) => {
|
|
@@ -17184,10 +17340,10 @@ var renderActionSummary = (summary) => {
|
|
|
17184
17340
|
return [
|
|
17185
17341
|
'<section class="voice-handoff-health-columns">',
|
|
17186
17342
|
"<article><h3>Actions</h3>",
|
|
17187
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
17343
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml28(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
17188
17344
|
"</article>",
|
|
17189
17345
|
"<article><h3>Adapters</h3>",
|
|
17190
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
17346
|
+
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
17347
|
"</article>",
|
|
17192
17348
|
"</section>"
|
|
17193
17349
|
].join("");
|
|
@@ -17201,22 +17357,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
17201
17357
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
17202
17358
|
'<div class="voice-handoff-health-events">',
|
|
17203
17359
|
...summary.events.map((event) => [
|
|
17204
|
-
`<article class="${
|
|
17360
|
+
`<article class="${escapeHtml28(event.status)}">`,
|
|
17205
17361
|
'<div class="voice-handoff-health-event-header">',
|
|
17206
|
-
`<strong>${
|
|
17207
|
-
`<span>${
|
|
17362
|
+
`<strong>${escapeHtml28(event.action ?? "handoff")}</strong>`,
|
|
17363
|
+
`<span>${escapeHtml28(event.status)}</span>`,
|
|
17208
17364
|
"</div>",
|
|
17209
|
-
`<p><small>${
|
|
17210
|
-
event.target ? `<p>Target: ${
|
|
17211
|
-
event.reason ? `<p>Reason: ${
|
|
17365
|
+
`<p><small>${escapeHtml28(event.sessionId)}</small></p>`,
|
|
17366
|
+
event.target ? `<p>Target: ${escapeHtml28(event.target)}</p>` : "",
|
|
17367
|
+
event.reason ? `<p>Reason: ${escapeHtml28(event.reason)}</p>` : "",
|
|
17212
17368
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
17213
17369
|
"<li>",
|
|
17214
|
-
`${
|
|
17215
|
-
delivery.deliveredTo ? ` to ${
|
|
17216
|
-
delivery.error ? ` (${
|
|
17370
|
+
`${escapeHtml28(delivery.adapterId)}: ${escapeHtml28(delivery.status)}`,
|
|
17371
|
+
delivery.deliveredTo ? ` to ${escapeHtml28(delivery.deliveredTo)}` : "",
|
|
17372
|
+
delivery.error ? ` (${escapeHtml28(delivery.error)})` : "",
|
|
17217
17373
|
"</li>"
|
|
17218
17374
|
].join("")).join("")}</ul>` : "",
|
|
17219
|
-
event.replayHref ? `<p><a href="${
|
|
17375
|
+
event.replayHref ? `<p><a href="${escapeHtml28(event.replayHref)}">Open replay</a></p>` : "",
|
|
17220
17376
|
"</article>"
|
|
17221
17377
|
].join("")),
|
|
17222
17378
|
"</div>"
|
|
@@ -17369,12 +17525,12 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
17369
17525
|
thresholds
|
|
17370
17526
|
};
|
|
17371
17527
|
};
|
|
17372
|
-
var
|
|
17528
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17373
17529
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
17374
17530
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
17375
17531
|
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="${
|
|
17532
|
+
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("");
|
|
17533
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml29(link.href)}">${escapeHtml29(link.label)}</a>`).join("")}</nav>` : "";
|
|
17378
17534
|
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
17535
|
};
|
|
17380
17536
|
var createVoiceQualityRoutes = (options) => {
|
|
@@ -17408,7 +17564,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
17408
17564
|
};
|
|
17409
17565
|
|
|
17410
17566
|
// src/evalRoutes.ts
|
|
17411
|
-
var
|
|
17567
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17412
17568
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
17413
17569
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
17414
17570
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -17730,7 +17886,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
17730
17886
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
17731
17887
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
17732
17888
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
17733
|
-
const snippet =
|
|
17889
|
+
const snippet = escapeHtml30(`app.use(
|
|
17734
17890
|
createVoiceEvalRoutes({
|
|
17735
17891
|
path: '/evals',
|
|
17736
17892
|
store: traceStore,
|
|
@@ -17751,44 +17907,44 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
17751
17907
|
};
|
|
17752
17908
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
17753
17909
|
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>${
|
|
17910
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
17911
|
+
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
17912
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
17757
17913
|
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>${
|
|
17914
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml30(session.operationsRecordHref)}">${escapeHtml30(session.sessionId)}</a>` : escapeHtml30(session.sessionId);
|
|
17915
|
+
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
17916
|
}).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>${
|
|
17917
|
+
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
17918
|
};
|
|
17763
17919
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
17764
17920
|
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>${
|
|
17921
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
17922
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml30(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
17923
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml30(id)}</li>`).join("") : "<li>none</li>";
|
|
17924
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml30(id)}</li>`).join("") : "<li>none</li>";
|
|
17925
|
+
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
17926
|
};
|
|
17771
17927
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
17772
17928
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
17773
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17929
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
17774
17930
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
17775
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
17931
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml30(issue)}</li>`).join("")}</ul>` : "";
|
|
17776
17932
|
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>${
|
|
17933
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml30(session.operationsRecordHref)}">${escapeHtml30(session.sessionId)}</a>` : escapeHtml30(session.sessionId);
|
|
17934
|
+
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
17935
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
17780
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
17936
|
+
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
17937
|
}).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>${
|
|
17938
|
+
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
17939
|
};
|
|
17784
17940
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
17785
17941
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
17786
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17942
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join("")}</nav>` : "";
|
|
17787
17943
|
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>${
|
|
17944
|
+
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("");
|
|
17945
|
+
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
17946
|
}).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>${
|
|
17947
|
+
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
17948
|
};
|
|
17793
17949
|
var createVoiceEvalRoutes = (options) => {
|
|
17794
17950
|
const path = options.path ?? "/evals";
|
|
@@ -17933,7 +18089,7 @@ import { Elysia as Elysia32 } from "elysia";
|
|
|
17933
18089
|
|
|
17934
18090
|
// src/outcomeContract.ts
|
|
17935
18091
|
import { Elysia as Elysia30 } from "elysia";
|
|
17936
|
-
var
|
|
18092
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17937
18093
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
17938
18094
|
if (value === false) {
|
|
17939
18095
|
return;
|
|
@@ -18144,13 +18300,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
18144
18300
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
18145
18301
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
18146
18302
|
const contracts = report.contracts.map((contract) => {
|
|
18147
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
18303
|
+
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
18304
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
18149
18305
|
<div class="contract-header">
|
|
18150
18306
|
<div>
|
|
18151
|
-
<p class="eyebrow">${
|
|
18152
|
-
<h2>${
|
|
18153
|
-
${contract.description ? `<p>${
|
|
18307
|
+
<p class="eyebrow">${escapeHtml31(contract.contractId)}</p>
|
|
18308
|
+
<h2>${escapeHtml31(contract.label ?? contract.contractId)}</h2>
|
|
18309
|
+
${contract.description ? `<p>${escapeHtml31(contract.description)}</p>` : ""}
|
|
18154
18310
|
${sessionLinks}
|
|
18155
18311
|
</div>
|
|
18156
18312
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -18162,10 +18318,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
18162
18318
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
18163
18319
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
18164
18320
|
</div>
|
|
18165
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
18321
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml31(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
18166
18322
|
</section>`;
|
|
18167
18323
|
}).join("");
|
|
18168
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18324
|
+
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
18325
|
};
|
|
18170
18326
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
18171
18327
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -18400,7 +18556,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
18400
18556
|
});
|
|
18401
18557
|
var defaultApi = {};
|
|
18402
18558
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
18403
|
-
var
|
|
18559
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18404
18560
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
18405
18561
|
if (value === false) {
|
|
18406
18562
|
return;
|
|
@@ -18649,7 +18805,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
18649
18805
|
};
|
|
18650
18806
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
18651
18807
|
const title = options.title ?? "Voice Tool Contracts";
|
|
18652
|
-
const snippet =
|
|
18808
|
+
const snippet = escapeHtml32(`app.use(
|
|
18653
18809
|
createVoiceToolContractRoutes({
|
|
18654
18810
|
htmlPath: '/tool-contracts',
|
|
18655
18811
|
path: '/api/tool-contracts',
|
|
@@ -18675,20 +18831,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18675
18831
|
);`);
|
|
18676
18832
|
const contracts = report.contracts.map((contract) => {
|
|
18677
18833
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
18678
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
18834
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml32(testCase.operationsRecordHref)}">${escapeHtml32(testCase.label ?? testCase.caseId)}</a>` : escapeHtml32(testCase.label ?? testCase.caseId)}</td>
|
|
18679
18835
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
18680
|
-
<td>${
|
|
18681
|
-
<td>${
|
|
18836
|
+
<td>${escapeHtml32(testCase.status)}</td>
|
|
18837
|
+
<td>${escapeHtml32(testCase.sessionId)}</td>
|
|
18682
18838
|
<td>${String(testCase.attempts)}</td>
|
|
18683
18839
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
18684
18840
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
18685
|
-
<td>${
|
|
18841
|
+
<td>${escapeHtml32(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
18686
18842
|
</tr>`).join("");
|
|
18687
18843
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
18688
18844
|
<div class="contract-header">
|
|
18689
18845
|
<div>
|
|
18690
|
-
<p class="eyebrow">${
|
|
18691
|
-
<h2>${
|
|
18846
|
+
<p class="eyebrow">${escapeHtml32(contract.toolName)}</p>
|
|
18847
|
+
<h2>${escapeHtml32(contract.label ?? contract.contractId)}</h2>
|
|
18692
18848
|
</div>
|
|
18693
18849
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
18694
18850
|
</div>
|
|
@@ -18698,7 +18854,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18698
18854
|
</table>
|
|
18699
18855
|
</section>`;
|
|
18700
18856
|
}).join("");
|
|
18701
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18857
|
+
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
18858
|
};
|
|
18703
18859
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
18704
18860
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -18725,7 +18881,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
18725
18881
|
};
|
|
18726
18882
|
|
|
18727
18883
|
// src/simulationSuite.ts
|
|
18728
|
-
var
|
|
18884
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18729
18885
|
var summarizeSection = (report) => ({
|
|
18730
18886
|
failed: report.failed,
|
|
18731
18887
|
passed: report.passed,
|
|
@@ -18921,15 +19077,15 @@ var renderSection = (label, summary) => {
|
|
|
18921
19077
|
if (!summary) {
|
|
18922
19078
|
return "";
|
|
18923
19079
|
}
|
|
18924
|
-
return `<article class="${
|
|
19080
|
+
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
19081
|
};
|
|
18926
19082
|
var renderAction = (action) => {
|
|
18927
|
-
const content = `<strong>${
|
|
18928
|
-
return action.href ? `<a class="action" href="${
|
|
19083
|
+
const content = `<strong>${escapeHtml33(action.label)}</strong><p>${escapeHtml33(action.description)}</p><span>${escapeHtml33(action.section)} / ${escapeHtml33(action.severity)}</span>`;
|
|
19084
|
+
return action.href ? `<a class="action" href="${escapeHtml33(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
18929
19085
|
};
|
|
18930
19086
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
18931
19087
|
const title = options.title ?? "Voice Simulation Suite";
|
|
18932
|
-
const snippet =
|
|
19088
|
+
const snippet = escapeHtml33(`app.use(
|
|
18933
19089
|
createVoiceSimulationSuiteRoutes({
|
|
18934
19090
|
htmlPath: '/voice/simulations',
|
|
18935
19091
|
path: '/api/voice/simulations',
|
|
@@ -18962,7 +19118,7 @@ app.use(
|
|
|
18962
19118
|
store: traceStore
|
|
18963
19119
|
})
|
|
18964
19120
|
);`);
|
|
18965
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19121
|
+
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
19122
|
};
|
|
18967
19123
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
18968
19124
|
const path = options.path ?? "/api/voice/simulations";
|
|
@@ -19281,7 +19437,7 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
19281
19437
|
// src/sessionReplay.ts
|
|
19282
19438
|
import { Elysia as Elysia33 } from "elysia";
|
|
19283
19439
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
19284
|
-
var
|
|
19440
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19285
19441
|
var increment4 = (record, key) => {
|
|
19286
19442
|
record[key] = (record[key] ?? 0) + 1;
|
|
19287
19443
|
};
|
|
@@ -19475,10 +19631,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
19475
19631
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
19476
19632
|
'<div class="voice-sessions-list">',
|
|
19477
19633
|
...sessions.map((session) => [
|
|
19478
|
-
`<article class="voice-session-card ${
|
|
19634
|
+
`<article class="voice-session-card ${escapeHtml34(session.status)}">`,
|
|
19479
19635
|
'<div class="voice-session-card-header">',
|
|
19480
|
-
`<strong>${
|
|
19481
|
-
`<span>${
|
|
19636
|
+
`<strong>${escapeHtml34(session.sessionId)}</strong>`,
|
|
19637
|
+
`<span>${escapeHtml34(session.status)}</span>`,
|
|
19482
19638
|
"</div>",
|
|
19483
19639
|
"<dl>",
|
|
19484
19640
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -19486,9 +19642,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
19486
19642
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
19487
19643
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
19488
19644
|
"</dl>",
|
|
19489
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
19490
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
19491
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
19645
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml34(session.latestOutcome)}</p>` : "",
|
|
19646
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml34).join(", ")}</p>` : "",
|
|
19647
|
+
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
19648
|
"</article>"
|
|
19493
19649
|
].join("")),
|
|
19494
19650
|
"</div>"
|
|
@@ -19864,7 +20020,7 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
19864
20020
|
import { Elysia as Elysia34 } from "elysia";
|
|
19865
20021
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
19866
20022
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
19867
|
-
var
|
|
20023
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19868
20024
|
var firstNumber2 = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19869
20025
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
19870
20026
|
var createTraceStageIndex = (events) => {
|
|
@@ -19996,11 +20152,11 @@ await traceStore.append({
|
|
|
19996
20152
|
turnId,
|
|
19997
20153
|
type: 'turn_latency.stage'
|
|
19998
20154
|
});`;
|
|
19999
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
20000
|
-
<header><div><p class="eyebrow">${
|
|
20001
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
20155
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml35(turn.status)}">
|
|
20156
|
+
<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>
|
|
20157
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml35(stage.label)}</dt><dd>${escapeHtml35(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
20002
20158
|
</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>${
|
|
20159
|
+
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
20160
|
};
|
|
20005
20161
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
20006
20162
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -20027,7 +20183,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
20027
20183
|
};
|
|
20028
20184
|
// src/liveLatency.ts
|
|
20029
20185
|
import { Elysia as Elysia35 } from "elysia";
|
|
20030
|
-
var
|
|
20186
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20031
20187
|
var percentile3 = (values, percentileValue) => {
|
|
20032
20188
|
if (values.length === 0) {
|
|
20033
20189
|
return;
|
|
@@ -20094,8 +20250,8 @@ await traceStore.append({
|
|
|
20094
20250
|
sessionId,
|
|
20095
20251
|
type: 'client.live_latency'
|
|
20096
20252
|
});`;
|
|
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>${
|
|
20253
|
+
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("");
|
|
20254
|
+
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
20255
|
};
|
|
20100
20256
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
20101
20257
|
const path = options.path ?? "/api/live-latency";
|
|
@@ -20421,7 +20577,7 @@ None.
|
|
|
20421
20577
|
// src/turnQuality.ts
|
|
20422
20578
|
import { Elysia as Elysia36 } from "elysia";
|
|
20423
20579
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
20424
|
-
var
|
|
20580
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20425
20581
|
var getTurnLatencyMs = (turn) => {
|
|
20426
20582
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
20427
20583
|
if (firstTranscriptAt === undefined) {
|
|
@@ -20492,24 +20648,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
20492
20648
|
};
|
|
20493
20649
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
20494
20650
|
const title = options.title ?? "Voice Turn Quality";
|
|
20495
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
20651
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml37(turn.status)}">
|
|
20496
20652
|
<div class="turn-header">
|
|
20497
20653
|
<div>
|
|
20498
|
-
<p class="eyebrow">${
|
|
20499
|
-
<h2>${
|
|
20654
|
+
<p class="eyebrow">${escapeHtml37(turn.sessionId)} \xB7 ${escapeHtml37(turn.turnId)}</p>
|
|
20655
|
+
<h2>${escapeHtml37(turn.text || "Empty turn")}</h2>
|
|
20500
20656
|
</div>
|
|
20501
|
-
<strong>${
|
|
20657
|
+
<strong>${escapeHtml37(turn.status)}</strong>
|
|
20502
20658
|
</div>
|
|
20503
20659
|
<dl>
|
|
20504
|
-
<div><dt>Source</dt><dd>${
|
|
20660
|
+
<div><dt>Source</dt><dd>${escapeHtml37(turn.source ?? "unknown")}</dd></div>
|
|
20505
20661
|
<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 ${
|
|
20662
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml37(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
20663
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml37(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
20508
20664
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
20509
20665
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
20510
20666
|
</dl>
|
|
20511
20667
|
</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>${
|
|
20668
|
+
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
20669
|
};
|
|
20514
20670
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
20515
20671
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -21436,7 +21592,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
21436
21592
|
return parameters;
|
|
21437
21593
|
};
|
|
21438
21594
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21439
|
-
var
|
|
21595
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21440
21596
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
21441
21597
|
if (!webhook?.verificationUrl) {
|
|
21442
21598
|
return;
|
|
@@ -21479,23 +21635,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
21479
21635
|
};
|
|
21480
21636
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21481
21637
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
21482
|
-
<h1>${
|
|
21638
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
21483
21639
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21484
21640
|
<section>
|
|
21485
21641
|
<h2>URLs</h2>
|
|
21486
21642
|
<ul>
|
|
21487
|
-
<li><strong>TwiML:</strong> <code>${
|
|
21488
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21489
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21643
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml38(status.urls.twiml)}</code></li>
|
|
21644
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml38(status.urls.stream)}</code></li>
|
|
21645
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml38(status.urls.webhook)}</code></li>
|
|
21490
21646
|
</ul>
|
|
21491
21647
|
</section>
|
|
21492
21648
|
<section>
|
|
21493
21649
|
<h2>Signing</h2>
|
|
21494
21650
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
21495
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
21651
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml38(status.signing.verificationUrl)}</code></p>` : ""}
|
|
21496
21652
|
</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>${
|
|
21653
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml38(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
21654
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml38(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
21499
21655
|
</main>`;
|
|
21500
21656
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
21501
21657
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -21506,20 +21662,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
21506
21662
|
});
|
|
21507
21663
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21508
21664
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
21509
|
-
<h1>${
|
|
21665
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
21510
21666
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21511
21667
|
<section>
|
|
21512
21668
|
<h2>Checks</h2>
|
|
21513
21669
|
<ul>
|
|
21514
|
-
${report.checks.map((check) => `<li><strong>${
|
|
21670
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml38(check.name)}</strong>: ${escapeHtml38(check.status)}${check.message ? ` - ${escapeHtml38(check.message)}` : ""}</li>`).join("")}
|
|
21515
21671
|
</ul>
|
|
21516
21672
|
</section>
|
|
21517
21673
|
<section>
|
|
21518
21674
|
<h2>Observed URLs</h2>
|
|
21519
21675
|
<ul>
|
|
21520
|
-
<li><strong>TwiML:</strong> <code>${
|
|
21521
|
-
<li><strong>Stream:</strong> <code>${
|
|
21522
|
-
<li><strong>Webhook:</strong> <code>${
|
|
21676
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml38(report.setup.urls.twiml)}</code></li>
|
|
21677
|
+
<li><strong>Stream:</strong> <code>${escapeHtml38(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
21678
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml38(report.setup.urls.webhook)}</code></li>
|
|
21523
21679
|
</ul>
|
|
21524
21680
|
</section>
|
|
21525
21681
|
</main>`;
|
|
@@ -22202,7 +22358,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
22202
22358
|
|
|
22203
22359
|
// src/telephony/plivo.ts
|
|
22204
22360
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22205
|
-
var
|
|
22361
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22206
22362
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22207
22363
|
var resolveRequestOrigin2 = (request) => {
|
|
22208
22364
|
const url = new URL(request.url);
|
|
@@ -22633,21 +22789,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
22633
22789
|
};
|
|
22634
22790
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22635
22791
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
22636
|
-
<h1>${
|
|
22792
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22637
22793
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
22638
22794
|
<ul>
|
|
22639
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
22640
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
22641
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
22795
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml39(status.urls.answer)}</code></li>
|
|
22796
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml39(status.urls.stream)}</code></li>
|
|
22797
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml39(status.urls.webhook)}</code></li>
|
|
22642
22798
|
</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>${
|
|
22799
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml39(name)}</code></li>`).join("")}</ul>` : ""}
|
|
22800
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml39(warning)}</li>`).join("")}</ul>` : ""}
|
|
22645
22801
|
</main>`;
|
|
22646
22802
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22647
22803
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
22648
|
-
<h1>${
|
|
22804
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22649
22805
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
22650
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
22806
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml39(check.name)}</strong>: ${escapeHtml39(check.status)}${check.message ? ` - ${escapeHtml39(check.message)}` : ""}</li>`).join("")}</ul>
|
|
22651
22807
|
</main>`;
|
|
22652
22808
|
var runPlivoSmokeTest = async (input) => {
|
|
22653
22809
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -22851,7 +23007,7 @@ import { Buffer as Buffer6 } from "buffer";
|
|
|
22851
23007
|
import { Database as Database2 } from "bun:sqlite";
|
|
22852
23008
|
import { Elysia as Elysia40 } from "elysia";
|
|
22853
23009
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22854
|
-
var
|
|
23010
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22855
23011
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22856
23012
|
var resolveRequestOrigin3 = (request) => {
|
|
22857
23013
|
const url = new URL(request.url);
|
|
@@ -23245,21 +23401,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
23245
23401
|
};
|
|
23246
23402
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
23247
23403
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
23248
|
-
<h1>${
|
|
23404
|
+
<h1>${escapeHtml40(title)}</h1>
|
|
23249
23405
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
23250
23406
|
<ul>
|
|
23251
|
-
<li><strong>TeXML:</strong> <code>${
|
|
23252
|
-
<li><strong>Media stream:</strong> <code>${
|
|
23253
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
23407
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml40(status.urls.texml)}</code></li>
|
|
23408
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml40(status.urls.stream)}</code></li>
|
|
23409
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml40(status.urls.webhook)}</code></li>
|
|
23254
23410
|
</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>${
|
|
23411
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml40(name)}</code></li>`).join("")}</ul>` : ""}
|
|
23412
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml40(warning)}</li>`).join("")}</ul>` : ""}
|
|
23257
23413
|
</main>`;
|
|
23258
23414
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
23259
23415
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
23260
|
-
<h1>${
|
|
23416
|
+
<h1>${escapeHtml40(title)}</h1>
|
|
23261
23417
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
23262
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
23418
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml40(check.name)}</strong>: ${escapeHtml40(check.status)}${check.message ? ` - ${escapeHtml40(check.message)}` : ""}</li>`).join("")}</ul>
|
|
23263
23419
|
</main>`;
|
|
23264
23420
|
var runTelnyxSmokeTest = async (input) => {
|
|
23265
23421
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -23463,7 +23619,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
23463
23619
|
|
|
23464
23620
|
// src/telephony/matrix.ts
|
|
23465
23621
|
import { Elysia as Elysia41 } from "elysia";
|
|
23466
|
-
var
|
|
23622
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23467
23623
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
23468
23624
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
23469
23625
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -23524,13 +23680,13 @@ var badgeStyles = {
|
|
|
23524
23680
|
};
|
|
23525
23681
|
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
23682
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
23527
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
23683
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml41(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
23528
23684
|
<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
23685
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
23530
23686
|
${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
23687
|
<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]}">${
|
|
23688
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml41(entry.name)}</h2>
|
|
23689
|
+
<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
23690
|
</div>
|
|
23535
23691
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
23536
23692
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -23538,9 +23694,9 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
23538
23694
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
23539
23695
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
23540
23696
|
</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>${
|
|
23697
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml41(entry.setup.urls.stream || "missing")}</code></p>
|
|
23698
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml41(entry.setup.urls.webhook || "missing")}</code></p>
|
|
23699
|
+
${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
23700
|
</article>`).join("")}
|
|
23545
23701
|
</section>
|
|
23546
23702
|
</main>`;
|
|
@@ -23576,7 +23732,7 @@ var defaultRequirements = [
|
|
|
23576
23732
|
"lifecycle-outcome",
|
|
23577
23733
|
"no-session-error"
|
|
23578
23734
|
];
|
|
23579
|
-
var
|
|
23735
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23580
23736
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
23581
23737
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
23582
23738
|
const value = event.payload[key];
|
|
@@ -23685,10 +23841,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
23685
23841
|
});
|
|
23686
23842
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
23687
23843
|
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>${
|
|
23844
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml42(issue.requirement)}</strong>: ${escapeHtml42(issue.message)}</li>`).join("");
|
|
23845
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml42(outcome)}</span>`).join("");
|
|
23846
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml42(requirement)}</span>`).join("");
|
|
23847
|
+
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
23848
|
};
|
|
23693
23849
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
23694
23850
|
query,
|
|
@@ -23754,7 +23910,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
23754
23910
|
"completed",
|
|
23755
23911
|
"failed"
|
|
23756
23912
|
];
|
|
23757
|
-
var
|
|
23913
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23758
23914
|
var loadRouteJson = async (input) => {
|
|
23759
23915
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
23760
23916
|
headers: {
|
|
@@ -23992,10 +24148,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
23992
24148
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
23993
24149
|
const urls = entry?.setup.urls;
|
|
23994
24150
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
23995
|
-
return `<tr><td>${
|
|
24151
|
+
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
24152
|
}).join("");
|
|
23997
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
23998
|
-
const snippet =
|
|
24153
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml43(stage)}</code></li>`).join("");
|
|
24154
|
+
const snippet = escapeHtml43(`const phoneAgent = createVoicePhoneAgent({
|
|
23999
24155
|
carriers: [
|
|
24000
24156
|
{
|
|
24001
24157
|
provider: 'twilio',
|
|
@@ -24029,11 +24185,11 @@ app.use(
|
|
|
24029
24185
|
);`);
|
|
24030
24186
|
const checklist = report.carriers.map((carrier) => {
|
|
24031
24187
|
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>${
|
|
24188
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml43(issue)}</li>`).join("") ?? "";
|
|
24189
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml43(step)}</li>`).join("") ?? "";
|
|
24190
|
+
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
24191
|
}).join("");
|
|
24036
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24192
|
+
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
24193
|
};
|
|
24038
24194
|
var createVoicePhoneAgent = (options) => {
|
|
24039
24195
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -25673,7 +25829,7 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
25673
25829
|
};
|
|
25674
25830
|
// src/providerCapabilities.ts
|
|
25675
25831
|
import { Elysia as Elysia44 } from "elysia";
|
|
25676
|
-
var
|
|
25832
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25677
25833
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
25678
25834
|
configured: true,
|
|
25679
25835
|
features: options.features?.[provider],
|
|
@@ -25736,27 +25892,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
25736
25892
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
25737
25893
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
25738
25894
|
const cards = report.capabilities.map((capability) => {
|
|
25739
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
25740
|
-
return `<article class="card ${
|
|
25895
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml44(feature)}</span>`).join("");
|
|
25896
|
+
return `<article class="card ${escapeHtml44(capability.status)}">
|
|
25741
25897
|
<div class="card-header">
|
|
25742
25898
|
<div>
|
|
25743
|
-
<p class="eyebrow">${
|
|
25744
|
-
<h2>${
|
|
25899
|
+
<p class="eyebrow">${escapeHtml44(capability.kind)}</p>
|
|
25900
|
+
<h2>${escapeHtml44(capability.label ?? capability.provider)}</h2>
|
|
25745
25901
|
</div>
|
|
25746
|
-
<strong>${
|
|
25902
|
+
<strong>${escapeHtml44(capability.status)}</strong>
|
|
25747
25903
|
</div>
|
|
25748
|
-
${capability.description ? `<p>${
|
|
25904
|
+
${capability.description ? `<p>${escapeHtml44(capability.description)}</p>` : ""}
|
|
25749
25905
|
<dl>
|
|
25750
25906
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
25751
25907
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
25752
|
-
<div><dt>Model</dt><dd>${
|
|
25908
|
+
<div><dt>Model</dt><dd>${escapeHtml44(capability.model ?? "default")}</dd></div>
|
|
25753
25909
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
25754
25910
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
25755
25911
|
</dl>
|
|
25756
25912
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
25757
25913
|
</article>`;
|
|
25758
25914
|
}).join("");
|
|
25759
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25915
|
+
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
25916
|
};
|
|
25761
25917
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
25762
25918
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -25795,7 +25951,7 @@ var statusRank4 = {
|
|
|
25795
25951
|
warn: 1,
|
|
25796
25952
|
fail: 2
|
|
25797
25953
|
};
|
|
25798
|
-
var
|
|
25954
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25799
25955
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
25800
25956
|
var uniqueSorted6 = (values) => [
|
|
25801
25957
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -25938,21 +26094,21 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
25938
26094
|
};
|
|
25939
26095
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
25940
26096
|
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">${
|
|
26097
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml45(surface.status)}">
|
|
26098
|
+
<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
26099
|
<dl>
|
|
25944
|
-
<div><dt>Providers</dt><dd>${
|
|
25945
|
-
<div><dt>Fallback</dt><dd>${
|
|
26100
|
+
<div><dt>Providers</dt><dd>${escapeHtml45(surface.providers.join(", ") || "none")}</dd></div>
|
|
26101
|
+
<div><dt>Fallback</dt><dd>${escapeHtml45(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
25946
26102
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
25947
26103
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
25948
26104
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
25949
26105
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
25950
26106
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
25951
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
26107
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml45(surface.fallbackMode || "default")}</dd></div>
|
|
25952
26108
|
</dl>
|
|
25953
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
26109
|
+
${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
26110
|
</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>${
|
|
26111
|
+
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
26112
|
};
|
|
25957
26113
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
25958
26114
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
@@ -26162,7 +26318,7 @@ var statusRank5 = {
|
|
|
26162
26318
|
warn: 1,
|
|
26163
26319
|
fail: 2
|
|
26164
26320
|
};
|
|
26165
|
-
var
|
|
26321
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26166
26322
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
26167
26323
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
26168
26324
|
var uniqueSorted7 = (values) => [
|
|
@@ -26458,11 +26614,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
26458
26614
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
26459
26615
|
const kindCards = providerKinds.map((kind) => {
|
|
26460
26616
|
const kindReport = report.kinds[kind];
|
|
26461
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
26617
|
+
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
26618
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
26463
|
-
return `<article class="${
|
|
26619
|
+
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
26620
|
}).join("");
|
|
26465
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
26621
|
+
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
26622
|
const snippet = `createVoiceProviderSloRoutes({
|
|
26467
26623
|
store: runtimeStorage.traces,
|
|
26468
26624
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -26472,7 +26628,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
26472
26628
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
26473
26629
|
}
|
|
26474
26630
|
})`;
|
|
26475
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26631
|
+
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
26632
|
};
|
|
26477
26633
|
var createVoiceProviderSloRoutes = (options) => {
|
|
26478
26634
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -27312,7 +27468,7 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
27312
27468
|
|
|
27313
27469
|
// src/opsRecovery.ts
|
|
27314
27470
|
import { Elysia as Elysia48 } from "elysia";
|
|
27315
|
-
var
|
|
27471
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27316
27472
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
27317
27473
|
var hrefForSession = (value, sessionId) => {
|
|
27318
27474
|
if (typeof value === "function") {
|
|
@@ -27526,13 +27682,13 @@ ${failedSessions || "None."}
|
|
|
27526
27682
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
27527
27683
|
`;
|
|
27528
27684
|
};
|
|
27529
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
27685
|
+
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
27686
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
27531
27687
|
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>${
|
|
27688
|
+
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("");
|
|
27689
|
+
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("");
|
|
27690
|
+
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("");
|
|
27691
|
+
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
27692
|
};
|
|
27537
27693
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
27538
27694
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
@@ -27579,7 +27735,7 @@ import { Elysia as Elysia50 } from "elysia";
|
|
|
27579
27735
|
|
|
27580
27736
|
// src/traceTimeline.ts
|
|
27581
27737
|
import { Elysia as Elysia49 } from "elysia";
|
|
27582
|
-
var
|
|
27738
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27583
27739
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
27584
27740
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
27585
27741
|
var firstString4 = (payload, keys) => {
|
|
@@ -27762,17 +27918,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
27762
27918
|
};
|
|
27763
27919
|
};
|
|
27764
27920
|
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>${
|
|
27921
|
+
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
27922
|
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>${
|
|
27923
|
+
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("");
|
|
27924
|
+
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>";
|
|
27925
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml48(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
27926
|
+
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
27927
|
};
|
|
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="${
|
|
27928
|
+
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
27929
|
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
27930
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
27775
|
-
const snippet =
|
|
27931
|
+
const snippet = escapeHtml48(`const traceStore = createVoiceTraceSinkStore({
|
|
27776
27932
|
store: runtimeStorage.traces,
|
|
27777
27933
|
sinks: [
|
|
27778
27934
|
createVoiceTraceHTTPSink({
|
|
@@ -27798,7 +27954,7 @@ app.use(
|
|
|
27798
27954
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
27799
27955
|
})
|
|
27800
27956
|
);`);
|
|
27801
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27957
|
+
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
27958
|
};
|
|
27803
27959
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
27804
27960
|
const path = options.path ?? "/api/voice-traces";
|
|
@@ -28434,7 +28590,7 @@ var renderVoiceFailureReplayMarkdown = (report) => {
|
|
|
28434
28590
|
].join(`
|
|
28435
28591
|
`);
|
|
28436
28592
|
};
|
|
28437
|
-
var
|
|
28593
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28438
28594
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
28439
28595
|
var outcomeLabels = (outcome) => [
|
|
28440
28596
|
outcome.complete ? "complete" : undefined,
|
|
@@ -28544,18 +28700,18 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
28544
28700
|
`);
|
|
28545
28701
|
};
|
|
28546
28702
|
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>${
|
|
28703
|
+
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>';
|
|
28704
|
+
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>";
|
|
28705
|
+
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
28706
|
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>${
|
|
28707
|
+
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>";
|
|
28708
|
+
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>";
|
|
28709
|
+
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>";
|
|
28710
|
+
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>";
|
|
28711
|
+
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
28712
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
28557
28713
|
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 ${
|
|
28714
|
+
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
28715
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
28560
28716
|
const telephonyMedia = record.telephonyMedia.events.length ? record.telephonyMedia.events.slice(0, 50).map((event) => {
|
|
28561
28717
|
const details = [
|
|
@@ -28566,9 +28722,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
28566
28722
|
event.sequenceNumber ? `Seq: ${event.sequenceNumber}` : undefined,
|
|
28567
28723
|
`Audio bytes: ${String(event.audioBytes)}`
|
|
28568
28724
|
].filter((detail) => typeof detail === "string");
|
|
28569
|
-
return `<li><strong>${
|
|
28725
|
+
return `<li><strong>${escapeHtml49(event.event)}</strong> <span>${escapeHtml49(new Date(event.at).toLocaleString())}</span><p>${escapeHtml49(details.join(" \xB7 "))}</p></li>`;
|
|
28570
28726
|
}).join("") : "<li>No telephony media trace events recorded.</li>";
|
|
28571
|
-
const snippet =
|
|
28727
|
+
const snippet = escapeHtml49(`app.use(
|
|
28572
28728
|
createVoiceOperationsRecordRoutes({
|
|
28573
28729
|
audit: auditStore,
|
|
28574
28730
|
integrationEvents: opsEvents,
|
|
@@ -28582,9 +28738,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
28582
28738
|
tasks: opsTasks
|
|
28583
28739
|
})
|
|
28584
28740
|
);`);
|
|
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>${
|
|
28741
|
+
const incidentMarkdown = escapeHtml49(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
28742
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml49(options.incidentHref)}">Download incident.md</a>` : "";
|
|
28743
|
+
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
28744
|
};
|
|
28589
28745
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
28590
28746
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -30128,7 +30284,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
30128
30284
|
};
|
|
30129
30285
|
|
|
30130
30286
|
// src/productionReadiness.ts
|
|
30131
|
-
var
|
|
30287
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30132
30288
|
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
30133
30289
|
var readinessGateCodes = {
|
|
30134
30290
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -31766,25 +31922,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
31766
31922
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
31767
31923
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
31768
31924
|
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>${
|
|
31925
|
+
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>` : "";
|
|
31926
|
+
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
31927
|
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 ${
|
|
31928
|
+
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("");
|
|
31929
|
+
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>` : "";
|
|
31930
|
+
return `<article class="check ${escapeHtml50(check.status)}">
|
|
31775
31931
|
<div>
|
|
31776
|
-
<span>${
|
|
31777
|
-
<h2>${
|
|
31778
|
-
${check.detail ? `<p>${
|
|
31932
|
+
<span>${escapeHtml50(check.status.toUpperCase())}</span>
|
|
31933
|
+
<h2>${escapeHtml50(check.label)}</h2>
|
|
31934
|
+
${check.detail ? `<p>${escapeHtml50(check.detail)}</p>` : ""}
|
|
31779
31935
|
${explanation}
|
|
31780
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
31936
|
+
${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
31937
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
31782
31938
|
</div>
|
|
31783
|
-
<strong>${
|
|
31784
|
-
${check.href ? `<a href="${
|
|
31939
|
+
<strong>${escapeHtml50(String(check.value ?? check.status))}</strong>
|
|
31940
|
+
${check.href ? `<a href="${escapeHtml50(check.href)}">Open surface</a>` : ""}
|
|
31785
31941
|
</article>`;
|
|
31786
31942
|
}).join("");
|
|
31787
|
-
const snippet =
|
|
31943
|
+
const snippet = escapeHtml50(`createVoiceProductionReadinessRoutes({
|
|
31788
31944
|
htmlPath: '/production-readiness',
|
|
31789
31945
|
path: '/api/production-readiness',
|
|
31790
31946
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -31800,7 +31956,7 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
31800
31956
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
31801
31957
|
store: traceStore
|
|
31802
31958
|
});`);
|
|
31803
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31959
|
+
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
31960
|
};
|
|
31805
31961
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
31806
31962
|
const path = options.path ?? "/api/production-readiness";
|
|
@@ -31855,7 +32011,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
31855
32011
|
};
|
|
31856
32012
|
// src/voiceMonitoring.ts
|
|
31857
32013
|
import { Elysia as Elysia53 } from "elysia";
|
|
31858
|
-
var
|
|
32014
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31859
32015
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
31860
32016
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
31861
32017
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -32108,14 +32264,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
32108
32264
|
};
|
|
32109
32265
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
32110
32266
|
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 =
|
|
32267
|
+
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("");
|
|
32268
|
+
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("");
|
|
32269
|
+
const snippet = escapeHtml51(`app.use(createVoiceMonitorRoutes({
|
|
32114
32270
|
evidence,
|
|
32115
32271
|
issueStore,
|
|
32116
32272
|
monitors: [defineVoiceMonitor(...)]
|
|
32117
32273
|
}));`);
|
|
32118
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32274
|
+
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
32275
|
};
|
|
32120
32276
|
var actorFromRequest = async (request) => {
|
|
32121
32277
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -32563,7 +32719,7 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
32563
32719
|
};
|
|
32564
32720
|
// src/providerStackRecommendations.ts
|
|
32565
32721
|
import { Elysia as Elysia54 } from "elysia";
|
|
32566
|
-
var
|
|
32722
|
+
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32567
32723
|
var profileProviderPriorities = {
|
|
32568
32724
|
"meeting-recorder": {
|
|
32569
32725
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -32882,17 +33038,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
32882
33038
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
32883
33039
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
32884
33040
|
const rows = report.rows.map((row) => {
|
|
32885
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
32886
|
-
return `<article class="row ${
|
|
33041
|
+
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("");
|
|
33042
|
+
return `<article class="row ${escapeHtml52(row.status)}">
|
|
32887
33043
|
<div>
|
|
32888
|
-
<p class="eyebrow">${
|
|
32889
|
-
<h2>${
|
|
32890
|
-
<p class="status ${
|
|
33044
|
+
<p class="eyebrow">${escapeHtml52(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
33045
|
+
<h2>${escapeHtml52(row.provider)}</h2>
|
|
33046
|
+
<p class="status ${escapeHtml52(row.status)}">${escapeHtml52(row.status.toUpperCase())}</p>
|
|
32891
33047
|
</div>
|
|
32892
33048
|
<ul>${checks}</ul>
|
|
32893
33049
|
</article>`;
|
|
32894
33050
|
}).join("");
|
|
32895
|
-
const snippet =
|
|
33051
|
+
const snippet = escapeHtml52(`const providerContracts = () =>
|
|
32896
33052
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
32897
33053
|
env: process.env,
|
|
32898
33054
|
providers: {
|
|
@@ -32913,7 +33069,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
32913
33069
|
providerContractMatrix: () =>
|
|
32914
33070
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
32915
33071
|
});`);
|
|
32916
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33072
|
+
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
33073
|
};
|
|
32918
33074
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
32919
33075
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -33081,7 +33237,7 @@ var DEFAULT_LINKS = [
|
|
|
33081
33237
|
label: "Handoffs"
|
|
33082
33238
|
}
|
|
33083
33239
|
];
|
|
33084
|
-
var
|
|
33240
|
+
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33085
33241
|
var countProviderStatuses = (providers) => {
|
|
33086
33242
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
33087
33243
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -33150,16 +33306,16 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
33150
33306
|
trace
|
|
33151
33307
|
};
|
|
33152
33308
|
};
|
|
33153
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
33309
|
+
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
33310
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
33155
33311
|
const links = report.links.map((link) => `<article class="surface">
|
|
33156
|
-
<div><h2>${
|
|
33157
|
-
<p><a href="${
|
|
33312
|
+
<div><h2>${escapeHtml53(link.label)}</h2>${link.description ? `<p>${escapeHtml53(link.description)}</p>` : ""}</div>
|
|
33313
|
+
<p><a href="${escapeHtml53(link.href)}">Open ${escapeHtml53(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml53(link.statusHref)}">Status</a>` : ""}</p>
|
|
33158
33314
|
</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>${
|
|
33315
|
+
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>';
|
|
33316
|
+
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
33317
|
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>${
|
|
33318
|
+
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
33319
|
};
|
|
33164
33320
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
33165
33321
|
const path = options.path ?? "/ops-console";
|
|
@@ -33583,14 +33739,14 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
33583
33739
|
};
|
|
33584
33740
|
// src/opsStatusRoutes.ts
|
|
33585
33741
|
import { Elysia as Elysia57 } from "elysia";
|
|
33586
|
-
var
|
|
33742
|
+
var escapeHtml54 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33587
33743
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
33588
33744
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
33589
33745
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
33590
33746
|
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 ${
|
|
33747
|
+
return `<article class="surface ${escapeHtml54(surface.status)}"><span>${escapeHtml54(surface.status.toUpperCase())}</span><h2>${escapeHtml54(key)}</h2><strong>${escapeHtml54(value)}</strong></article>`;
|
|
33592
33748
|
}).join("");
|
|
33593
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33749
|
+
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
33750
|
};
|
|
33595
33751
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
33596
33752
|
const path = options.path ?? "/api/voice/ops-status";
|
|
@@ -34028,7 +34184,7 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
34028
34184
|
};
|
|
34029
34185
|
// src/traceDeliveryRoutes.ts
|
|
34030
34186
|
import { Elysia as Elysia58 } from "elysia";
|
|
34031
|
-
var
|
|
34187
|
+
var escapeHtml55 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34032
34188
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
34033
34189
|
var getNumber12 = (value) => {
|
|
34034
34190
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -34109,14 +34265,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
34109
34265
|
if (entries.length === 0) {
|
|
34110
34266
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
34111
34267
|
}
|
|
34112
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
34268
|
+
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
34269
|
};
|
|
34114
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
34270
|
+
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
34271
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
34116
34272
|
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>${
|
|
34273
|
+
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>`;
|
|
34274
|
+
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("");
|
|
34275
|
+
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
34276
|
};
|
|
34121
34277
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
34122
34278
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -36228,6 +36384,8 @@ export {
|
|
|
36228
36384
|
renderVoiceProviderDecisionTraceHTML,
|
|
36229
36385
|
renderVoiceProviderContractMatrixHTML,
|
|
36230
36386
|
renderVoiceProviderCapabilityHTML,
|
|
36387
|
+
renderVoiceProofTrendRecommendationMarkdown,
|
|
36388
|
+
renderVoiceProofTrendRecommendationHTML,
|
|
36231
36389
|
renderVoiceProductionReadinessHTML,
|
|
36232
36390
|
renderVoicePostCallAnalysisMarkdown,
|
|
36233
36391
|
renderVoicePhoneAgentProductionSmokeHTML,
|
|
@@ -36475,6 +36633,7 @@ export {
|
|
|
36475
36633
|
createVoiceProviderCapabilityJSONHandler,
|
|
36476
36634
|
createVoiceProviderCapabilityHTMLHandler,
|
|
36477
36635
|
createVoiceProofTrendRoutes,
|
|
36636
|
+
createVoiceProofTrendRecommendationRoutes,
|
|
36478
36637
|
createVoiceProductionReadinessRoutes,
|
|
36479
36638
|
createVoicePostgresTraceSinkDeliveryStore,
|
|
36480
36639
|
createVoicePostgresTraceEventStore,
|
|
@@ -36669,6 +36828,7 @@ export {
|
|
|
36669
36828
|
buildVoiceProviderDecisionTraceReport,
|
|
36670
36829
|
buildVoiceProviderContractMatrix,
|
|
36671
36830
|
buildVoiceProofTrendReport,
|
|
36831
|
+
buildVoiceProofTrendRecommendationReport,
|
|
36672
36832
|
buildVoiceProductionReadinessReport,
|
|
36673
36833
|
buildVoiceProductionReadinessGate,
|
|
36674
36834
|
buildVoicePostCallAnalysisReport,
|