@absolutejs/voice 0.0.22-beta.286 → 0.0.22-beta.288
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/index.d.ts +2 -2
- package/dist/index.js +406 -264
- package/dist/sloCalibration.d.ts +61 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12790,7 +12790,76 @@ var createVoiceSloThresholdProfile = (input, options = {}) => {
|
|
|
12790
12790
|
status: report.status
|
|
12791
12791
|
};
|
|
12792
12792
|
};
|
|
12793
|
+
var createVoiceSloReadinessThresholdOptions = (input, options = {}) => {
|
|
12794
|
+
const profile = "providerSlo" in input ? input : createVoiceSloThresholdProfile(input, options);
|
|
12795
|
+
return {
|
|
12796
|
+
liveLatencyFailAfterMs: profile.liveLatency.failAfterMs,
|
|
12797
|
+
liveLatencyWarnAfterMs: profile.liveLatency.warnAfterMs,
|
|
12798
|
+
monitoringNotifierDeliveryFailAfterMs: profile.monitoring.notifierDeliveryFailAfterMs,
|
|
12799
|
+
monitoringRunFailAfterMs: profile.monitoring.monitorRunFailAfterMs,
|
|
12800
|
+
reconnectResumeFailAfterMs: profile.reconnect.failAfterMs
|
|
12801
|
+
};
|
|
12802
|
+
};
|
|
12803
|
+
var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
12804
|
+
const report = Array.isArray(input) ? buildVoiceSloCalibrationReport(input, options) : ("thresholds" in input) ? input : undefined;
|
|
12805
|
+
const profile = report === undefined ? input : createVoiceSloThresholdProfile(report, options);
|
|
12806
|
+
return {
|
|
12807
|
+
bargeIn: profile.bargeIn,
|
|
12808
|
+
generatedAt: new Date().toISOString(),
|
|
12809
|
+
issues: profile.issues,
|
|
12810
|
+
liveLatencyMaxAgeMs: options.liveLatencyMaxAgeMs,
|
|
12811
|
+
ok: profile.status !== "fail",
|
|
12812
|
+
providerSlo: profile.providerSlo,
|
|
12813
|
+
readinessOptions: createVoiceSloReadinessThresholdOptions(profile),
|
|
12814
|
+
sources: report?.sources ?? [],
|
|
12815
|
+
status: profile.status
|
|
12816
|
+
};
|
|
12817
|
+
};
|
|
12793
12818
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
12819
|
+
var escapeHtml16 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12820
|
+
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
12821
|
+
var readinessThresholdRows = (report) => [
|
|
12822
|
+
{
|
|
12823
|
+
control: "Provider SLO p95",
|
|
12824
|
+
value: report.providerSlo.llm?.maxP95ElapsedMs,
|
|
12825
|
+
usedBy: "Provider SLO gates for STT, LLM, and TTS"
|
|
12826
|
+
},
|
|
12827
|
+
{
|
|
12828
|
+
control: "Live latency warn",
|
|
12829
|
+
value: report.readinessOptions.liveLatencyWarnAfterMs,
|
|
12830
|
+
usedBy: "Production readiness live latency warning gate"
|
|
12831
|
+
},
|
|
12832
|
+
{
|
|
12833
|
+
control: "Live latency fail",
|
|
12834
|
+
value: report.readinessOptions.liveLatencyFailAfterMs,
|
|
12835
|
+
usedBy: "Production readiness live latency fail gate"
|
|
12836
|
+
},
|
|
12837
|
+
{
|
|
12838
|
+
control: "Live latency freshness",
|
|
12839
|
+
value: report.liveLatencyMaxAgeMs,
|
|
12840
|
+
usedBy: "Maximum age for latency evidence before readiness ignores it"
|
|
12841
|
+
},
|
|
12842
|
+
{
|
|
12843
|
+
control: "Barge-in interruption",
|
|
12844
|
+
value: report.bargeIn.thresholdMs,
|
|
12845
|
+
usedBy: "Runtime interruption classification threshold"
|
|
12846
|
+
},
|
|
12847
|
+
{
|
|
12848
|
+
control: "Reconnect resume p95",
|
|
12849
|
+
value: report.readinessOptions.reconnectResumeFailAfterMs,
|
|
12850
|
+
usedBy: "Production readiness reconnect-resume gate"
|
|
12851
|
+
},
|
|
12852
|
+
{
|
|
12853
|
+
control: "Monitor run elapsed",
|
|
12854
|
+
value: report.readinessOptions.monitoringRunFailAfterMs,
|
|
12855
|
+
usedBy: "Production readiness monitoring run gate"
|
|
12856
|
+
},
|
|
12857
|
+
{
|
|
12858
|
+
control: "Notifier delivery elapsed",
|
|
12859
|
+
value: report.readinessOptions.monitoringNotifierDeliveryFailAfterMs,
|
|
12860
|
+
usedBy: "Production readiness notifier delivery gate"
|
|
12861
|
+
}
|
|
12862
|
+
];
|
|
12794
12863
|
var renderVoiceSloCalibrationMarkdown = (report, options = {}) => {
|
|
12795
12864
|
const rows = Object.values(report.thresholds).map((threshold) => `| ${escapeMarkdown(threshold.metric)} | ${threshold.status} | ${threshold.samples} | ${threshold.baselineP95Ms ?? "n/a"} | ${threshold.warnAfterMs ?? "n/a"} | ${threshold.failAfterMs ?? "n/a"} |`).join(`
|
|
12796
12865
|
`);
|
|
@@ -12812,6 +12881,37 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
12812
12881
|
`) || "- None"}
|
|
12813
12882
|
`;
|
|
12814
12883
|
};
|
|
12884
|
+
var renderVoiceSloReadinessThresholdMarkdown = (report, options = {}) => {
|
|
12885
|
+
const rows = readinessThresholdRows(report).map((row) => `| ${escapeMarkdown(row.control)} | ${formatMs(row.value)} | ${escapeMarkdown(row.usedBy)} |`).join(`
|
|
12886
|
+
`);
|
|
12887
|
+
return `# ${options.title ?? "Calibration -> Active Readiness Gate"}
|
|
12888
|
+
|
|
12889
|
+
Generated: ${report.generatedAt}
|
|
12890
|
+
|
|
12891
|
+
Status: **${report.status}**
|
|
12892
|
+
|
|
12893
|
+
| Threshold | Active value | Used by |
|
|
12894
|
+
| --- | ---: | --- |
|
|
12895
|
+
${rows}
|
|
12896
|
+
|
|
12897
|
+
Sources:
|
|
12898
|
+
|
|
12899
|
+
${report.sources.map((source) => `- ${source}`).join(`
|
|
12900
|
+
`) || "- n/a"}
|
|
12901
|
+
|
|
12902
|
+
Issues:
|
|
12903
|
+
|
|
12904
|
+
${report.issues.map((issue) => `- ${issue}`).join(`
|
|
12905
|
+
`) || "- None"}
|
|
12906
|
+
`;
|
|
12907
|
+
};
|
|
12908
|
+
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
12909
|
+
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
12910
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml16(row.control)}</td><td>${escapeHtml16(formatMs(row.value))}</td><td>${escapeHtml16(row.usedBy)}</td></tr>`).join("");
|
|
12911
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml16(issue)}</li>`).join("");
|
|
12912
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml16(source)}</code></li>`).join("");
|
|
12913
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml16(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>${escapeHtml16(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">${escapeHtml16(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml16(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml16(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml16(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>`;
|
|
12914
|
+
};
|
|
12815
12915
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
12816
12916
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
12817
12917
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
@@ -12835,6 +12935,43 @@ var createVoiceSloCalibrationRoutes = (options) => {
|
|
|
12835
12935
|
}
|
|
12836
12936
|
return routes;
|
|
12837
12937
|
};
|
|
12938
|
+
var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
12939
|
+
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
12940
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
12941
|
+
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
12942
|
+
const routes = new Elysia15({
|
|
12943
|
+
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
12944
|
+
});
|
|
12945
|
+
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
12946
|
+
routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
|
|
12947
|
+
if (htmlPath !== false) {
|
|
12948
|
+
routes.get(htmlPath, async () => {
|
|
12949
|
+
const report = await loadReport();
|
|
12950
|
+
return new Response(renderVoiceSloReadinessThresholdHTML(report, {
|
|
12951
|
+
title: options.title
|
|
12952
|
+
}), {
|
|
12953
|
+
headers: {
|
|
12954
|
+
"content-type": "text/html; charset=utf-8",
|
|
12955
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
12956
|
+
}
|
|
12957
|
+
});
|
|
12958
|
+
});
|
|
12959
|
+
}
|
|
12960
|
+
if (markdownPath !== false) {
|
|
12961
|
+
routes.get(markdownPath, async () => {
|
|
12962
|
+
const report = await loadReport();
|
|
12963
|
+
return new Response(renderVoiceSloReadinessThresholdMarkdown(report, {
|
|
12964
|
+
title: options.title
|
|
12965
|
+
}), {
|
|
12966
|
+
headers: {
|
|
12967
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
12968
|
+
...Object.fromEntries(new Headers(options.headers))
|
|
12969
|
+
}
|
|
12970
|
+
});
|
|
12971
|
+
});
|
|
12972
|
+
}
|
|
12973
|
+
return routes;
|
|
12974
|
+
};
|
|
12838
12975
|
// src/liveOps.ts
|
|
12839
12976
|
import { Elysia as Elysia16 } from "elysia";
|
|
12840
12977
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
@@ -13171,12 +13308,12 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
13171
13308
|
import { Elysia as Elysia17 } from "elysia";
|
|
13172
13309
|
import { mkdir } from "fs/promises";
|
|
13173
13310
|
import { dirname, join } from "path";
|
|
13174
|
-
var
|
|
13311
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13175
13312
|
var renderSummaryCard = (label, summary) => {
|
|
13176
13313
|
if (!summary) {
|
|
13177
|
-
return `<article><span>${
|
|
13314
|
+
return `<article><span>${escapeHtml17(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
13178
13315
|
}
|
|
13179
|
-
return `<article><span>${
|
|
13316
|
+
return `<article><span>${escapeHtml17(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>`;
|
|
13180
13317
|
};
|
|
13181
13318
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
13182
13319
|
audit: leases,
|
|
@@ -13387,9 +13524,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
13387
13524
|
});
|
|
13388
13525
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
13389
13526
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
13390
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
13391
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
13392
|
-
const snippet =
|
|
13527
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml17(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
13528
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml17(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
13529
|
+
const snippet = escapeHtml17(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
13393
13530
|
createVoiceDeliveryRuntimePresetConfig({
|
|
13394
13531
|
audit: {
|
|
13395
13532
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -13415,7 +13552,7 @@ app.use(
|
|
|
13415
13552
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
13416
13553
|
})
|
|
13417
13554
|
);`);
|
|
13418
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13555
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(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>${escapeHtml17(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 ${escapeHtml17(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>`;
|
|
13419
13556
|
};
|
|
13420
13557
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
13421
13558
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
@@ -13697,7 +13834,7 @@ var parseRetentionScopes = (value) => {
|
|
|
13697
13834
|
const allowed = new Set(allRetentionScopes);
|
|
13698
13835
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
13699
13836
|
};
|
|
13700
|
-
var
|
|
13837
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13701
13838
|
var buildStorageSurfaces = (options) => [
|
|
13702
13839
|
{
|
|
13703
13840
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -13934,12 +14071,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
13934
14071
|
zeroRetentionAvailable: true
|
|
13935
14072
|
};
|
|
13936
14073
|
};
|
|
13937
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
14074
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml18(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml18(scope.skippedReason ?? "")}</td><td><code>${escapeHtml18(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
13938
14075
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
13939
14076
|
const title = options.title ?? "Voice Data Control";
|
|
13940
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
13941
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
13942
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
14077
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml18(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml18(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
14078
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml18(key.name)}</td><td><code>${escapeHtml18(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml18(key.recommendation)}</td></tr>`).join("");
|
|
14079
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml18(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>${escapeHtml18(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>`;
|
|
13943
14080
|
};
|
|
13944
14081
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
13945
14082
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -14082,7 +14219,7 @@ import { Elysia as Elysia20 } from "elysia";
|
|
|
14082
14219
|
|
|
14083
14220
|
// src/handoffHealth.ts
|
|
14084
14221
|
import { Elysia as Elysia19 } from "elysia";
|
|
14085
|
-
var
|
|
14222
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14086
14223
|
var getString7 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
14087
14224
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
14088
14225
|
var increment3 = (record, key) => {
|
|
@@ -14200,10 +14337,10 @@ var renderActionSummary = (summary) => {
|
|
|
14200
14337
|
return [
|
|
14201
14338
|
'<section class="voice-handoff-health-columns">',
|
|
14202
14339
|
"<article><h3>Actions</h3>",
|
|
14203
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
14340
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml19(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
14204
14341
|
"</article>",
|
|
14205
14342
|
"<article><h3>Adapters</h3>",
|
|
14206
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
14343
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml19(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
14207
14344
|
"</article>",
|
|
14208
14345
|
"</section>"
|
|
14209
14346
|
].join("");
|
|
@@ -14217,22 +14354,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
14217
14354
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
14218
14355
|
'<div class="voice-handoff-health-events">',
|
|
14219
14356
|
...summary.events.map((event) => [
|
|
14220
|
-
`<article class="${
|
|
14357
|
+
`<article class="${escapeHtml19(event.status)}">`,
|
|
14221
14358
|
'<div class="voice-handoff-health-event-header">',
|
|
14222
|
-
`<strong>${
|
|
14223
|
-
`<span>${
|
|
14359
|
+
`<strong>${escapeHtml19(event.action ?? "handoff")}</strong>`,
|
|
14360
|
+
`<span>${escapeHtml19(event.status)}</span>`,
|
|
14224
14361
|
"</div>",
|
|
14225
|
-
`<p><small>${
|
|
14226
|
-
event.target ? `<p>Target: ${
|
|
14227
|
-
event.reason ? `<p>Reason: ${
|
|
14362
|
+
`<p><small>${escapeHtml19(event.sessionId)}</small></p>`,
|
|
14363
|
+
event.target ? `<p>Target: ${escapeHtml19(event.target)}</p>` : "",
|
|
14364
|
+
event.reason ? `<p>Reason: ${escapeHtml19(event.reason)}</p>` : "",
|
|
14228
14365
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
14229
14366
|
"<li>",
|
|
14230
|
-
`${
|
|
14231
|
-
delivery.deliveredTo ? ` to ${
|
|
14232
|
-
delivery.error ? ` (${
|
|
14367
|
+
`${escapeHtml19(delivery.adapterId)}: ${escapeHtml19(delivery.status)}`,
|
|
14368
|
+
delivery.deliveredTo ? ` to ${escapeHtml19(delivery.deliveredTo)}` : "",
|
|
14369
|
+
delivery.error ? ` (${escapeHtml19(delivery.error)})` : "",
|
|
14233
14370
|
"</li>"
|
|
14234
14371
|
].join("")).join("")}</ul>` : "",
|
|
14235
|
-
event.replayHref ? `<p><a href="${
|
|
14372
|
+
event.replayHref ? `<p><a href="${escapeHtml19(event.replayHref)}">Open replay</a></p>` : "",
|
|
14236
14373
|
"</article>"
|
|
14237
14374
|
].join("")),
|
|
14238
14375
|
"</div>"
|
|
@@ -14385,12 +14522,12 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
14385
14522
|
thresholds
|
|
14386
14523
|
};
|
|
14387
14524
|
};
|
|
14388
|
-
var
|
|
14525
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14389
14526
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
14390
14527
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
14391
14528
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
14392
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
14393
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
14529
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml20(metric.label)}</td><td>${escapeHtml20(formatMetricValue(metric))}</td><td>${escapeHtml20(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml20(key)}</code></td></tr>`).join("");
|
|
14530
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml20(link.href)}">${escapeHtml20(link.label)}</a>`).join("")}</nav>` : "";
|
|
14394
14531
|
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>`;
|
|
14395
14532
|
};
|
|
14396
14533
|
var createVoiceQualityRoutes = (options) => {
|
|
@@ -14424,7 +14561,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
14424
14561
|
};
|
|
14425
14562
|
|
|
14426
14563
|
// src/evalRoutes.ts
|
|
14427
|
-
var
|
|
14564
|
+
var escapeHtml21 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14428
14565
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
14429
14566
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
14430
14567
|
var getString9 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -14746,7 +14883,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
14746
14883
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
14747
14884
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
14748
14885
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
14749
|
-
const snippet =
|
|
14886
|
+
const snippet = escapeHtml21(`app.use(
|
|
14750
14887
|
createVoiceEvalRoutes({
|
|
14751
14888
|
path: '/evals',
|
|
14752
14889
|
store: traceStore,
|
|
@@ -14767,44 +14904,44 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
14767
14904
|
};
|
|
14768
14905
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
14769
14906
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
14770
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
14771
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
14907
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml21(link.href)}">${escapeHtml21(link.label)}</a>`).join("")}</nav>` : "";
|
|
14908
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml21(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>';
|
|
14772
14909
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
14773
14910
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
14774
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
14775
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
14911
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml21(session.operationsRecordHref)}">${escapeHtml21(session.sessionId)}</a>` : escapeHtml21(session.sessionId);
|
|
14912
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml21(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml21(formatTime(session.endedAt))}</td><td>${escapeHtml21(failedMetrics || "none")}</td></tr>`;
|
|
14776
14913
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
14777
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14914
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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>${escapeHtml21(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>`;
|
|
14778
14915
|
};
|
|
14779
14916
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
14780
14917
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
14781
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
14782
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
14783
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
14784
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
14785
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14918
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml21(link.href)}">${escapeHtml21(link.label)}</a>`).join("")}</nav>` : "";
|
|
14919
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml21(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
14920
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml21(id)}</li>`).join("") : "<li>none</li>";
|
|
14921
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml21(id)}</li>`).join("") : "<li>none</li>";
|
|
14922
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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>${escapeHtml21(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml21(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml21(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>${escapeHtml21(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>`;
|
|
14786
14923
|
};
|
|
14787
14924
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
14788
14925
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
14789
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
14926
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml21(link.href)}">${escapeHtml21(link.label)}</a>`).join("")}</nav>` : "";
|
|
14790
14927
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
14791
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
14928
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml21(issue)}</li>`).join("")}</ul>` : "";
|
|
14792
14929
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
14793
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
14794
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
14930
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml21(session.operationsRecordHref)}">${escapeHtml21(session.sessionId)}</a>` : escapeHtml21(session.sessionId);
|
|
14931
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml21(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml21(session.issues.join(", ") || "none")}</td></tr>`;
|
|
14795
14932
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
14796
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
14933
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml21(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml21(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>`;
|
|
14797
14934
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
14798
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14935
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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>${escapeHtml21(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>`;
|
|
14799
14936
|
};
|
|
14800
14937
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
14801
14938
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
14802
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
14939
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml21(link.href)}">${escapeHtml21(link.label)}</a>`).join("")}</nav>` : "";
|
|
14803
14940
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
14804
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
14805
|
-
return `<section class="${fixture.status}"><h2>${
|
|
14941
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml21(scenario.label)}</td><td>${escapeHtml21(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml21([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
14942
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml21(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml21(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>`;
|
|
14806
14943
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
14807
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14944
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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>${escapeHtml21(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>`;
|
|
14808
14945
|
};
|
|
14809
14946
|
var createVoiceEvalRoutes = (options) => {
|
|
14810
14947
|
const path = options.path ?? "/evals";
|
|
@@ -14949,7 +15086,7 @@ import { Elysia as Elysia24 } from "elysia";
|
|
|
14949
15086
|
|
|
14950
15087
|
// src/outcomeContract.ts
|
|
14951
15088
|
import { Elysia as Elysia22 } from "elysia";
|
|
14952
|
-
var
|
|
15089
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14953
15090
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
14954
15091
|
if (value === false) {
|
|
14955
15092
|
return;
|
|
@@ -15160,13 +15297,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
15160
15297
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
15161
15298
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
15162
15299
|
const contracts = report.contracts.map((contract) => {
|
|
15163
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
15300
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml22(href)}">${escapeHtml22(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
15164
15301
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
15165
15302
|
<div class="contract-header">
|
|
15166
15303
|
<div>
|
|
15167
|
-
<p class="eyebrow">${
|
|
15168
|
-
<h2>${
|
|
15169
|
-
${contract.description ? `<p>${
|
|
15304
|
+
<p class="eyebrow">${escapeHtml22(contract.contractId)}</p>
|
|
15305
|
+
<h2>${escapeHtml22(contract.label ?? contract.contractId)}</h2>
|
|
15306
|
+
${contract.description ? `<p>${escapeHtml22(contract.description)}</p>` : ""}
|
|
15170
15307
|
${sessionLinks}
|
|
15171
15308
|
</div>
|
|
15172
15309
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -15178,10 +15315,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
15178
15315
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
15179
15316
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
15180
15317
|
</div>
|
|
15181
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
15318
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml22(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
15182
15319
|
</section>`;
|
|
15183
15320
|
}).join("");
|
|
15184
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15321
|
+
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:#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>${escapeHtml22(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>`;
|
|
15185
15322
|
};
|
|
15186
15323
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
15187
15324
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -15416,7 +15553,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
15416
15553
|
});
|
|
15417
15554
|
var defaultApi = {};
|
|
15418
15555
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
15419
|
-
var
|
|
15556
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15420
15557
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
15421
15558
|
if (value === false) {
|
|
15422
15559
|
return;
|
|
@@ -15665,7 +15802,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
15665
15802
|
};
|
|
15666
15803
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
15667
15804
|
const title = options.title ?? "Voice Tool Contracts";
|
|
15668
|
-
const snippet =
|
|
15805
|
+
const snippet = escapeHtml23(`app.use(
|
|
15669
15806
|
createVoiceToolContractRoutes({
|
|
15670
15807
|
htmlPath: '/tool-contracts',
|
|
15671
15808
|
path: '/api/tool-contracts',
|
|
@@ -15691,20 +15828,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
15691
15828
|
);`);
|
|
15692
15829
|
const contracts = report.contracts.map((contract) => {
|
|
15693
15830
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
15694
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
15831
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml23(testCase.operationsRecordHref)}">${escapeHtml23(testCase.label ?? testCase.caseId)}</a>` : escapeHtml23(testCase.label ?? testCase.caseId)}</td>
|
|
15695
15832
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
15696
|
-
<td>${
|
|
15697
|
-
<td>${
|
|
15833
|
+
<td>${escapeHtml23(testCase.status)}</td>
|
|
15834
|
+
<td>${escapeHtml23(testCase.sessionId)}</td>
|
|
15698
15835
|
<td>${String(testCase.attempts)}</td>
|
|
15699
15836
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
15700
15837
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
15701
|
-
<td>${
|
|
15838
|
+
<td>${escapeHtml23(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
15702
15839
|
</tr>`).join("");
|
|
15703
15840
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
15704
15841
|
<div class="contract-header">
|
|
15705
15842
|
<div>
|
|
15706
|
-
<p class="eyebrow">${
|
|
15707
|
-
<h2>${
|
|
15843
|
+
<p class="eyebrow">${escapeHtml23(contract.toolName)}</p>
|
|
15844
|
+
<h2>${escapeHtml23(contract.label ?? contract.contractId)}</h2>
|
|
15708
15845
|
</div>
|
|
15709
15846
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
15710
15847
|
</div>
|
|
@@ -15714,7 +15851,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
15714
15851
|
</table>
|
|
15715
15852
|
</section>`;
|
|
15716
15853
|
}).join("");
|
|
15717
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15854
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml23(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>${escapeHtml23(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml23(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>`;
|
|
15718
15855
|
};
|
|
15719
15856
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
15720
15857
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -15741,7 +15878,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
15741
15878
|
};
|
|
15742
15879
|
|
|
15743
15880
|
// src/simulationSuite.ts
|
|
15744
|
-
var
|
|
15881
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15745
15882
|
var summarizeSection = (report) => ({
|
|
15746
15883
|
failed: report.failed,
|
|
15747
15884
|
passed: report.passed,
|
|
@@ -15937,15 +16074,15 @@ var renderSection = (label, summary) => {
|
|
|
15937
16074
|
if (!summary) {
|
|
15938
16075
|
return "";
|
|
15939
16076
|
}
|
|
15940
|
-
return `<article class="${
|
|
16077
|
+
return `<article class="${escapeHtml24(summary.status)}"><span>${escapeHtml24(label)}</span><strong>${escapeHtml24(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
15941
16078
|
};
|
|
15942
16079
|
var renderAction = (action) => {
|
|
15943
|
-
const content = `<strong>${
|
|
15944
|
-
return action.href ? `<a class="action" href="${
|
|
16080
|
+
const content = `<strong>${escapeHtml24(action.label)}</strong><p>${escapeHtml24(action.description)}</p><span>${escapeHtml24(action.section)} / ${escapeHtml24(action.severity)}</span>`;
|
|
16081
|
+
return action.href ? `<a class="action" href="${escapeHtml24(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
15945
16082
|
};
|
|
15946
16083
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
15947
16084
|
const title = options.title ?? "Voice Simulation Suite";
|
|
15948
|
-
const snippet =
|
|
16085
|
+
const snippet = escapeHtml24(`app.use(
|
|
15949
16086
|
createVoiceSimulationSuiteRoutes({
|
|
15950
16087
|
htmlPath: '/voice/simulations',
|
|
15951
16088
|
path: '/api/voice/simulations',
|
|
@@ -15978,7 +16115,7 @@ app.use(
|
|
|
15978
16115
|
store: traceStore
|
|
15979
16116
|
})
|
|
15980
16117
|
);`);
|
|
15981
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16118
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(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>${escapeHtml24(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml24(report.status)}">Status: ${escapeHtml24(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>${escapeHtml24(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
15982
16119
|
};
|
|
15983
16120
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
15984
16121
|
const path = options.path ?? "/api/voice/simulations";
|
|
@@ -16297,7 +16434,7 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
16297
16434
|
// src/sessionReplay.ts
|
|
16298
16435
|
import { Elysia as Elysia25 } from "elysia";
|
|
16299
16436
|
var getString10 = (value) => typeof value === "string" ? value : undefined;
|
|
16300
|
-
var
|
|
16437
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16301
16438
|
var increment4 = (record, key) => {
|
|
16302
16439
|
record[key] = (record[key] ?? 0) + 1;
|
|
16303
16440
|
};
|
|
@@ -16491,10 +16628,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
16491
16628
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
16492
16629
|
'<div class="voice-sessions-list">',
|
|
16493
16630
|
...sessions.map((session) => [
|
|
16494
|
-
`<article class="voice-session-card ${
|
|
16631
|
+
`<article class="voice-session-card ${escapeHtml25(session.status)}">`,
|
|
16495
16632
|
'<div class="voice-session-card-header">',
|
|
16496
|
-
`<strong>${
|
|
16497
|
-
`<span>${
|
|
16633
|
+
`<strong>${escapeHtml25(session.sessionId)}</strong>`,
|
|
16634
|
+
`<span>${escapeHtml25(session.status)}</span>`,
|
|
16498
16635
|
"</div>",
|
|
16499
16636
|
"<dl>",
|
|
16500
16637
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -16502,9 +16639,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
16502
16639
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
16503
16640
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
16504
16641
|
"</dl>",
|
|
16505
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
16506
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
16507
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
16642
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml25(session.latestOutcome)}</p>` : "",
|
|
16643
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml25).join(", ")}</p>` : "",
|
|
16644
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml25(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml25(session.replayHref)}">Open replay</a></p>` : "",
|
|
16508
16645
|
"</article>"
|
|
16509
16646
|
].join("")),
|
|
16510
16647
|
"</div>"
|
|
@@ -16880,7 +17017,7 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
16880
17017
|
import { Elysia as Elysia26 } from "elysia";
|
|
16881
17018
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
16882
17019
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
16883
|
-
var
|
|
17020
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16884
17021
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
16885
17022
|
var getString11 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
16886
17023
|
var createTraceStageIndex = (events) => {
|
|
@@ -16991,7 +17128,7 @@ var summarizeVoiceTurnLatency = async (options) => {
|
|
|
16991
17128
|
warnings
|
|
16992
17129
|
};
|
|
16993
17130
|
};
|
|
16994
|
-
var
|
|
17131
|
+
var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
16995
17132
|
var renderVoiceTurnLatencyHTML = (report, options = {}) => {
|
|
16996
17133
|
const title = options.title ?? "Voice Turn Latency";
|
|
16997
17134
|
const snippet = `app.use(
|
|
@@ -17012,11 +17149,11 @@ await traceStore.append({
|
|
|
17012
17149
|
turnId,
|
|
17013
17150
|
type: 'turn_latency.stage'
|
|
17014
17151
|
});`;
|
|
17015
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
17016
|
-
<header><div><p class="eyebrow">${
|
|
17017
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
17152
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml26(turn.status)}">
|
|
17153
|
+
<header><div><p class="eyebrow">${escapeHtml26(turn.sessionId)} \xB7 ${escapeHtml26(turn.turnId)}</p><h2>${escapeHtml26(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml26(turn.status)}</strong></header>
|
|
17154
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml26(stage.label)}</dt><dd>${escapeHtml26(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
17018
17155
|
</article>`).join("");
|
|
17019
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17156
|
+
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:#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>${escapeHtml26(title)}</h1><div class="summary"><span class="pill ${escapeHtml26(report.status)}">${escapeHtml26(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml26(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>${escapeHtml26(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
17020
17157
|
};
|
|
17021
17158
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
17022
17159
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -17043,7 +17180,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
17043
17180
|
};
|
|
17044
17181
|
// src/liveLatency.ts
|
|
17045
17182
|
import { Elysia as Elysia27 } from "elysia";
|
|
17046
|
-
var
|
|
17183
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17047
17184
|
var percentile3 = (values, percentileValue) => {
|
|
17048
17185
|
if (values.length === 0) {
|
|
17049
17186
|
return;
|
|
@@ -17088,7 +17225,7 @@ var summarizeVoiceLiveLatency = async (options) => {
|
|
|
17088
17225
|
warnings
|
|
17089
17226
|
};
|
|
17090
17227
|
};
|
|
17091
|
-
var
|
|
17228
|
+
var formatMs3 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
17092
17229
|
var renderVoiceLiveLatencyHTML = (report, options = {}) => {
|
|
17093
17230
|
const title = options.title ?? "Voice Live Latency";
|
|
17094
17231
|
const snippet = `app.use(
|
|
@@ -17110,8 +17247,8 @@ await traceStore.append({
|
|
|
17110
17247
|
sessionId,
|
|
17111
17248
|
type: 'client.live_latency'
|
|
17112
17249
|
});`;
|
|
17113
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
17114
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17250
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml27(sample.sessionId)}</td><td>${escapeHtml27(formatMs3(sample.latencyMs))}</td><td>${escapeHtml27(sample.status ?? "unknown")}</td><td>${escapeHtml27(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
17251
|
+
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:#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>${escapeHtml27(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml27(report.status)}">Status: ${escapeHtml27(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml27(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml27(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml27(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>${escapeHtml27(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>`;
|
|
17115
17252
|
};
|
|
17116
17253
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
17117
17254
|
const path = options.path ?? "/api/live-latency";
|
|
@@ -17437,7 +17574,7 @@ None.
|
|
|
17437
17574
|
// src/turnQuality.ts
|
|
17438
17575
|
import { Elysia as Elysia28 } from "elysia";
|
|
17439
17576
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
17440
|
-
var
|
|
17577
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17441
17578
|
var getTurnLatencyMs = (turn) => {
|
|
17442
17579
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
17443
17580
|
if (firstTranscriptAt === undefined) {
|
|
@@ -17508,24 +17645,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
17508
17645
|
};
|
|
17509
17646
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
17510
17647
|
const title = options.title ?? "Voice Turn Quality";
|
|
17511
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
17648
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml28(turn.status)}">
|
|
17512
17649
|
<div class="turn-header">
|
|
17513
17650
|
<div>
|
|
17514
|
-
<p class="eyebrow">${
|
|
17515
|
-
<h2>${
|
|
17651
|
+
<p class="eyebrow">${escapeHtml28(turn.sessionId)} \xB7 ${escapeHtml28(turn.turnId)}</p>
|
|
17652
|
+
<h2>${escapeHtml28(turn.text || "Empty turn")}</h2>
|
|
17516
17653
|
</div>
|
|
17517
|
-
<strong>${
|
|
17654
|
+
<strong>${escapeHtml28(turn.status)}</strong>
|
|
17518
17655
|
</div>
|
|
17519
17656
|
<dl>
|
|
17520
|
-
<div><dt>Source</dt><dd>${
|
|
17657
|
+
<div><dt>Source</dt><dd>${escapeHtml28(turn.source ?? "unknown")}</dd></div>
|
|
17521
17658
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
17522
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
17523
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
17659
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml28(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
17660
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml28(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
17524
17661
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
17525
17662
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
17526
17663
|
</dl>
|
|
17527
17664
|
</article>`).join("");
|
|
17528
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17665
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(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>${escapeHtml28(title)}</h1><div class="summary"><span class="pill ${escapeHtml28(report.status)}">${escapeHtml28(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>`;
|
|
17529
17666
|
};
|
|
17530
17667
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
17531
17668
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -18452,7 +18589,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
18452
18589
|
return parameters;
|
|
18453
18590
|
};
|
|
18454
18591
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
18455
|
-
var
|
|
18592
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
18456
18593
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
18457
18594
|
if (!webhook?.verificationUrl) {
|
|
18458
18595
|
return;
|
|
@@ -18495,23 +18632,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
18495
18632
|
};
|
|
18496
18633
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
18497
18634
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
18498
|
-
<h1>${
|
|
18635
|
+
<h1>${escapeHtml29(title)}</h1>
|
|
18499
18636
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
18500
18637
|
<section>
|
|
18501
18638
|
<h2>URLs</h2>
|
|
18502
18639
|
<ul>
|
|
18503
|
-
<li><strong>TwiML:</strong> <code>${
|
|
18504
|
-
<li><strong>Media stream:</strong> <code>${
|
|
18505
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
18640
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml29(status.urls.twiml)}</code></li>
|
|
18641
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml29(status.urls.stream)}</code></li>
|
|
18642
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml29(status.urls.webhook)}</code></li>
|
|
18506
18643
|
</ul>
|
|
18507
18644
|
</section>
|
|
18508
18645
|
<section>
|
|
18509
18646
|
<h2>Signing</h2>
|
|
18510
18647
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
18511
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
18648
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml29(status.signing.verificationUrl)}</code></p>` : ""}
|
|
18512
18649
|
</section>
|
|
18513
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
18514
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
18650
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml29(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
18651
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml29(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
18515
18652
|
</main>`;
|
|
18516
18653
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
18517
18654
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -18522,20 +18659,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
18522
18659
|
});
|
|
18523
18660
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
18524
18661
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
18525
|
-
<h1>${
|
|
18662
|
+
<h1>${escapeHtml29(title)}</h1>
|
|
18526
18663
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
18527
18664
|
<section>
|
|
18528
18665
|
<h2>Checks</h2>
|
|
18529
18666
|
<ul>
|
|
18530
|
-
${report.checks.map((check) => `<li><strong>${
|
|
18667
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml29(check.name)}</strong>: ${escapeHtml29(check.status)}${check.message ? ` - ${escapeHtml29(check.message)}` : ""}</li>`).join("")}
|
|
18531
18668
|
</ul>
|
|
18532
18669
|
</section>
|
|
18533
18670
|
<section>
|
|
18534
18671
|
<h2>Observed URLs</h2>
|
|
18535
18672
|
<ul>
|
|
18536
|
-
<li><strong>TwiML:</strong> <code>${
|
|
18537
|
-
<li><strong>Stream:</strong> <code>${
|
|
18538
|
-
<li><strong>Webhook:</strong> <code>${
|
|
18673
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml29(report.setup.urls.twiml)}</code></li>
|
|
18674
|
+
<li><strong>Stream:</strong> <code>${escapeHtml29(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
18675
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml29(report.setup.urls.webhook)}</code></li>
|
|
18539
18676
|
</ul>
|
|
18540
18677
|
</section>
|
|
18541
18678
|
</main>`;
|
|
@@ -19132,7 +19269,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
19132
19269
|
|
|
19133
19270
|
// src/telephony/plivo.ts
|
|
19134
19271
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19135
|
-
var
|
|
19272
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19136
19273
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19137
19274
|
var resolveRequestOrigin2 = (request) => {
|
|
19138
19275
|
const url = new URL(request.url);
|
|
@@ -19562,21 +19699,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
19562
19699
|
};
|
|
19563
19700
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19564
19701
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
19565
|
-
<h1>${
|
|
19702
|
+
<h1>${escapeHtml30(title)}</h1>
|
|
19566
19703
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
19567
19704
|
<ul>
|
|
19568
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
19569
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
19570
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
19705
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml30(status.urls.answer)}</code></li>
|
|
19706
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml30(status.urls.stream)}</code></li>
|
|
19707
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml30(status.urls.webhook)}</code></li>
|
|
19571
19708
|
</ul>
|
|
19572
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
19573
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
19709
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml30(name)}</code></li>`).join("")}</ul>` : ""}
|
|
19710
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml30(warning)}</li>`).join("")}</ul>` : ""}
|
|
19574
19711
|
</main>`;
|
|
19575
19712
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19576
19713
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
19577
|
-
<h1>${
|
|
19714
|
+
<h1>${escapeHtml30(title)}</h1>
|
|
19578
19715
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
19579
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
19716
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml30(check.name)}</strong>: ${escapeHtml30(check.status)}${check.message ? ` - ${escapeHtml30(check.message)}` : ""}</li>`).join("")}</ul>
|
|
19580
19717
|
</main>`;
|
|
19581
19718
|
var runPlivoSmokeTest = async (input) => {
|
|
19582
19719
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -19780,7 +19917,7 @@ import { Buffer as Buffer6 } from "buffer";
|
|
|
19780
19917
|
import { Database as Database2 } from "bun:sqlite";
|
|
19781
19918
|
import { Elysia as Elysia32 } from "elysia";
|
|
19782
19919
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19783
|
-
var
|
|
19920
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19784
19921
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19785
19922
|
var resolveRequestOrigin3 = (request) => {
|
|
19786
19923
|
const url = new URL(request.url);
|
|
@@ -20173,21 +20310,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
20173
20310
|
};
|
|
20174
20311
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20175
20312
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
20176
|
-
<h1>${
|
|
20313
|
+
<h1>${escapeHtml31(title)}</h1>
|
|
20177
20314
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20178
20315
|
<ul>
|
|
20179
|
-
<li><strong>TeXML:</strong> <code>${
|
|
20180
|
-
<li><strong>Media stream:</strong> <code>${
|
|
20181
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
20316
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml31(status.urls.texml)}</code></li>
|
|
20317
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml31(status.urls.stream)}</code></li>
|
|
20318
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml31(status.urls.webhook)}</code></li>
|
|
20182
20319
|
</ul>
|
|
20183
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20184
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
20320
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml31(name)}</code></li>`).join("")}</ul>` : ""}
|
|
20321
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml31(warning)}</li>`).join("")}</ul>` : ""}
|
|
20185
20322
|
</main>`;
|
|
20186
20323
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20187
20324
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
20188
|
-
<h1>${
|
|
20325
|
+
<h1>${escapeHtml31(title)}</h1>
|
|
20189
20326
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20190
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
20327
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml31(check.name)}</strong>: ${escapeHtml31(check.status)}${check.message ? ` - ${escapeHtml31(check.message)}` : ""}</li>`).join("")}</ul>
|
|
20191
20328
|
</main>`;
|
|
20192
20329
|
var runTelnyxSmokeTest = async (input) => {
|
|
20193
20330
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -20391,7 +20528,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
20391
20528
|
|
|
20392
20529
|
// src/telephony/matrix.ts
|
|
20393
20530
|
import { Elysia as Elysia33 } from "elysia";
|
|
20394
|
-
var
|
|
20531
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20395
20532
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
20396
20533
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
20397
20534
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -20452,13 +20589,13 @@ var badgeStyles = {
|
|
|
20452
20589
|
};
|
|
20453
20590
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
20454
20591
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
20455
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
20592
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml32(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
20456
20593
|
<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>
|
|
20457
20594
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
20458
20595
|
${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);">
|
|
20459
20596
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
20460
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
20461
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
20597
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml32(entry.name)}</h2>
|
|
20598
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml32(entry.status.toUpperCase())}</span>
|
|
20462
20599
|
</div>
|
|
20463
20600
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
20464
20601
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -20466,9 +20603,9 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
20466
20603
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
20467
20604
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
20468
20605
|
</dl>
|
|
20469
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
20470
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
20471
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
20606
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml32(entry.setup.urls.stream || "missing")}</code></p>
|
|
20607
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml32(entry.setup.urls.webhook || "missing")}</code></p>
|
|
20608
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml32(issue.severity)}: ${escapeHtml32(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
20472
20609
|
</article>`).join("")}
|
|
20473
20610
|
</section>
|
|
20474
20611
|
</main>`;
|
|
@@ -20504,7 +20641,7 @@ var defaultRequirements = [
|
|
|
20504
20641
|
"lifecycle-outcome",
|
|
20505
20642
|
"no-session-error"
|
|
20506
20643
|
];
|
|
20507
|
-
var
|
|
20644
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20508
20645
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
20509
20646
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
20510
20647
|
const value = event.payload[key];
|
|
@@ -20613,10 +20750,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
20613
20750
|
});
|
|
20614
20751
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
20615
20752
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
20616
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
20617
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
20618
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
20619
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20753
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml33(issue.requirement)}</strong>: ${escapeHtml33(issue.message)}</li>`).join("");
|
|
20754
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml33(outcome)}</span>`).join("");
|
|
20755
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml33(requirement)}</span>`).join("");
|
|
20756
|
+
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:#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>${escapeHtml33(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml33(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml33(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml33(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>`;
|
|
20620
20757
|
};
|
|
20621
20758
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
20622
20759
|
query,
|
|
@@ -20682,7 +20819,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
20682
20819
|
"completed",
|
|
20683
20820
|
"failed"
|
|
20684
20821
|
];
|
|
20685
|
-
var
|
|
20822
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20686
20823
|
var loadRouteJson = async (input) => {
|
|
20687
20824
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
20688
20825
|
headers: {
|
|
@@ -20920,10 +21057,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
20920
21057
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
20921
21058
|
const urls = entry?.setup.urls;
|
|
20922
21059
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
20923
|
-
return `<tr><td>${
|
|
21060
|
+
return `<tr><td>${escapeHtml34(carrier.name ?? carrier.provider)}</td><td>${escapeHtml34(carrier.provider)}</td><td><code>${escapeHtml34(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml34(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml34(entry.status)}">${escapeHtml34(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml34(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml34(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml34(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
20924
21061
|
}).join("");
|
|
20925
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
20926
|
-
const snippet =
|
|
21062
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml34(stage)}</code></li>`).join("");
|
|
21063
|
+
const snippet = escapeHtml34(`const phoneAgent = createVoicePhoneAgent({
|
|
20927
21064
|
carriers: [
|
|
20928
21065
|
{
|
|
20929
21066
|
provider: 'twilio',
|
|
@@ -20957,11 +21094,11 @@ app.use(
|
|
|
20957
21094
|
);`);
|
|
20958
21095
|
const checklist = report.carriers.map((carrier) => {
|
|
20959
21096
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
20960
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
20961
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
20962
|
-
return `<article><h3>${
|
|
21097
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml34(issue)}</li>`).join("") ?? "";
|
|
21098
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml34(step)}</li>`).join("") ?? "";
|
|
21099
|
+
return `<article><h3>${escapeHtml34(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
20963
21100
|
}).join("");
|
|
20964
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
21101
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml34(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>${escapeHtml34(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="${escapeHtml34(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>`;
|
|
20965
21102
|
};
|
|
20966
21103
|
var createVoicePhoneAgent = (options) => {
|
|
20967
21104
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -23030,7 +23167,7 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
23030
23167
|
};
|
|
23031
23168
|
// src/providerCapabilities.ts
|
|
23032
23169
|
import { Elysia as Elysia36 } from "elysia";
|
|
23033
|
-
var
|
|
23170
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23034
23171
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
23035
23172
|
configured: true,
|
|
23036
23173
|
features: options.features?.[provider],
|
|
@@ -23093,27 +23230,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
23093
23230
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
23094
23231
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
23095
23232
|
const cards = report.capabilities.map((capability) => {
|
|
23096
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
23097
|
-
return `<article class="card ${
|
|
23233
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml35(feature)}</span>`).join("");
|
|
23234
|
+
return `<article class="card ${escapeHtml35(capability.status)}">
|
|
23098
23235
|
<div class="card-header">
|
|
23099
23236
|
<div>
|
|
23100
|
-
<p class="eyebrow">${
|
|
23101
|
-
<h2>${
|
|
23237
|
+
<p class="eyebrow">${escapeHtml35(capability.kind)}</p>
|
|
23238
|
+
<h2>${escapeHtml35(capability.label ?? capability.provider)}</h2>
|
|
23102
23239
|
</div>
|
|
23103
|
-
<strong>${
|
|
23240
|
+
<strong>${escapeHtml35(capability.status)}</strong>
|
|
23104
23241
|
</div>
|
|
23105
|
-
${capability.description ? `<p>${
|
|
23242
|
+
${capability.description ? `<p>${escapeHtml35(capability.description)}</p>` : ""}
|
|
23106
23243
|
<dl>
|
|
23107
23244
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
23108
23245
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
23109
|
-
<div><dt>Model</dt><dd>${
|
|
23246
|
+
<div><dt>Model</dt><dd>${escapeHtml35(capability.model ?? "default")}</dd></div>
|
|
23110
23247
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
23111
23248
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
23112
23249
|
</dl>
|
|
23113
23250
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
23114
23251
|
</article>`;
|
|
23115
23252
|
}).join("");
|
|
23116
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
23253
|
+
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,.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>${escapeHtml35(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>`;
|
|
23117
23254
|
};
|
|
23118
23255
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
23119
23256
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -23140,7 +23277,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
23140
23277
|
};
|
|
23141
23278
|
// src/resilienceRoutes.ts
|
|
23142
23279
|
import { Elysia as Elysia37 } from "elysia";
|
|
23143
|
-
var
|
|
23280
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23144
23281
|
var getString13 = (value) => typeof value === "string" ? value : undefined;
|
|
23145
23282
|
var getNumber7 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
23146
23283
|
var getBoolean2 = (value) => value === true;
|
|
@@ -23288,13 +23425,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
23288
23425
|
};
|
|
23289
23426
|
var renderProviderCards = (title, providers) => {
|
|
23290
23427
|
if (providers.length === 0) {
|
|
23291
|
-
return `<p class="muted">No ${
|
|
23428
|
+
return `<p class="muted">No ${escapeHtml36(title)} provider health yet.</p>`;
|
|
23292
23429
|
}
|
|
23293
23430
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
23294
|
-
<article class="card provider ${
|
|
23431
|
+
<article class="card provider ${escapeHtml36(provider.status)}">
|
|
23295
23432
|
<div class="card-header">
|
|
23296
|
-
<strong>${
|
|
23297
|
-
<span>${
|
|
23433
|
+
<strong>${escapeHtml36(provider.provider)}</strong>
|
|
23434
|
+
<span>${escapeHtml36(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
23298
23435
|
</div>
|
|
23299
23436
|
<dl>
|
|
23300
23437
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -23303,7 +23440,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
23303
23440
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
23304
23441
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
23305
23442
|
</dl>
|
|
23306
|
-
${provider.lastError ? `<p class="muted">${
|
|
23443
|
+
${provider.lastError ? `<p class="muted">${escapeHtml36(provider.lastError)}</p>` : ""}
|
|
23307
23444
|
</article>
|
|
23308
23445
|
`).join("")}</div>`;
|
|
23309
23446
|
};
|
|
@@ -23312,24 +23449,24 @@ var renderTimeline2 = (events) => {
|
|
|
23312
23449
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
23313
23450
|
}
|
|
23314
23451
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
23315
|
-
<article class="card event ${
|
|
23452
|
+
<article class="card event ${escapeHtml36(event.status ?? "unknown")}">
|
|
23316
23453
|
<div class="card-header">
|
|
23317
|
-
<strong>${
|
|
23454
|
+
<strong>${escapeHtml36(event.kind.toUpperCase())} ${escapeHtml36(event.operation ?? "generate")}</strong>
|
|
23318
23455
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
23319
23456
|
</div>
|
|
23320
23457
|
<p>
|
|
23321
|
-
<span class="pill">${
|
|
23322
|
-
<span class="pill">provider: ${
|
|
23323
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
23458
|
+
<span class="pill">${escapeHtml36(event.status ?? "unknown")}</span>
|
|
23459
|
+
<span class="pill">provider: ${escapeHtml36(event.provider ?? "unknown")}</span>
|
|
23460
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml36(event.fallbackProvider)}</span>` : ""}
|
|
23324
23461
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
23325
23462
|
</p>
|
|
23326
23463
|
<dl>
|
|
23327
23464
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
23328
23465
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
23329
23466
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
23330
|
-
<div><dt>Session</dt><dd>${
|
|
23467
|
+
<div><dt>Session</dt><dd>${escapeHtml36(event.sessionId)}</dd></div>
|
|
23331
23468
|
</dl>
|
|
23332
|
-
${event.error ? `<p class="muted">${
|
|
23469
|
+
${event.error ? `<p class="muted">${escapeHtml36(event.error)}</p>` : ""}
|
|
23333
23470
|
</article>
|
|
23334
23471
|
`).join("")}</div>`;
|
|
23335
23472
|
};
|
|
@@ -23339,9 +23476,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
23339
23476
|
const status = latest?.status ?? "idle";
|
|
23340
23477
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
23341
23478
|
return `<div>
|
|
23342
|
-
<dt>${
|
|
23343
|
-
<dd>${
|
|
23344
|
-
<small>${
|
|
23479
|
+
<dt>${escapeHtml36(kind.toUpperCase())}</dt>
|
|
23480
|
+
<dd>${escapeHtml36(provider)}${escapeHtml36(fallback)}</dd>
|
|
23481
|
+
<small>${escapeHtml36(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>
|
|
23345
23482
|
</div>`;
|
|
23346
23483
|
};
|
|
23347
23484
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -23349,10 +23486,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
23349
23486
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
23350
23487
|
}
|
|
23351
23488
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
23352
|
-
<article class="card session ${
|
|
23489
|
+
<article class="card session ${escapeHtml36(session.status)}">
|
|
23353
23490
|
<div class="card-header">
|
|
23354
|
-
<strong>${
|
|
23355
|
-
<span>${
|
|
23491
|
+
<strong>${escapeHtml36(session.sessionId)}</strong>
|
|
23492
|
+
<span>${escapeHtml36(session.status)}</span>
|
|
23356
23493
|
</div>
|
|
23357
23494
|
<p>
|
|
23358
23495
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -23379,21 +23516,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
23379
23516
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
23380
23517
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
23381
23518
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
23382
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
23383
|
-
<p class="muted">${
|
|
23519
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml36(pathPrefix)}">
|
|
23520
|
+
<p class="muted">${escapeHtml36(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
23384
23521
|
<div class="simulate-actions">
|
|
23385
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
23386
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
23522
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml36(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml36(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
23523
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml36(provider.provider)}">Mark ${escapeHtml36(provider.provider)} recovered</button>`).join("")}
|
|
23387
23524
|
</div>
|
|
23388
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
23525
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml36(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
23389
23526
|
<pre class="simulate-output" hidden></pre>
|
|
23390
23527
|
</div>`;
|
|
23391
23528
|
};
|
|
23392
23529
|
var renderVoiceResilienceHTML = (input) => {
|
|
23393
23530
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
23394
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
23395
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
23396
|
-
const snippet =
|
|
23531
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml36(kind)}: ${String(count)}</span>`).join("");
|
|
23532
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml36(link.href)}">${escapeHtml36(link.label)}</a>`).join(" \xB7 ") : "";
|
|
23533
|
+
const snippet = escapeHtml36(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
23397
23534
|
kind: 'stt',
|
|
23398
23535
|
providers: ['deepgram', 'assemblyai'],
|
|
23399
23536
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -23431,7 +23568,7 @@ app.use(
|
|
|
23431
23568
|
<head>
|
|
23432
23569
|
<meta charset="utf-8" />
|
|
23433
23570
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
23434
|
-
<title>${
|
|
23571
|
+
<title>${escapeHtml36(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
23435
23572
|
<style>
|
|
23436
23573
|
:root { color-scheme: dark; }
|
|
23437
23574
|
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; }
|
|
@@ -23798,7 +23935,7 @@ var statusRank = {
|
|
|
23798
23935
|
warn: 1,
|
|
23799
23936
|
fail: 2
|
|
23800
23937
|
};
|
|
23801
|
-
var
|
|
23938
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23802
23939
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
23803
23940
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
23804
23941
|
var uniqueSorted5 = (values) => [
|
|
@@ -24094,11 +24231,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
24094
24231
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
24095
24232
|
const kindCards = providerKinds.map((kind) => {
|
|
24096
24233
|
const kindReport = report.kinds[kind];
|
|
24097
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
24234
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml37(metric.label)}</dt><dd>${escapeHtml37(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml37(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
24098
24235
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
24099
|
-
return `<article class="${
|
|
24236
|
+
return `<article class="${escapeHtml37(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml37(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml37(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
24100
24237
|
}).join("");
|
|
24101
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
24238
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml37(issue.status)}"><strong>${escapeHtml37(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml37(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
24102
24239
|
const snippet = `createVoiceProviderSloRoutes({
|
|
24103
24240
|
store: runtimeStorage.traces,
|
|
24104
24241
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -24108,7 +24245,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
24108
24245
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
24109
24246
|
}
|
|
24110
24247
|
})`;
|
|
24111
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24248
|
+
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:#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>${escapeHtml37(title)}</h1><p class="status ${escapeHtml37(report.status)}">${escapeHtml37(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>${escapeHtml37(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
24112
24249
|
};
|
|
24113
24250
|
var createVoiceProviderSloRoutes = (options) => {
|
|
24114
24251
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -24948,7 +25085,7 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
24948
25085
|
|
|
24949
25086
|
// src/opsRecovery.ts
|
|
24950
25087
|
import { Elysia as Elysia40 } from "elysia";
|
|
24951
|
-
var
|
|
25088
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24952
25089
|
var getString14 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
24953
25090
|
var hrefForSession = (value, sessionId) => {
|
|
24954
25091
|
if (typeof value === "function") {
|
|
@@ -25162,13 +25299,13 @@ ${failedSessions || "None."}
|
|
|
25162
25299
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
25163
25300
|
`;
|
|
25164
25301
|
};
|
|
25165
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
25302
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml38(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>${escapeHtml38(label)}</span><strong>not configured</strong></article>`;
|
|
25166
25303
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
25167
25304
|
const title = options.title ?? "Voice Ops Recovery";
|
|
25168
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
25169
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
25170
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
25171
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25305
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml38(issue.severity)}</td><td><code>${escapeHtml38(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml38(issue.href)}">${escapeHtml38(issue.label)}</a>` : escapeHtml38(issue.label)}</td><td>${escapeHtml38(String(issue.value ?? ""))}</td><td>${escapeHtml38(issue.detail ?? "")}</td></tr>`).join("");
|
|
25306
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml38(provider.provider)}</td><td>${escapeHtml38(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml38(provider.lastError ?? "")}</td></tr>`).join("");
|
|
25307
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml38(session.operationsRecordHref)}">${escapeHtml38(session.sessionId)}</a>` : escapeHtml38(session.sessionId)}${session.provider ? ` via ${escapeHtml38(session.provider)}` : ""}${session.error ? `: ${escapeHtml38(session.error)}` : ""}</li>`).join("");
|
|
25308
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(title)}</h1><p><span class="status">${escapeHtml38(report.status)}</span> Checked ${escapeHtml38(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>${escapeHtml38(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>`;
|
|
25172
25309
|
};
|
|
25173
25310
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
25174
25311
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
@@ -25215,7 +25352,7 @@ import { Elysia as Elysia42 } from "elysia";
|
|
|
25215
25352
|
|
|
25216
25353
|
// src/traceTimeline.ts
|
|
25217
25354
|
import { Elysia as Elysia41 } from "elysia";
|
|
25218
|
-
var
|
|
25355
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25219
25356
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
25220
25357
|
var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
25221
25358
|
var firstString3 = (payload, keys) => {
|
|
@@ -25397,18 +25534,18 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
25397
25534
|
warnings: sessions.filter((session) => session.status === "warning").length
|
|
25398
25535
|
};
|
|
25399
25536
|
};
|
|
25400
|
-
var
|
|
25401
|
-
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>${
|
|
25537
|
+
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
25538
|
+
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>${escapeHtml39(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>`;
|
|
25402
25539
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
25403
|
-
const events = session.events.map((event) => `<tr class="${
|
|
25404
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
25405
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
25406
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25540
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml39(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml39(event.type)}</td><td>${escapeHtml39(event.label)}</td><td>${escapeHtml39(event.provider ?? "")}</td><td>${escapeHtml39(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
25541
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml39(issue.severity)}">${escapeHtml39(issue.code)}: ${escapeHtml39(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
25542
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml39(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
25543
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(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>${escapeHtml39(session.sessionId)}</h1><p class="status ${escapeHtml39(session.status)}">${escapeHtml39(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>`;
|
|
25407
25544
|
};
|
|
25408
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
25545
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml39(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml39(session.operationsRecordHref)}">${escapeHtml39(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml39(session.sessionId)}</a>`}</td><td>${escapeHtml39(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) => escapeHtml39(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
25409
25546
|
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}}";
|
|
25410
25547
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
25411
|
-
const snippet =
|
|
25548
|
+
const snippet = escapeHtml39(`const traceStore = createVoiceTraceSinkStore({
|
|
25412
25549
|
store: runtimeStorage.traces,
|
|
25413
25550
|
sinks: [
|
|
25414
25551
|
createVoiceTraceHTTPSink({
|
|
@@ -25434,7 +25571,7 @@ app.use(
|
|
|
25434
25571
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
25435
25572
|
})
|
|
25436
25573
|
);`);
|
|
25437
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25574
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(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>${escapeHtml39(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>`;
|
|
25438
25575
|
};
|
|
25439
25576
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
25440
25577
|
const path = options.path ?? "/api/voice-traces";
|
|
@@ -25748,8 +25885,8 @@ var assertVoiceOperationsRecordGuardrails = (record, input = {}) => {
|
|
|
25748
25885
|
}
|
|
25749
25886
|
return report;
|
|
25750
25887
|
};
|
|
25751
|
-
var
|
|
25752
|
-
var
|
|
25888
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25889
|
+
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
25753
25890
|
var outcomeLabels = (outcome) => [
|
|
25754
25891
|
outcome.complete ? "complete" : undefined,
|
|
25755
25892
|
outcome.escalated ? "escalated" : undefined,
|
|
@@ -25765,7 +25902,7 @@ var renderVoiceOperationsRecordIncidentMarkdown = (record) => {
|
|
|
25765
25902
|
`# Voice incident handoff: ${record.sessionId}`,
|
|
25766
25903
|
"",
|
|
25767
25904
|
`- Status: ${record.status}`,
|
|
25768
|
-
`- Duration: ${
|
|
25905
|
+
`- Duration: ${formatMs5(record.summary.callDurationMs)}`,
|
|
25769
25906
|
`- Turns: ${String(record.summary.turnCount)}`,
|
|
25770
25907
|
`- Errors: ${String(record.summary.errorCount)}`,
|
|
25771
25908
|
`- Outcome: ${outcomes.join(", ") || "unknown"}`,
|
|
@@ -25803,19 +25940,19 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
25803
25940
|
`);
|
|
25804
25941
|
};
|
|
25805
25942
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
25806
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
25807
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
25808
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
25809
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
25810
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
25811
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
25812
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
25813
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
25943
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml40(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>';
|
|
25944
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml40(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml40(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml40(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml40(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
25945
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml40(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml40(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml40(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml40(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml40(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
25946
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml40(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml40(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml40(handoff.status ?? "")}</span><p>${escapeHtml40(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
25947
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml40(tool.toolName ?? "tool")}</strong> <span>${escapeHtml40(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml40(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
25948
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml40(review.title)}</strong> <span>${escapeHtml40(review.summary.outcome ?? "")}</span><p>${escapeHtml40(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
25949
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml40(task.title)}</strong> <span>${escapeHtml40(task.status)}</span><p>${escapeHtml40(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
25950
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml40(event.type)}</strong> <span>${escapeHtml40(event.deliveryStatus ?? "local")}</span><p>${escapeHtml40(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
25814
25951
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
25815
25952
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
25816
|
-
return `<li><strong>assistant.guardrail ${
|
|
25953
|
+
return `<li><strong>assistant.guardrail ${escapeHtml40(decision.stage ?? "unknown")}</strong> <span>${escapeHtml40(decision.status ?? "")}</span><p>Allowed: ${escapeHtml40(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml40(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml40(decision.turnId)}` : ""}</p><p>${escapeHtml40(findings)}</p></li>`;
|
|
25817
25954
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
25818
|
-
const snippet =
|
|
25955
|
+
const snippet = escapeHtml40(`app.use(
|
|
25819
25956
|
createVoiceOperationsRecordRoutes({
|
|
25820
25957
|
audit: auditStore,
|
|
25821
25958
|
integrationEvents: opsEvents,
|
|
@@ -25829,9 +25966,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
25829
25966
|
tasks: opsTasks
|
|
25830
25967
|
})
|
|
25831
25968
|
);`);
|
|
25832
|
-
const incidentMarkdown =
|
|
25833
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
25834
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25969
|
+
const incidentMarkdown = escapeHtml40(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
25970
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml40(options.incidentHref)}">Download incident.md</a>` : "";
|
|
25971
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(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>${escapeHtml40(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml40(record.status)}">${escapeHtml40(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</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>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="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, 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>`;
|
|
25835
25972
|
};
|
|
25836
25973
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
25837
25974
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -27375,7 +27512,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
27375
27512
|
};
|
|
27376
27513
|
|
|
27377
27514
|
// src/productionReadiness.ts
|
|
27378
|
-
var
|
|
27515
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27379
27516
|
var rollupStatus3 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
27380
27517
|
var readinessGateCodes = {
|
|
27381
27518
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -28718,22 +28855,22 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28718
28855
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
28719
28856
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
28720
28857
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
28721
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
28858
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml41(report.profile.name)}</h2><p>${escapeHtml41(report.profile.description)}</p><p>${escapeHtml41(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="${escapeHtml41(surface.href)}">${escapeHtml41(surface.label)}</a>` : escapeHtml41(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
28722
28859
|
const checks = report.checks.map((check, index) => {
|
|
28723
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
28724
|
-
return `<article class="check ${
|
|
28860
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml41(action.href)}">${escapeHtml41(action.label)}</button>` : `<a href="${escapeHtml41(action.href)}">${escapeHtml41(action.label)}</a>`).join("");
|
|
28861
|
+
return `<article class="check ${escapeHtml41(check.status)}">
|
|
28725
28862
|
<div>
|
|
28726
|
-
<span>${
|
|
28727
|
-
<h2>${
|
|
28728
|
-
${check.detail ? `<p>${
|
|
28729
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
28863
|
+
<span>${escapeHtml41(check.status.toUpperCase())}</span>
|
|
28864
|
+
<h2>${escapeHtml41(check.label)}</h2>
|
|
28865
|
+
${check.detail ? `<p>${escapeHtml41(check.detail)}</p>` : ""}
|
|
28866
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml41(check.proofSource.href)}">${escapeHtml41(check.proofSource.sourceLabel)}</a>` : escapeHtml41(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml41(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
28730
28867
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
28731
28868
|
</div>
|
|
28732
|
-
<strong>${
|
|
28733
|
-
${check.href ? `<a href="${
|
|
28869
|
+
<strong>${escapeHtml41(String(check.value ?? check.status))}</strong>
|
|
28870
|
+
${check.href ? `<a href="${escapeHtml41(check.href)}">Open surface</a>` : ""}
|
|
28734
28871
|
</article>`;
|
|
28735
28872
|
}).join("");
|
|
28736
|
-
const snippet =
|
|
28873
|
+
const snippet = escapeHtml41(`createVoiceProductionReadinessRoutes({
|
|
28737
28874
|
htmlPath: '/production-readiness',
|
|
28738
28875
|
path: '/api/production-readiness',
|
|
28739
28876
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -28749,7 +28886,7 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
28749
28886
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
28750
28887
|
store: traceStore
|
|
28751
28888
|
});`);
|
|
28752
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
28889
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(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 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>${escapeHtml41(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 ${escapeHtml41(report.status)}">Overall: ${escapeHtml41(report.status.toUpperCase())}</p><p>Checked ${escapeHtml41(new Date(report.checkedAt).toLocaleString())}</p></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>`;
|
|
28753
28890
|
};
|
|
28754
28891
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
28755
28892
|
const path = options.path ?? "/api/production-readiness";
|
|
@@ -28804,7 +28941,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
28804
28941
|
};
|
|
28805
28942
|
// src/voiceMonitoring.ts
|
|
28806
28943
|
import { Elysia as Elysia45 } from "elysia";
|
|
28807
|
-
var
|
|
28944
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28808
28945
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
28809
28946
|
var rollupStatus4 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
28810
28947
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -29057,14 +29194,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
29057
29194
|
};
|
|
29058
29195
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
29059
29196
|
const title = options.title ?? "Voice Monitors";
|
|
29060
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
29061
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
29062
|
-
const snippet =
|
|
29197
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml42(run.label)}</td><td class="${escapeHtml42(run.status)}">${escapeHtml42(run.status)}</td><td>${escapeHtml42(run.severity)}</td><td>${escapeHtml42(String(run.value ?? ""))}</td><td>${escapeHtml42(String(run.threshold ?? ""))}</td><td>${escapeHtml42(run.detail ?? "")}</td></tr>`).join("");
|
|
29198
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml42(issue.label)}</strong> <span class="${escapeHtml42(issue.status)}">${escapeHtml42(issue.status)}</span> ${escapeHtml42(issue.detail ?? "")}</li>`).join("");
|
|
29199
|
+
const snippet = escapeHtml42(`app.use(createVoiceMonitorRoutes({
|
|
29063
29200
|
evidence,
|
|
29064
29201
|
issueStore,
|
|
29065
29202
|
monitors: [defineVoiceMonitor(...)]
|
|
29066
29203
|
}));`);
|
|
29067
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29204
|
+
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:#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>${escapeHtml42(title)}</h1><p class="pill ${escapeHtml42(report.status)}">Status: ${escapeHtml42(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>`;
|
|
29068
29205
|
};
|
|
29069
29206
|
var actorFromRequest = async (request) => {
|
|
29070
29207
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -29512,7 +29649,7 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
29512
29649
|
};
|
|
29513
29650
|
// src/providerStackRecommendations.ts
|
|
29514
29651
|
import { Elysia as Elysia46 } from "elysia";
|
|
29515
|
-
var
|
|
29652
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29516
29653
|
var profileProviderPriorities = {
|
|
29517
29654
|
"meeting-recorder": {
|
|
29518
29655
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -29831,17 +29968,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
29831
29968
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
29832
29969
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
29833
29970
|
const rows = report.rows.map((row) => {
|
|
29834
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
29835
|
-
return `<article class="row ${
|
|
29971
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml43(check.status)}"><strong>${escapeHtml43(check.label)}</strong><span>${escapeHtml43(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml43(check.remediation.href)}">${escapeHtml43(check.remediation.label)}</a>` : escapeHtml43(check.remediation.label)}: ${escapeHtml43(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
29972
|
+
return `<article class="row ${escapeHtml43(row.status)}">
|
|
29836
29973
|
<div>
|
|
29837
|
-
<p class="eyebrow">${
|
|
29838
|
-
<h2>${
|
|
29839
|
-
<p class="status ${
|
|
29974
|
+
<p class="eyebrow">${escapeHtml43(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
29975
|
+
<h2>${escapeHtml43(row.provider)}</h2>
|
|
29976
|
+
<p class="status ${escapeHtml43(row.status)}">${escapeHtml43(row.status.toUpperCase())}</p>
|
|
29840
29977
|
</div>
|
|
29841
29978
|
<ul>${checks}</ul>
|
|
29842
29979
|
</article>`;
|
|
29843
29980
|
}).join("");
|
|
29844
|
-
const snippet =
|
|
29981
|
+
const snippet = escapeHtml43(`const providerContracts = () =>
|
|
29845
29982
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
29846
29983
|
env: process.env,
|
|
29847
29984
|
providers: {
|
|
@@ -29862,7 +29999,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
29862
29999
|
providerContractMatrix: () =>
|
|
29863
30000
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
29864
30001
|
});`);
|
|
29865
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30002
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(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>${escapeHtml43(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>`;
|
|
29866
30003
|
};
|
|
29867
30004
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
29868
30005
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -30030,7 +30167,7 @@ var DEFAULT_LINKS = [
|
|
|
30030
30167
|
label: "Handoffs"
|
|
30031
30168
|
}
|
|
30032
30169
|
];
|
|
30033
|
-
var
|
|
30170
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30034
30171
|
var countProviderStatuses = (providers) => {
|
|
30035
30172
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
30036
30173
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -30099,16 +30236,16 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
30099
30236
|
trace
|
|
30100
30237
|
};
|
|
30101
30238
|
};
|
|
30102
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
30239
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml44(input.label)}</span><strong>${escapeHtml44(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml44(input.status)}">${escapeHtml44(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml44(input.href)}">Open</a>` : ""}</article>`;
|
|
30103
30240
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
30104
30241
|
const links = report.links.map((link) => `<article class="surface">
|
|
30105
|
-
<div><h2>${
|
|
30106
|
-
<p><a href="${
|
|
30242
|
+
<div><h2>${escapeHtml44(link.label)}</h2>${link.description ? `<p>${escapeHtml44(link.description)}</p>` : ""}</div>
|
|
30243
|
+
<p><a href="${escapeHtml44(link.href)}">Open ${escapeHtml44(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml44(link.statusHref)}">Status</a>` : ""}</p>
|
|
30107
30244
|
</article>`).join("");
|
|
30108
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
30109
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
30245
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml44(session.sessionId)}</td><td>${escapeHtml44(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml44(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
30246
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml44(event.kind)}</td><td>${escapeHtml44(event.provider ?? "unknown")}</td><td>${escapeHtml44(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml44(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
30110
30247
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
30111
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30248
|
+
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{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>${escapeHtml44(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 ${escapeHtml44(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>`;
|
|
30112
30249
|
};
|
|
30113
30250
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
30114
30251
|
const path = options.path ?? "/ops-console";
|
|
@@ -30532,14 +30669,14 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
30532
30669
|
};
|
|
30533
30670
|
// src/opsStatusRoutes.ts
|
|
30534
30671
|
import { Elysia as Elysia49 } from "elysia";
|
|
30535
|
-
var
|
|
30672
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30536
30673
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
30537
30674
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
30538
30675
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
30539
30676
|
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;
|
|
30540
|
-
return `<article class="surface ${
|
|
30677
|
+
return `<article class="surface ${escapeHtml45(surface.status)}"><span>${escapeHtml45(surface.status.toUpperCase())}</span><h2>${escapeHtml45(key)}</h2><strong>${escapeHtml45(value)}</strong></article>`;
|
|
30541
30678
|
}).join("");
|
|
30542
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30679
|
+
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:#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>${escapeHtml45(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml45(report.status)}">Overall: ${escapeHtml45(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>`;
|
|
30543
30680
|
};
|
|
30544
30681
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
30545
30682
|
const path = options.path ?? "/api/voice/ops-status";
|
|
@@ -30977,7 +31114,7 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
30977
31114
|
};
|
|
30978
31115
|
// src/traceDeliveryRoutes.ts
|
|
30979
31116
|
import { Elysia as Elysia50 } from "elysia";
|
|
30980
|
-
var
|
|
31117
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30981
31118
|
var getString19 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
30982
31119
|
var getNumber11 = (value) => {
|
|
30983
31120
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -31058,14 +31195,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
31058
31195
|
if (entries.length === 0) {
|
|
31059
31196
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
31060
31197
|
}
|
|
31061
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
31198
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml46(sinkId)}</strong>: ${escapeHtml46(result.status)}${result.deliveredTo ? ` to ${escapeHtml46(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml46(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
31062
31199
|
};
|
|
31063
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
31200
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml46(event.type)} <small>${escapeHtml46(event.id)}</small>${event.sessionId ? ` session=${escapeHtml46(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
31064
31201
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
31065
31202
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
31066
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
31067
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
31068
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31203
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml46(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
31204
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml46(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml46(delivery.deliveryStatus)}</span><h2>${escapeHtml46(delivery.id)}</h2><p>${escapeHtml46(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml46(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml46(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
31205
|
+
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:#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>${escapeHtml46(title)}</h1><p>Checked ${escapeHtml46(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>`;
|
|
31069
31206
|
};
|
|
31070
31207
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
31071
31208
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32788,6 +32925,8 @@ export {
|
|
|
32788
32925
|
renderVoiceTraceDeliveryHTML,
|
|
32789
32926
|
renderVoiceToolContractHTML,
|
|
32790
32927
|
renderVoiceTelephonyCarrierMatrixHTML,
|
|
32928
|
+
renderVoiceSloReadinessThresholdMarkdown,
|
|
32929
|
+
renderVoiceSloReadinessThresholdHTML,
|
|
32791
32930
|
renderVoiceSloCalibrationMarkdown,
|
|
32792
32931
|
renderVoiceSimulationSuiteHTML,
|
|
32793
32932
|
renderVoiceSessionsHTML,
|
|
@@ -32970,6 +33109,8 @@ export {
|
|
|
32970
33109
|
createVoiceTaskCreatedEvent,
|
|
32971
33110
|
createVoiceTTSProviderRouter,
|
|
32972
33111
|
createVoiceSloThresholdProfile,
|
|
33112
|
+
createVoiceSloReadinessThresholdRoutes,
|
|
33113
|
+
createVoiceSloReadinessThresholdOptions,
|
|
32973
33114
|
createVoiceSloCalibrationRoutes,
|
|
32974
33115
|
createVoiceSimulationSuiteRoutes,
|
|
32975
33116
|
createVoiceSessionsJSONHandler,
|
|
@@ -33204,6 +33345,7 @@ export {
|
|
|
33204
33345
|
buildVoiceTraceReplay,
|
|
33205
33346
|
buildVoiceTraceDeliveryReport,
|
|
33206
33347
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
33348
|
+
buildVoiceSloReadinessThresholdReport,
|
|
33207
33349
|
buildVoiceSloCalibrationReport,
|
|
33208
33350
|
buildVoiceProviderSloReport,
|
|
33209
33351
|
buildVoiceProviderContractMatrix,
|