@absolutejs/voice 0.0.22-beta.146 → 0.0.22-beta.148
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/deliveryRuntime.d.ts +96 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +364 -246
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11564,6 +11564,120 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
11564
11564
|
}
|
|
11565
11565
|
return routes;
|
|
11566
11566
|
};
|
|
11567
|
+
// src/deliveryRuntime.ts
|
|
11568
|
+
import { Elysia as Elysia12 } from "elysia";
|
|
11569
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11570
|
+
var renderSummaryCard = (label, summary) => {
|
|
11571
|
+
if (!summary) {
|
|
11572
|
+
return `<article><span>${escapeHtml15(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
11573
|
+
}
|
|
11574
|
+
return `<article><span>${escapeHtml15(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>`;
|
|
11575
|
+
};
|
|
11576
|
+
var createVoiceDeliveryRuntime = (config) => {
|
|
11577
|
+
const audit = config.audit ? createVoiceAuditSinkDeliveryWorker(config.audit) : undefined;
|
|
11578
|
+
const trace = config.trace ? createVoiceTraceSinkDeliveryWorker(config.trace) : undefined;
|
|
11579
|
+
let auditLoop;
|
|
11580
|
+
let traceLoop;
|
|
11581
|
+
if (audit && config.audit) {
|
|
11582
|
+
auditLoop = createVoiceAuditSinkDeliveryWorkerLoop({
|
|
11583
|
+
onError: config.audit.onError,
|
|
11584
|
+
pollIntervalMs: config.audit.pollIntervalMs,
|
|
11585
|
+
worker: audit
|
|
11586
|
+
});
|
|
11587
|
+
}
|
|
11588
|
+
if (trace && config.trace) {
|
|
11589
|
+
traceLoop = createVoiceTraceSinkDeliveryWorkerLoop({
|
|
11590
|
+
onError: config.trace.onError,
|
|
11591
|
+
pollIntervalMs: config.trace.pollIntervalMs,
|
|
11592
|
+
worker: trace
|
|
11593
|
+
});
|
|
11594
|
+
}
|
|
11595
|
+
return {
|
|
11596
|
+
audit,
|
|
11597
|
+
isRunning: () => Boolean(auditLoop?.isRunning() || traceLoop?.isRunning()),
|
|
11598
|
+
start: () => {
|
|
11599
|
+
if (config.audit?.autoStart) {
|
|
11600
|
+
auditLoop?.start();
|
|
11601
|
+
}
|
|
11602
|
+
if (config.trace?.autoStart) {
|
|
11603
|
+
traceLoop?.start();
|
|
11604
|
+
}
|
|
11605
|
+
},
|
|
11606
|
+
stop: () => {
|
|
11607
|
+
auditLoop?.stop();
|
|
11608
|
+
traceLoop?.stop();
|
|
11609
|
+
},
|
|
11610
|
+
summarize: async () => {
|
|
11611
|
+
const summary = {};
|
|
11612
|
+
if (config.audit) {
|
|
11613
|
+
summary.audit = await summarizeVoiceAuditSinkDeliveries(await config.audit.deliveries.list(), {
|
|
11614
|
+
deadLetters: config.audit.deadLetters
|
|
11615
|
+
});
|
|
11616
|
+
}
|
|
11617
|
+
if (config.trace) {
|
|
11618
|
+
summary.trace = await summarizeVoiceTraceSinkDeliveries(await config.trace.deliveries.list(), {
|
|
11619
|
+
deadLetters: config.trace.deadLetters
|
|
11620
|
+
});
|
|
11621
|
+
}
|
|
11622
|
+
return summary;
|
|
11623
|
+
},
|
|
11624
|
+
tick: async () => {
|
|
11625
|
+
const result = {};
|
|
11626
|
+
if (auditLoop) {
|
|
11627
|
+
result.audit = await auditLoop.tick();
|
|
11628
|
+
}
|
|
11629
|
+
if (traceLoop) {
|
|
11630
|
+
result.trace = await traceLoop.tick();
|
|
11631
|
+
}
|
|
11632
|
+
return result;
|
|
11633
|
+
},
|
|
11634
|
+
trace
|
|
11635
|
+
};
|
|
11636
|
+
};
|
|
11637
|
+
var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
11638
|
+
checkedAt: Date.now(),
|
|
11639
|
+
isRunning: runtime.isRunning(),
|
|
11640
|
+
summary: await runtime.summarize()
|
|
11641
|
+
});
|
|
11642
|
+
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
11643
|
+
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
11644
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml15(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
11645
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(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}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}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}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml15(title)}</h1><p class="muted">Inspect queue summaries and manually tick audit and trace delivery workers from one runtime primitive.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml15(new Date(report.checkedAt).toLocaleString())}</p>${tickForm}</section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card"><h2>Runtime shape</h2><pre>const runtime = createVoiceDeliveryRuntime({ audit, trace })
|
|
11646
|
+
|
|
11647
|
+
await runtime.tick()
|
|
11648
|
+
await runtime.summarize()</pre></section></main></body></html>`;
|
|
11649
|
+
};
|
|
11650
|
+
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
11651
|
+
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
11652
|
+
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
11653
|
+
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
11654
|
+
const routes = new Elysia12({
|
|
11655
|
+
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
11656
|
+
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
11657
|
+
if (tickPath !== false) {
|
|
11658
|
+
routes.post(tickPath, async () => ({
|
|
11659
|
+
drainedAt: Date.now(),
|
|
11660
|
+
result: await options.runtime.tick(),
|
|
11661
|
+
summary: await options.runtime.summarize()
|
|
11662
|
+
}));
|
|
11663
|
+
}
|
|
11664
|
+
if (htmlPath !== false) {
|
|
11665
|
+
routes.get(htmlPath, async () => {
|
|
11666
|
+
const report = await buildVoiceDeliveryRuntimeReport(options.runtime);
|
|
11667
|
+
const body = await (options.render ?? renderVoiceDeliveryRuntimeHTML)(report, {
|
|
11668
|
+
tickPath,
|
|
11669
|
+
title: options.title
|
|
11670
|
+
});
|
|
11671
|
+
return new Response(body, {
|
|
11672
|
+
headers: {
|
|
11673
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
11674
|
+
...options.headers
|
|
11675
|
+
}
|
|
11676
|
+
});
|
|
11677
|
+
});
|
|
11678
|
+
}
|
|
11679
|
+
return routes;
|
|
11680
|
+
};
|
|
11567
11681
|
// src/dataControl.ts
|
|
11568
11682
|
var allRetentionScopes = [
|
|
11569
11683
|
"auditDeliveries",
|
|
@@ -11767,16 +11881,16 @@ var applyVoiceDataRetentionPolicy = async (options) => {
|
|
|
11767
11881
|
};
|
|
11768
11882
|
var buildVoiceDataRetentionPlan = (options) => applyVoiceDataRetentionPolicy({ ...options, dryRun: true });
|
|
11769
11883
|
// src/evalRoutes.ts
|
|
11770
|
-
import { Elysia as
|
|
11884
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
11771
11885
|
import { mkdir } from "fs/promises";
|
|
11772
11886
|
import { dirname } from "path";
|
|
11773
11887
|
|
|
11774
11888
|
// src/qualityRoutes.ts
|
|
11775
|
-
import { Elysia as
|
|
11889
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
11776
11890
|
|
|
11777
11891
|
// src/handoffHealth.ts
|
|
11778
|
-
import { Elysia as
|
|
11779
|
-
var
|
|
11892
|
+
import { Elysia as Elysia13 } from "elysia";
|
|
11893
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11780
11894
|
var getString6 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
11781
11895
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
11782
11896
|
var increment3 = (record, key) => {
|
|
@@ -11894,10 +12008,10 @@ var renderActionSummary = (summary) => {
|
|
|
11894
12008
|
return [
|
|
11895
12009
|
'<section class="voice-handoff-health-columns">',
|
|
11896
12010
|
"<article><h3>Actions</h3>",
|
|
11897
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
12011
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml16(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
11898
12012
|
"</article>",
|
|
11899
12013
|
"<article><h3>Adapters</h3>",
|
|
11900
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
12014
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml16(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
11901
12015
|
"</article>",
|
|
11902
12016
|
"</section>"
|
|
11903
12017
|
].join("");
|
|
@@ -11911,22 +12025,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
11911
12025
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
11912
12026
|
'<div class="voice-handoff-health-events">',
|
|
11913
12027
|
...summary.events.map((event) => [
|
|
11914
|
-
`<article class="${
|
|
12028
|
+
`<article class="${escapeHtml16(event.status)}">`,
|
|
11915
12029
|
'<div class="voice-handoff-health-event-header">',
|
|
11916
|
-
`<strong>${
|
|
11917
|
-
`<span>${
|
|
12030
|
+
`<strong>${escapeHtml16(event.action ?? "handoff")}</strong>`,
|
|
12031
|
+
`<span>${escapeHtml16(event.status)}</span>`,
|
|
11918
12032
|
"</div>",
|
|
11919
|
-
`<p><small>${
|
|
11920
|
-
event.target ? `<p>Target: ${
|
|
11921
|
-
event.reason ? `<p>Reason: ${
|
|
12033
|
+
`<p><small>${escapeHtml16(event.sessionId)}</small></p>`,
|
|
12034
|
+
event.target ? `<p>Target: ${escapeHtml16(event.target)}</p>` : "",
|
|
12035
|
+
event.reason ? `<p>Reason: ${escapeHtml16(event.reason)}</p>` : "",
|
|
11922
12036
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
11923
12037
|
"<li>",
|
|
11924
|
-
`${
|
|
11925
|
-
delivery.deliveredTo ? ` to ${
|
|
11926
|
-
delivery.error ? ` (${
|
|
12038
|
+
`${escapeHtml16(delivery.adapterId)}: ${escapeHtml16(delivery.status)}`,
|
|
12039
|
+
delivery.deliveredTo ? ` to ${escapeHtml16(delivery.deliveredTo)}` : "",
|
|
12040
|
+
delivery.error ? ` (${escapeHtml16(delivery.error)})` : "",
|
|
11927
12041
|
"</li>"
|
|
11928
12042
|
].join("")).join("")}</ul>` : "",
|
|
11929
|
-
event.replayHref ? `<p><a href="${
|
|
12043
|
+
event.replayHref ? `<p><a href="${escapeHtml16(event.replayHref)}">Open replay</a></p>` : "",
|
|
11930
12044
|
"</article>"
|
|
11931
12045
|
].join("")),
|
|
11932
12046
|
"</div>"
|
|
@@ -11958,7 +12072,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
11958
12072
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
11959
12073
|
const path = options.path ?? "/api/voice-handoffs";
|
|
11960
12074
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
11961
|
-
const routes = new
|
|
12075
|
+
const routes = new Elysia13({
|
|
11962
12076
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
11963
12077
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
11964
12078
|
if (htmlPath) {
|
|
@@ -12079,17 +12193,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
12079
12193
|
thresholds
|
|
12080
12194
|
};
|
|
12081
12195
|
};
|
|
12082
|
-
var
|
|
12196
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12083
12197
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
12084
12198
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
12085
12199
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
12086
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
12087
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
12200
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml17(metric.label)}</td><td>${escapeHtml17(formatMetricValue(metric))}</td><td>${escapeHtml17(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml17(key)}</code></td></tr>`).join("");
|
|
12201
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml17(link.href)}">${escapeHtml17(link.label)}</a>`).join("")}</nav>` : "";
|
|
12088
12202
|
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>`;
|
|
12089
12203
|
};
|
|
12090
12204
|
var createVoiceQualityRoutes = (options) => {
|
|
12091
12205
|
const path = options.path ?? "/quality";
|
|
12092
|
-
const routes = new
|
|
12206
|
+
const routes = new Elysia14({
|
|
12093
12207
|
name: options.name ?? "absolutejs-voice-quality"
|
|
12094
12208
|
});
|
|
12095
12209
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -12118,7 +12232,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
12118
12232
|
};
|
|
12119
12233
|
|
|
12120
12234
|
// src/evalRoutes.ts
|
|
12121
|
-
var
|
|
12235
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12122
12236
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
12123
12237
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
12124
12238
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -12427,44 +12541,44 @@ var formatTime = (value) => value === undefined ? "unknown" : new Date(value).to
|
|
|
12427
12541
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
12428
12542
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
12429
12543
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
12430
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
12431
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
12544
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
|
|
12545
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml18(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>';
|
|
12432
12546
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
12433
12547
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
12434
|
-
return `<tr class="${session.status}"><td>${
|
|
12548
|
+
return `<tr class="${session.status}"><td>${escapeHtml18(session.sessionId)}</td><td>${escapeHtml18(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml18(formatTime(session.endedAt))}</td><td>${escapeHtml18(failedMetrics || "none")}</td></tr>`;
|
|
12435
12549
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
12436
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12550
|
+
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{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}.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{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.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>${escapeHtml18(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><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>`;
|
|
12437
12551
|
};
|
|
12438
12552
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
12439
12553
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
12440
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
12441
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
12442
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
12443
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
12444
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12554
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
|
|
12555
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml18(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
12556
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml18(id)}</li>`).join("") : "<li>none</li>";
|
|
12557
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml18(id)}</li>`).join("") : "<li>none</li>";
|
|
12558
|
+
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{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>${escapeHtml18(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml18(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml18(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>${escapeHtml18(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>`;
|
|
12445
12559
|
};
|
|
12446
12560
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
12447
12561
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
12448
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
12562
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
|
|
12449
12563
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
12450
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
12451
|
-
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${
|
|
12452
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
12564
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml18(issue)}</li>`).join("")}</ul>` : "";
|
|
12565
|
+
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml18(session.sessionId)}</td><td>${escapeHtml18(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml18(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
12566
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml18(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml18(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>`;
|
|
12453
12567
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
12454
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12568
|
+
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{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}.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}.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>${escapeHtml18(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>${scenarios}</main></body></html>`;
|
|
12455
12569
|
};
|
|
12456
12570
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
12457
12571
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
12458
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
12572
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
|
|
12459
12573
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
12460
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
12461
|
-
return `<section class="${fixture.status}"><h2>${
|
|
12574
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml18(scenario.label)}</td><td>${escapeHtml18(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml18([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
12575
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml18(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml18(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>`;
|
|
12462
12576
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
12463
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12577
|
+
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{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}.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}.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>${escapeHtml18(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>${fixtures}</main></body></html>`;
|
|
12464
12578
|
};
|
|
12465
12579
|
var createVoiceEvalRoutes = (options) => {
|
|
12466
12580
|
const path = options.path ?? "/evals";
|
|
12467
|
-
const routes = new
|
|
12581
|
+
const routes = new Elysia15({
|
|
12468
12582
|
name: options.name ?? "absolutejs-voice-evals"
|
|
12469
12583
|
});
|
|
12470
12584
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -12598,11 +12712,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
12598
12712
|
return routes;
|
|
12599
12713
|
};
|
|
12600
12714
|
// src/simulationSuite.ts
|
|
12601
|
-
import { Elysia as
|
|
12715
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
12602
12716
|
|
|
12603
12717
|
// src/outcomeContract.ts
|
|
12604
|
-
import { Elysia as
|
|
12605
|
-
var
|
|
12718
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12719
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12606
12720
|
var getPayloadString = (event, key) => typeof event.payload[key] === "string" ? event.payload[key] : undefined;
|
|
12607
12721
|
var toList = async (input) => Array.isArray(input) ? input : await input?.list() ?? [];
|
|
12608
12722
|
var hydrateSessions = async (input) => {
|
|
@@ -12710,9 +12824,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
12710
12824
|
const contracts = report.contracts.map((contract) => `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
12711
12825
|
<div class="contract-header">
|
|
12712
12826
|
<div>
|
|
12713
|
-
<p class="eyebrow">${
|
|
12714
|
-
<h2>${
|
|
12715
|
-
${contract.description ? `<p>${
|
|
12827
|
+
<p class="eyebrow">${escapeHtml19(contract.contractId)}</p>
|
|
12828
|
+
<h2>${escapeHtml19(contract.label ?? contract.contractId)}</h2>
|
|
12829
|
+
${contract.description ? `<p>${escapeHtml19(contract.description)}</p>` : ""}
|
|
12716
12830
|
</div>
|
|
12717
12831
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
12718
12832
|
</div>
|
|
@@ -12723,9 +12837,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
12723
12837
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
12724
12838
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
12725
12839
|
</div>
|
|
12726
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
12840
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml19(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
12727
12841
|
</section>`).join("");
|
|
12728
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12842
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(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>`;
|
|
12729
12843
|
};
|
|
12730
12844
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
12731
12845
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -12741,7 +12855,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
12741
12855
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
12742
12856
|
const path = options.path ?? "/api/outcome-contracts";
|
|
12743
12857
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
12744
|
-
const routes = new
|
|
12858
|
+
const routes = new Elysia16({
|
|
12745
12859
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
12746
12860
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
12747
12861
|
if (htmlPath) {
|
|
@@ -12751,7 +12865,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
12751
12865
|
};
|
|
12752
12866
|
|
|
12753
12867
|
// src/toolContract.ts
|
|
12754
|
-
import { Elysia as
|
|
12868
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
12755
12869
|
|
|
12756
12870
|
// src/toolRuntime.ts
|
|
12757
12871
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -12960,7 +13074,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
12960
13074
|
});
|
|
12961
13075
|
var defaultApi = {};
|
|
12962
13076
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
12963
|
-
var
|
|
13077
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12964
13078
|
var evaluateExpectation = (input) => {
|
|
12965
13079
|
const issues = [];
|
|
12966
13080
|
const expect = input.expect;
|
|
@@ -13126,19 +13240,19 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
13126
13240
|
const title = options.title ?? "Voice Tool Contracts";
|
|
13127
13241
|
const contracts = report.contracts.map((contract) => {
|
|
13128
13242
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
13129
|
-
<td>${
|
|
13243
|
+
<td>${escapeHtml20(testCase.label ?? testCase.caseId)}</td>
|
|
13130
13244
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
13131
|
-
<td>${
|
|
13245
|
+
<td>${escapeHtml20(testCase.status)}</td>
|
|
13132
13246
|
<td>${String(testCase.attempts)}</td>
|
|
13133
13247
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
13134
13248
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
13135
|
-
<td>${
|
|
13249
|
+
<td>${escapeHtml20(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
13136
13250
|
</tr>`).join("");
|
|
13137
13251
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
13138
13252
|
<div class="contract-header">
|
|
13139
13253
|
<div>
|
|
13140
|
-
<p class="eyebrow">${
|
|
13141
|
-
<h2>${
|
|
13254
|
+
<p class="eyebrow">${escapeHtml20(contract.toolName)}</p>
|
|
13255
|
+
<h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
|
|
13142
13256
|
</div>
|
|
13143
13257
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
13144
13258
|
</div>
|
|
@@ -13148,7 +13262,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
13148
13262
|
</table>
|
|
13149
13263
|
</section>`;
|
|
13150
13264
|
}).join("");
|
|
13151
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13265
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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(245,158,11,.12))}.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)}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>${escapeHtml20(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml20(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 tool contracts configured.</p></section>'}</main></body></html>`;
|
|
13152
13266
|
};
|
|
13153
13267
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
13154
13268
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -13165,7 +13279,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
13165
13279
|
var createVoiceToolContractRoutes = (options) => {
|
|
13166
13280
|
const path = options.path ?? "/api/tool-contracts";
|
|
13167
13281
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
13168
|
-
const routes = new
|
|
13282
|
+
const routes = new Elysia17({
|
|
13169
13283
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
13170
13284
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
13171
13285
|
if (htmlPath) {
|
|
@@ -13175,7 +13289,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
13175
13289
|
};
|
|
13176
13290
|
|
|
13177
13291
|
// src/simulationSuite.ts
|
|
13178
|
-
var
|
|
13292
|
+
var escapeHtml21 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13179
13293
|
var summarizeSection = (report) => ({
|
|
13180
13294
|
failed: report.failed,
|
|
13181
13295
|
passed: report.passed,
|
|
@@ -13311,20 +13425,20 @@ var renderSection = (label, summary) => {
|
|
|
13311
13425
|
if (!summary) {
|
|
13312
13426
|
return "";
|
|
13313
13427
|
}
|
|
13314
|
-
return `<article class="${
|
|
13428
|
+
return `<article class="${escapeHtml21(summary.status)}"><span>${escapeHtml21(label)}</span><strong>${escapeHtml21(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
13315
13429
|
};
|
|
13316
13430
|
var renderAction = (action) => {
|
|
13317
|
-
const content = `<strong>${
|
|
13318
|
-
return action.href ? `<a class="action" href="${
|
|
13431
|
+
const content = `<strong>${escapeHtml21(action.label)}</strong><p>${escapeHtml21(action.description)}</p><span>${escapeHtml21(action.section)} / ${escapeHtml21(action.severity)}</span>`;
|
|
13432
|
+
return action.href ? `<a class="action" href="${escapeHtml21(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
13319
13433
|
};
|
|
13320
13434
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
13321
13435
|
const title = options.title ?? "Voice Simulation Suite";
|
|
13322
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13436
|
+
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{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero{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}.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{color:#d8dee6;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml21(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml21(report.status)}">Status: ${escapeHtml21(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><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>${escapeHtml21(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
13323
13437
|
};
|
|
13324
13438
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
13325
13439
|
const path = options.path ?? "/api/voice/simulations";
|
|
13326
13440
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
13327
|
-
const app = new
|
|
13441
|
+
const app = new Elysia18({
|
|
13328
13442
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
13329
13443
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
13330
13444
|
if (htmlPath) {
|
|
@@ -13636,9 +13750,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
13636
13750
|
};
|
|
13637
13751
|
};
|
|
13638
13752
|
// src/sessionReplay.ts
|
|
13639
|
-
import { Elysia as
|
|
13753
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13640
13754
|
var getString9 = (value) => typeof value === "string" ? value : undefined;
|
|
13641
|
-
var
|
|
13755
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13642
13756
|
var increment4 = (record, key) => {
|
|
13643
13757
|
record[key] = (record[key] ?? 0) + 1;
|
|
13644
13758
|
};
|
|
@@ -13818,10 +13932,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
13818
13932
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
13819
13933
|
'<div class="voice-sessions-list">',
|
|
13820
13934
|
...sessions.map((session) => [
|
|
13821
|
-
`<article class="voice-session-card ${
|
|
13935
|
+
`<article class="voice-session-card ${escapeHtml22(session.status)}">`,
|
|
13822
13936
|
'<div class="voice-session-card-header">',
|
|
13823
|
-
`<strong>${
|
|
13824
|
-
`<span>${
|
|
13937
|
+
`<strong>${escapeHtml22(session.sessionId)}</strong>`,
|
|
13938
|
+
`<span>${escapeHtml22(session.status)}</span>`,
|
|
13825
13939
|
"</div>",
|
|
13826
13940
|
"<dl>",
|
|
13827
13941
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -13829,9 +13943,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
13829
13943
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
13830
13944
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
13831
13945
|
"</dl>",
|
|
13832
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
13833
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
13834
|
-
session.replayHref ? `<p><a href="${
|
|
13946
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml22(session.latestOutcome)}</p>` : "",
|
|
13947
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml22).join(", ")}</p>` : "",
|
|
13948
|
+
session.replayHref ? `<p><a href="${escapeHtml22(session.replayHref)}">Open replay</a></p>` : "",
|
|
13835
13949
|
"</article>"
|
|
13836
13950
|
].join("")),
|
|
13837
13951
|
"</div>"
|
|
@@ -13862,7 +13976,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
13862
13976
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
13863
13977
|
const path = options.path ?? "/api/voice-sessions";
|
|
13864
13978
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
13865
|
-
const routes = new
|
|
13979
|
+
const routes = new Elysia19({
|
|
13866
13980
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
13867
13981
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
13868
13982
|
if (htmlPath) {
|
|
@@ -13890,7 +14004,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
13890
14004
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
13891
14005
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
13892
14006
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
13893
|
-
const routes = new
|
|
14007
|
+
const routes = new Elysia19({
|
|
13894
14008
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
13895
14009
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
13896
14010
|
if (htmlPath) {
|
|
@@ -14057,10 +14171,10 @@ var assertVoiceAgentSquadContract = async (options) => {
|
|
|
14057
14171
|
return report;
|
|
14058
14172
|
};
|
|
14059
14173
|
// src/turnLatency.ts
|
|
14060
|
-
import { Elysia as
|
|
14174
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
14061
14175
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
14062
14176
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
14063
|
-
var
|
|
14177
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14064
14178
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
14065
14179
|
var getString10 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
14066
14180
|
var createTraceStageIndex = (events) => {
|
|
@@ -14174,11 +14288,11 @@ var summarizeVoiceTurnLatency = async (options) => {
|
|
|
14174
14288
|
var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
14175
14289
|
var renderVoiceTurnLatencyHTML = (report, options = {}) => {
|
|
14176
14290
|
const title = options.title ?? "Voice Turn Latency";
|
|
14177
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
14178
|
-
<header><div><p class="eyebrow">${
|
|
14179
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
14291
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml23(turn.status)}">
|
|
14292
|
+
<header><div><p class="eyebrow">${escapeHtml23(turn.sessionId)} \xB7 ${escapeHtml23(turn.turnId)}</p><h2>${escapeHtml23(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml23(turn.status)}</strong></header>
|
|
14293
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml23(stage.label)}</dt><dd>${escapeHtml23(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
14180
14294
|
</article>`).join("");
|
|
14181
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14295
|
+
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,.turn{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}.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>${escapeHtml23(title)}</h1><div class="summary"><span class="pill ${escapeHtml23(report.status)}">${escapeHtml23(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml23(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
14182
14296
|
};
|
|
14183
14297
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
14184
14298
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -14195,7 +14309,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
14195
14309
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
14196
14310
|
const path = options.path ?? "/api/turn-latency";
|
|
14197
14311
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
14198
|
-
const routes = new
|
|
14312
|
+
const routes = new Elysia20({
|
|
14199
14313
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
14200
14314
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
14201
14315
|
if (htmlPath) {
|
|
@@ -14204,8 +14318,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
14204
14318
|
return routes;
|
|
14205
14319
|
};
|
|
14206
14320
|
// src/liveLatency.ts
|
|
14207
|
-
import { Elysia as
|
|
14208
|
-
var
|
|
14321
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14322
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14209
14323
|
var percentile = (values, percentileValue) => {
|
|
14210
14324
|
if (values.length === 0) {
|
|
14211
14325
|
return;
|
|
@@ -14253,13 +14367,13 @@ var summarizeVoiceLiveLatency = async (options) => {
|
|
|
14253
14367
|
var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
14254
14368
|
var renderVoiceLiveLatencyHTML = (report, options = {}) => {
|
|
14255
14369
|
const title = options.title ?? "Voice Live Latency";
|
|
14256
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
14257
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14370
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml24(sample.sessionId)}</td><td>${escapeHtml24(formatMs2(sample.latencyMs))}</td><td>${escapeHtml24(sample.status ?? "unknown")}</td><td>${escapeHtml24(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
14371
|
+
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:#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{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}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>${escapeHtml24(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml24(report.status)}">Status: ${escapeHtml24(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml24(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml24(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml24(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></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>`;
|
|
14258
14372
|
};
|
|
14259
14373
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
14260
14374
|
const path = options.path ?? "/api/live-latency";
|
|
14261
14375
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
14262
|
-
const routes = new
|
|
14376
|
+
const routes = new Elysia21({
|
|
14263
14377
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
14264
14378
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
14265
14379
|
if (htmlPath) {
|
|
@@ -14276,9 +14390,9 @@ var createVoiceLiveLatencyRoutes = (options) => {
|
|
|
14276
14390
|
return routes;
|
|
14277
14391
|
};
|
|
14278
14392
|
// src/turnQuality.ts
|
|
14279
|
-
import { Elysia as
|
|
14393
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14280
14394
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
14281
|
-
var
|
|
14395
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14282
14396
|
var getTurnLatencyMs = (turn) => {
|
|
14283
14397
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
14284
14398
|
if (firstTranscriptAt === undefined) {
|
|
@@ -14349,24 +14463,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
14349
14463
|
};
|
|
14350
14464
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
14351
14465
|
const title = options.title ?? "Voice Turn Quality";
|
|
14352
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
14466
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml25(turn.status)}">
|
|
14353
14467
|
<div class="turn-header">
|
|
14354
14468
|
<div>
|
|
14355
|
-
<p class="eyebrow">${
|
|
14356
|
-
<h2>${
|
|
14469
|
+
<p class="eyebrow">${escapeHtml25(turn.sessionId)} \xB7 ${escapeHtml25(turn.turnId)}</p>
|
|
14470
|
+
<h2>${escapeHtml25(turn.text || "Empty turn")}</h2>
|
|
14357
14471
|
</div>
|
|
14358
|
-
<strong>${
|
|
14472
|
+
<strong>${escapeHtml25(turn.status)}</strong>
|
|
14359
14473
|
</div>
|
|
14360
14474
|
<dl>
|
|
14361
|
-
<div><dt>Source</dt><dd>${
|
|
14475
|
+
<div><dt>Source</dt><dd>${escapeHtml25(turn.source ?? "unknown")}</dd></div>
|
|
14362
14476
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
14363
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
14364
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
14477
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml25(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
14478
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml25(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
14365
14479
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
14366
14480
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
14367
14481
|
</dl>
|
|
14368
14482
|
</article>`).join("");
|
|
14369
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14483
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{background:#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>${escapeHtml25(title)}</h1><div class="summary"><span class="pill ${escapeHtml25(report.status)}">${escapeHtml25(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>`;
|
|
14370
14484
|
};
|
|
14371
14485
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
14372
14486
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -14383,7 +14497,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
14383
14497
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
14384
14498
|
const path = options.path ?? "/api/turn-quality";
|
|
14385
14499
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
14386
|
-
const routes = new
|
|
14500
|
+
const routes = new Elysia22({
|
|
14387
14501
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
14388
14502
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
14389
14503
|
if (htmlPath) {
|
|
@@ -14392,7 +14506,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
14392
14506
|
return routes;
|
|
14393
14507
|
};
|
|
14394
14508
|
// src/telephonyOutcome.ts
|
|
14395
|
-
import { Elysia as
|
|
14509
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
14396
14510
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
14397
14511
|
"answered",
|
|
14398
14512
|
"completed",
|
|
@@ -15042,7 +15156,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
15042
15156
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
15043
15157
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
15044
15158
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
15045
|
-
return new
|
|
15159
|
+
return new Elysia23({
|
|
15046
15160
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
15047
15161
|
}).post(path, async ({ query, request }) => {
|
|
15048
15162
|
try {
|
|
@@ -15063,11 +15177,11 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
15063
15177
|
});
|
|
15064
15178
|
};
|
|
15065
15179
|
// src/phoneAgent.ts
|
|
15066
|
-
import { Elysia as
|
|
15180
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
15067
15181
|
|
|
15068
15182
|
// src/telephony/plivo.ts
|
|
15069
15183
|
import { Buffer as Buffer5 } from "buffer";
|
|
15070
|
-
import { Elysia as
|
|
15184
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15071
15185
|
|
|
15072
15186
|
// src/telephony/contract.ts
|
|
15073
15187
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -15151,7 +15265,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
15151
15265
|
|
|
15152
15266
|
// src/telephony/twilio.ts
|
|
15153
15267
|
import { Buffer as Buffer4 } from "buffer";
|
|
15154
|
-
import { Elysia as
|
|
15268
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15155
15269
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
15156
15270
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
15157
15271
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -15181,7 +15295,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
15181
15295
|
return parameters;
|
|
15182
15296
|
};
|
|
15183
15297
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
15184
|
-
var
|
|
15298
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
15185
15299
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
15186
15300
|
if (!webhook?.verificationUrl) {
|
|
15187
15301
|
return;
|
|
@@ -15224,23 +15338,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
15224
15338
|
};
|
|
15225
15339
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
15226
15340
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
15227
|
-
<h1>${
|
|
15341
|
+
<h1>${escapeHtml26(title)}</h1>
|
|
15228
15342
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
15229
15343
|
<section>
|
|
15230
15344
|
<h2>URLs</h2>
|
|
15231
15345
|
<ul>
|
|
15232
|
-
<li><strong>TwiML:</strong> <code>${
|
|
15233
|
-
<li><strong>Media stream:</strong> <code>${
|
|
15234
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
15346
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml26(status.urls.twiml)}</code></li>
|
|
15347
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml26(status.urls.stream)}</code></li>
|
|
15348
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml26(status.urls.webhook)}</code></li>
|
|
15235
15349
|
</ul>
|
|
15236
15350
|
</section>
|
|
15237
15351
|
<section>
|
|
15238
15352
|
<h2>Signing</h2>
|
|
15239
15353
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
15240
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
15354
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml26(status.signing.verificationUrl)}</code></p>` : ""}
|
|
15241
15355
|
</section>
|
|
15242
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
15243
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
15356
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml26(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
15357
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml26(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
15244
15358
|
</main>`;
|
|
15245
15359
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
15246
15360
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -15251,20 +15365,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
15251
15365
|
});
|
|
15252
15366
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
15253
15367
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
15254
|
-
<h1>${
|
|
15368
|
+
<h1>${escapeHtml26(title)}</h1>
|
|
15255
15369
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
15256
15370
|
<section>
|
|
15257
15371
|
<h2>Checks</h2>
|
|
15258
15372
|
<ul>
|
|
15259
|
-
${report.checks.map((check) => `<li><strong>${
|
|
15373
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml26(check.name)}</strong>: ${escapeHtml26(check.status)}${check.message ? ` - ${escapeHtml26(check.message)}` : ""}</li>`).join("")}
|
|
15260
15374
|
</ul>
|
|
15261
15375
|
</section>
|
|
15262
15376
|
<section>
|
|
15263
15377
|
<h2>Observed URLs</h2>
|
|
15264
15378
|
<ul>
|
|
15265
|
-
<li><strong>TwiML:</strong> <code>${
|
|
15266
|
-
<li><strong>Stream:</strong> <code>${
|
|
15267
|
-
<li><strong>Webhook:</strong> <code>${
|
|
15379
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml26(report.setup.urls.twiml)}</code></li>
|
|
15380
|
+
<li><strong>Stream:</strong> <code>${escapeHtml26(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
15381
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml26(report.setup.urls.webhook)}</code></li>
|
|
15268
15382
|
</ul>
|
|
15269
15383
|
</section>
|
|
15270
15384
|
</main>`;
|
|
@@ -15724,7 +15838,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
15724
15838
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
15725
15839
|
const bridges = new WeakMap;
|
|
15726
15840
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
15727
|
-
const app = new
|
|
15841
|
+
const app = new Elysia24({
|
|
15728
15842
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
15729
15843
|
}).get(twimlPath, async ({ query, request }) => {
|
|
15730
15844
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -15861,7 +15975,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
15861
15975
|
|
|
15862
15976
|
// src/telephony/plivo.ts
|
|
15863
15977
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
15864
|
-
var
|
|
15978
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
15865
15979
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
15866
15980
|
var resolveRequestOrigin2 = (request) => {
|
|
15867
15981
|
const url = new URL(request.url);
|
|
@@ -16112,21 +16226,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
16112
16226
|
};
|
|
16113
16227
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
16114
16228
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
16115
|
-
<h1>${
|
|
16229
|
+
<h1>${escapeHtml27(title)}</h1>
|
|
16116
16230
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
16117
16231
|
<ul>
|
|
16118
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
16119
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
16120
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
16232
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml27(status.urls.answer)}</code></li>
|
|
16233
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml27(status.urls.stream)}</code></li>
|
|
16234
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml27(status.urls.webhook)}</code></li>
|
|
16121
16235
|
</ul>
|
|
16122
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
16123
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
16236
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml27(name)}</code></li>`).join("")}</ul>` : ""}
|
|
16237
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml27(warning)}</li>`).join("")}</ul>` : ""}
|
|
16124
16238
|
</main>`;
|
|
16125
16239
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
16126
16240
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
16127
|
-
<h1>${
|
|
16241
|
+
<h1>${escapeHtml27(title)}</h1>
|
|
16128
16242
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
16129
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
16243
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml27(check.name)}</strong>: ${escapeHtml27(check.status)}${check.message ? ` - ${escapeHtml27(check.message)}` : ""}</li>`).join("")}</ul>
|
|
16130
16244
|
</main>`;
|
|
16131
16245
|
var runPlivoSmokeTest = async (input) => {
|
|
16132
16246
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -16221,7 +16335,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
16221
16335
|
request: input.request
|
|
16222
16336
|
}) : verificationUrl ?? input.request.url
|
|
16223
16337
|
}) : undefined);
|
|
16224
|
-
const app = new
|
|
16338
|
+
const app = new Elysia25({
|
|
16225
16339
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
16226
16340
|
}).get(answerPath, async ({ query, request }) => {
|
|
16227
16341
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -16332,9 +16446,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
16332
16446
|
|
|
16333
16447
|
// src/telephony/telnyx.ts
|
|
16334
16448
|
import { Buffer as Buffer6 } from "buffer";
|
|
16335
|
-
import { Elysia as
|
|
16449
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
16336
16450
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
16337
|
-
var
|
|
16451
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
16338
16452
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
16339
16453
|
var resolveRequestOrigin3 = (request) => {
|
|
16340
16454
|
const url = new URL(request.url);
|
|
@@ -16535,21 +16649,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
16535
16649
|
};
|
|
16536
16650
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
16537
16651
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
16538
|
-
<h1>${
|
|
16652
|
+
<h1>${escapeHtml28(title)}</h1>
|
|
16539
16653
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
16540
16654
|
<ul>
|
|
16541
|
-
<li><strong>TeXML:</strong> <code>${
|
|
16542
|
-
<li><strong>Media stream:</strong> <code>${
|
|
16543
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
16655
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml28(status.urls.texml)}</code></li>
|
|
16656
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
|
|
16657
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
|
|
16544
16658
|
</ul>
|
|
16545
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
16546
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
16659
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul>` : ""}
|
|
16660
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul>` : ""}
|
|
16547
16661
|
</main>`;
|
|
16548
16662
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
16549
16663
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
16550
|
-
<h1>${
|
|
16664
|
+
<h1>${escapeHtml28(title)}</h1>
|
|
16551
16665
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
16552
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
16666
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}</ul>
|
|
16553
16667
|
</main>`;
|
|
16554
16668
|
var runTelnyxSmokeTest = async (input) => {
|
|
16555
16669
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -16643,7 +16757,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
16643
16757
|
publicKey: options.webhook?.publicKey,
|
|
16644
16758
|
toleranceSeconds: options.webhook?.toleranceSeconds
|
|
16645
16759
|
}) : undefined);
|
|
16646
|
-
const app = new
|
|
16760
|
+
const app = new Elysia26({
|
|
16647
16761
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
16648
16762
|
}).get(texmlPath, async ({ query, request }) => {
|
|
16649
16763
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -16753,8 +16867,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
16753
16867
|
};
|
|
16754
16868
|
|
|
16755
16869
|
// src/telephony/matrix.ts
|
|
16756
|
-
import { Elysia as
|
|
16757
|
-
var
|
|
16870
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16871
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
16758
16872
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
16759
16873
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
16760
16874
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -16815,13 +16929,13 @@ var badgeStyles = {
|
|
|
16815
16929
|
};
|
|
16816
16930
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
16817
16931
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
16818
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
16932
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml29(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
16819
16933
|
<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>
|
|
16820
16934
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
16821
16935
|
${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);">
|
|
16822
16936
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
16823
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
16824
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
16937
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml29(entry.name)}</h2>
|
|
16938
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml29(entry.status.toUpperCase())}</span>
|
|
16825
16939
|
</div>
|
|
16826
16940
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
16827
16941
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -16829,15 +16943,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
16829
16943
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
16830
16944
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
16831
16945
|
</dl>
|
|
16832
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
16833
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
16834
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
16946
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml29(entry.setup.urls.stream || "missing")}</code></p>
|
|
16947
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml29(entry.setup.urls.webhook || "missing")}</code></p>
|
|
16948
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml29(issue.severity)}: ${escapeHtml29(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
16835
16949
|
</article>`).join("")}
|
|
16836
16950
|
</section>
|
|
16837
16951
|
</main>`;
|
|
16838
16952
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
16839
16953
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
16840
|
-
return new
|
|
16954
|
+
return new Elysia27({
|
|
16841
16955
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
16842
16956
|
}).get(path, async ({ query, request }) => {
|
|
16843
16957
|
const providers = await options.load({ query, request });
|
|
@@ -16859,7 +16973,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
16859
16973
|
};
|
|
16860
16974
|
|
|
16861
16975
|
// src/phoneAgentProductionSmoke.ts
|
|
16862
|
-
import { Elysia as
|
|
16976
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16863
16977
|
var defaultRequirements = [
|
|
16864
16978
|
"media-started",
|
|
16865
16979
|
"transcript",
|
|
@@ -16867,7 +16981,7 @@ var defaultRequirements = [
|
|
|
16867
16981
|
"lifecycle-outcome",
|
|
16868
16982
|
"no-session-error"
|
|
16869
16983
|
];
|
|
16870
|
-
var
|
|
16984
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16871
16985
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
16872
16986
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
16873
16987
|
const value = event.payload[key];
|
|
@@ -16976,10 +17090,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
16976
17090
|
});
|
|
16977
17091
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
16978
17092
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
16979
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
16980
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
16981
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
16982
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17093
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml30(issue.requirement)}</strong>: ${escapeHtml30(issue.message)}</li>`).join("");
|
|
17094
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml30(outcome)}</span>`).join("");
|
|
17095
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml30(requirement)}</span>`).join("");
|
|
17096
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{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>${escapeHtml30(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml30(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml30(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml30(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>`;
|
|
16983
17097
|
};
|
|
16984
17098
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
16985
17099
|
query,
|
|
@@ -17002,7 +17116,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
17002
17116
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
17003
17117
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
17004
17118
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
17005
|
-
const routes = new
|
|
17119
|
+
const routes = new Elysia28({
|
|
17006
17120
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
17007
17121
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
17008
17122
|
if (htmlPath) {
|
|
@@ -17045,7 +17159,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
17045
17159
|
"completed",
|
|
17046
17160
|
"failed"
|
|
17047
17161
|
];
|
|
17048
|
-
var
|
|
17162
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
17049
17163
|
var loadRouteJson = async (input) => {
|
|
17050
17164
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
17051
17165
|
headers: {
|
|
@@ -17105,18 +17219,18 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
17105
17219
|
const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
|
|
17106
17220
|
const urls = entry?.setup.urls;
|
|
17107
17221
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
17108
|
-
return `<tr><td>${
|
|
17222
|
+
return `<tr><td>${escapeHtml31(carrier.name ?? carrier.provider)}</td><td>${escapeHtml31(carrier.provider)}</td><td><code>${escapeHtml31(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml31(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml31(entry.status)}">${escapeHtml31(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml31(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml31(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml31(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
17109
17223
|
}).join("");
|
|
17110
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
17224
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml31(stage)}</code></li>`).join("");
|
|
17111
17225
|
const checklist = report.carriers.map((carrier) => {
|
|
17112
17226
|
const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
|
|
17113
17227
|
const urls = entry?.setup.urls;
|
|
17114
17228
|
const answerLabel = carrier.provider === "telnyx" ? "TeXML URL" : carrier.provider === "plivo" ? "Answer URL" : "TwiML URL";
|
|
17115
17229
|
const answerUrl = urls?.twiml;
|
|
17116
|
-
const issueList = entry?.issues.map((issue) => `<li>${
|
|
17117
|
-
return `<article><h3>${
|
|
17230
|
+
const issueList = entry?.issues.map((issue) => `<li>${escapeHtml31(issue.severity)}: ${escapeHtml31(issue.message)}</li>`).join("") ?? "";
|
|
17231
|
+
return `<article><h3>${escapeHtml31(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml31(answerLabel)} to <code>${escapeHtml31(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml31(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml31(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml31(carrier.setupPath)}?format=html">${escapeHtml31(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml31(carrier.smokePath)}?format=html">${escapeHtml31(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml31(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml31(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
17118
17232
|
}).join("");
|
|
17119
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17233
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(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{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.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}.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>${escapeHtml31(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="${escapeHtml31(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</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>`;
|
|
17120
17234
|
};
|
|
17121
17235
|
var createVoicePhoneAgent = (options) => {
|
|
17122
17236
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -17125,7 +17239,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
17125
17239
|
setupPath: resolveSetupPath(carrier),
|
|
17126
17240
|
smokePath: resolveSmokePath(carrier)
|
|
17127
17241
|
}));
|
|
17128
|
-
const app = new
|
|
17242
|
+
const app = new Elysia29({
|
|
17129
17243
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
17130
17244
|
});
|
|
17131
17245
|
for (const carrier of options.carriers) {
|
|
@@ -19137,8 +19251,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
19137
19251
|
};
|
|
19138
19252
|
};
|
|
19139
19253
|
// src/providerCapabilities.ts
|
|
19140
|
-
import { Elysia as
|
|
19141
|
-
var
|
|
19254
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
19255
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19142
19256
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
19143
19257
|
configured: true,
|
|
19144
19258
|
features: options.features?.[provider],
|
|
@@ -19201,27 +19315,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
19201
19315
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
19202
19316
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
19203
19317
|
const cards = report.capabilities.map((capability) => {
|
|
19204
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
19205
|
-
return `<article class="card ${
|
|
19318
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml32(feature)}</span>`).join("");
|
|
19319
|
+
return `<article class="card ${escapeHtml32(capability.status)}">
|
|
19206
19320
|
<div class="card-header">
|
|
19207
19321
|
<div>
|
|
19208
|
-
<p class="eyebrow">${
|
|
19209
|
-
<h2>${
|
|
19322
|
+
<p class="eyebrow">${escapeHtml32(capability.kind)}</p>
|
|
19323
|
+
<h2>${escapeHtml32(capability.label ?? capability.provider)}</h2>
|
|
19210
19324
|
</div>
|
|
19211
|
-
<strong>${
|
|
19325
|
+
<strong>${escapeHtml32(capability.status)}</strong>
|
|
19212
19326
|
</div>
|
|
19213
|
-
${capability.description ? `<p>${
|
|
19327
|
+
${capability.description ? `<p>${escapeHtml32(capability.description)}</p>` : ""}
|
|
19214
19328
|
<dl>
|
|
19215
19329
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
19216
19330
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
19217
|
-
<div><dt>Model</dt><dd>${
|
|
19331
|
+
<div><dt>Model</dt><dd>${escapeHtml32(capability.model ?? "default")}</dd></div>
|
|
19218
19332
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
19219
19333
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
19220
19334
|
</dl>
|
|
19221
19335
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
19222
19336
|
</article>`;
|
|
19223
19337
|
}).join("");
|
|
19224
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19338
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.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>${escapeHtml32(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>`;
|
|
19225
19339
|
};
|
|
19226
19340
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
19227
19341
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -19238,7 +19352,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
19238
19352
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
19239
19353
|
const path = options.path ?? "/api/provider-capabilities";
|
|
19240
19354
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19241
|
-
const routes = new
|
|
19355
|
+
const routes = new Elysia30({
|
|
19242
19356
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
19243
19357
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
19244
19358
|
if (htmlPath) {
|
|
@@ -19247,8 +19361,8 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
19247
19361
|
return routes;
|
|
19248
19362
|
};
|
|
19249
19363
|
// src/resilienceRoutes.ts
|
|
19250
|
-
import { Elysia as
|
|
19251
|
-
var
|
|
19364
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
19365
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19252
19366
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
19253
19367
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
19254
19368
|
var getBoolean2 = (value) => value === true;
|
|
@@ -19395,13 +19509,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
19395
19509
|
};
|
|
19396
19510
|
var renderProviderCards = (title, providers) => {
|
|
19397
19511
|
if (providers.length === 0) {
|
|
19398
|
-
return `<p class="muted">No ${
|
|
19512
|
+
return `<p class="muted">No ${escapeHtml33(title)} provider health yet.</p>`;
|
|
19399
19513
|
}
|
|
19400
19514
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
19401
|
-
<article class="card provider ${
|
|
19515
|
+
<article class="card provider ${escapeHtml33(provider.status)}">
|
|
19402
19516
|
<div class="card-header">
|
|
19403
|
-
<strong>${
|
|
19404
|
-
<span>${
|
|
19517
|
+
<strong>${escapeHtml33(provider.provider)}</strong>
|
|
19518
|
+
<span>${escapeHtml33(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
19405
19519
|
</div>
|
|
19406
19520
|
<dl>
|
|
19407
19521
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -19410,7 +19524,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
19410
19524
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
19411
19525
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
19412
19526
|
</dl>
|
|
19413
|
-
${provider.lastError ? `<p class="muted">${
|
|
19527
|
+
${provider.lastError ? `<p class="muted">${escapeHtml33(provider.lastError)}</p>` : ""}
|
|
19414
19528
|
</article>
|
|
19415
19529
|
`).join("")}</div>`;
|
|
19416
19530
|
};
|
|
@@ -19419,24 +19533,24 @@ var renderTimeline2 = (events) => {
|
|
|
19419
19533
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
19420
19534
|
}
|
|
19421
19535
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
19422
|
-
<article class="card event ${
|
|
19536
|
+
<article class="card event ${escapeHtml33(event.status ?? "unknown")}">
|
|
19423
19537
|
<div class="card-header">
|
|
19424
|
-
<strong>${
|
|
19538
|
+
<strong>${escapeHtml33(event.kind.toUpperCase())} ${escapeHtml33(event.operation ?? "generate")}</strong>
|
|
19425
19539
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
19426
19540
|
</div>
|
|
19427
19541
|
<p>
|
|
19428
|
-
<span class="pill">${
|
|
19429
|
-
<span class="pill">provider: ${
|
|
19430
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
19542
|
+
<span class="pill">${escapeHtml33(event.status ?? "unknown")}</span>
|
|
19543
|
+
<span class="pill">provider: ${escapeHtml33(event.provider ?? "unknown")}</span>
|
|
19544
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml33(event.fallbackProvider)}</span>` : ""}
|
|
19431
19545
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
19432
19546
|
</p>
|
|
19433
19547
|
<dl>
|
|
19434
19548
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
19435
19549
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
19436
19550
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
19437
|
-
<div><dt>Session</dt><dd>${
|
|
19551
|
+
<div><dt>Session</dt><dd>${escapeHtml33(event.sessionId)}</dd></div>
|
|
19438
19552
|
</dl>
|
|
19439
|
-
${event.error ? `<p class="muted">${
|
|
19553
|
+
${event.error ? `<p class="muted">${escapeHtml33(event.error)}</p>` : ""}
|
|
19440
19554
|
</article>
|
|
19441
19555
|
`).join("")}</div>`;
|
|
19442
19556
|
};
|
|
@@ -19446,9 +19560,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
19446
19560
|
const status = latest?.status ?? "idle";
|
|
19447
19561
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
19448
19562
|
return `<div>
|
|
19449
|
-
<dt>${
|
|
19450
|
-
<dd>${
|
|
19451
|
-
<small>${
|
|
19563
|
+
<dt>${escapeHtml33(kind.toUpperCase())}</dt>
|
|
19564
|
+
<dd>${escapeHtml33(provider)}${escapeHtml33(fallback)}</dd>
|
|
19565
|
+
<small>${escapeHtml33(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>
|
|
19452
19566
|
</div>`;
|
|
19453
19567
|
};
|
|
19454
19568
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -19456,10 +19570,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
19456
19570
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
19457
19571
|
}
|
|
19458
19572
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
19459
|
-
<article class="card session ${
|
|
19573
|
+
<article class="card session ${escapeHtml33(session.status)}">
|
|
19460
19574
|
<div class="card-header">
|
|
19461
|
-
<strong>${
|
|
19462
|
-
<span>${
|
|
19575
|
+
<strong>${escapeHtml33(session.sessionId)}</strong>
|
|
19576
|
+
<span>${escapeHtml33(session.status)}</span>
|
|
19463
19577
|
</div>
|
|
19464
19578
|
<p>
|
|
19465
19579
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -19486,26 +19600,26 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
19486
19600
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
19487
19601
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
19488
19602
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
19489
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
19490
|
-
<p class="muted">${
|
|
19603
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml33(pathPrefix)}">
|
|
19604
|
+
<p class="muted">${escapeHtml33(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
19491
19605
|
<div class="simulate-actions">
|
|
19492
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
19493
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
19606
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml33(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml33(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
19607
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml33(provider.provider)}">Mark ${escapeHtml33(provider.provider)} recovered</button>`).join("")}
|
|
19494
19608
|
</div>
|
|
19495
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
19609
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml33(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
19496
19610
|
<pre class="simulate-output" hidden></pre>
|
|
19497
19611
|
</div>`;
|
|
19498
19612
|
};
|
|
19499
19613
|
var renderVoiceResilienceHTML = (input) => {
|
|
19500
19614
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
19501
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
19502
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
19615
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml33(kind)}: ${String(count)}</span>`).join("");
|
|
19616
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml33(link.href)}">${escapeHtml33(link.label)}</a>`).join(" \xB7 ") : "";
|
|
19503
19617
|
return `<!doctype html>
|
|
19504
19618
|
<html lang="en">
|
|
19505
19619
|
<head>
|
|
19506
19620
|
<meta charset="utf-8" />
|
|
19507
19621
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
19508
|
-
<title>${
|
|
19622
|
+
<title>${escapeHtml33(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
19509
19623
|
<style>
|
|
19510
19624
|
:root { color-scheme: dark; }
|
|
19511
19625
|
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; }
|
|
@@ -19648,7 +19762,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
19648
19762
|
};
|
|
19649
19763
|
var createVoiceResilienceRoutes = (options) => {
|
|
19650
19764
|
const path = options.path ?? "/resilience";
|
|
19651
|
-
const routes = new
|
|
19765
|
+
const routes = new Elysia31({
|
|
19652
19766
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
19653
19767
|
}).get(path, async () => {
|
|
19654
19768
|
const events = await options.store.list();
|
|
@@ -19726,8 +19840,8 @@ var assertVoiceProviderRoutingContract = async (options) => {
|
|
|
19726
19840
|
return report;
|
|
19727
19841
|
};
|
|
19728
19842
|
// src/productionReadiness.ts
|
|
19729
|
-
import { Elysia as
|
|
19730
|
-
var
|
|
19843
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
19844
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19731
19845
|
var rollupStatus2 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
19732
19846
|
var carrierStatus = (matrix) => matrix.summary.failing > 0 ? "fail" : matrix.summary.warnings > 0 || matrix.summary.ready < matrix.summary.providers ? "warn" : "pass";
|
|
19733
19847
|
var resolveCarriers = async (options, input) => {
|
|
@@ -20330,25 +20444,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
20330
20444
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
20331
20445
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
20332
20446
|
const checks = report.checks.map((check, index) => {
|
|
20333
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
20334
|
-
return `<article class="check ${
|
|
20447
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml34(action.href)}">${escapeHtml34(action.label)}</button>` : `<a href="${escapeHtml34(action.href)}">${escapeHtml34(action.label)}</a>`).join("");
|
|
20448
|
+
return `<article class="check ${escapeHtml34(check.status)}">
|
|
20335
20449
|
<div>
|
|
20336
|
-
<span>${
|
|
20337
|
-
<h2>${
|
|
20338
|
-
${check.detail ? `<p>${
|
|
20339
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
20450
|
+
<span>${escapeHtml34(check.status.toUpperCase())}</span>
|
|
20451
|
+
<h2>${escapeHtml34(check.label)}</h2>
|
|
20452
|
+
${check.detail ? `<p>${escapeHtml34(check.detail)}</p>` : ""}
|
|
20453
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml34(check.proofSource.href)}">${escapeHtml34(check.proofSource.sourceLabel)}</a>` : escapeHtml34(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml34(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
20340
20454
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
20341
20455
|
</div>
|
|
20342
|
-
<strong>${
|
|
20343
|
-
${check.href ? `<a href="${
|
|
20456
|
+
<strong>${escapeHtml34(String(check.value ?? check.status))}</strong>
|
|
20457
|
+
${check.href ? `<a href="${escapeHtml34(check.href)}">Open surface</a>` : ""}
|
|
20344
20458
|
</article>`;
|
|
20345
20459
|
}).join("");
|
|
20346
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20460
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml34(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(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.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}.status.pass,.check.pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.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{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check strong{font-size:1.5rem}.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>${escapeHtml34(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 ${escapeHtml34(report.status)}">Overall: ${escapeHtml34(report.status.toUpperCase())}</p><p>Checked ${escapeHtml34(new Date(report.checkedAt).toLocaleString())}</p></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>`;
|
|
20347
20461
|
};
|
|
20348
20462
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
20349
20463
|
const path = options.path ?? "/api/production-readiness";
|
|
20350
20464
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
20351
|
-
const routes = new
|
|
20465
|
+
const routes = new Elysia32({
|
|
20352
20466
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
20353
20467
|
});
|
|
20354
20468
|
routes.get(path, async ({ query, request }) => buildVoiceProductionReadinessReport(options, { query, request }));
|
|
@@ -20370,7 +20484,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
20370
20484
|
return routes;
|
|
20371
20485
|
};
|
|
20372
20486
|
// src/opsConsoleRoutes.ts
|
|
20373
|
-
import { Elysia as
|
|
20487
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
20374
20488
|
var DEFAULT_LINKS = [
|
|
20375
20489
|
{
|
|
20376
20490
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -20405,7 +20519,7 @@ var DEFAULT_LINKS = [
|
|
|
20405
20519
|
label: "Handoffs"
|
|
20406
20520
|
}
|
|
20407
20521
|
];
|
|
20408
|
-
var
|
|
20522
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20409
20523
|
var countProviderStatuses = (providers) => {
|
|
20410
20524
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
20411
20525
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -20474,20 +20588,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
20474
20588
|
trace
|
|
20475
20589
|
};
|
|
20476
20590
|
};
|
|
20477
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
20591
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml35(input.label)}</span><strong>${escapeHtml35(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml35(input.status)}">${escapeHtml35(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml35(input.href)}">Open</a>` : ""}</article>`;
|
|
20478
20592
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
20479
20593
|
const links = report.links.map((link) => `<article class="surface">
|
|
20480
|
-
<div><h2>${
|
|
20481
|
-
<p><a href="${
|
|
20594
|
+
<div><h2>${escapeHtml35(link.label)}</h2>${link.description ? `<p>${escapeHtml35(link.description)}</p>` : ""}</div>
|
|
20595
|
+
<p><a href="${escapeHtml35(link.href)}">Open ${escapeHtml35(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml35(link.statusHref)}">Status</a>` : ""}</p>
|
|
20482
20596
|
</article>`).join("");
|
|
20483
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
20484
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
20597
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml35(session.sessionId)}</td><td>${escapeHtml35(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml35(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
20598
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml35(event.kind)}</td><td>${escapeHtml35(event.provider ?? "unknown")}</td><td>${escapeHtml35(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml35(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
20485
20599
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
20486
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20600
|
+
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{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>${escapeHtml35(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 ${escapeHtml35(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>`;
|
|
20487
20601
|
};
|
|
20488
20602
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
20489
20603
|
const path = options.path ?? "/ops-console";
|
|
20490
|
-
const routes = new
|
|
20604
|
+
const routes = new Elysia33({
|
|
20491
20605
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
20492
20606
|
});
|
|
20493
20607
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -20675,19 +20789,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
20675
20789
|
};
|
|
20676
20790
|
};
|
|
20677
20791
|
// src/opsStatusRoutes.ts
|
|
20678
|
-
import { Elysia as
|
|
20679
|
-
var
|
|
20792
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
20793
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
20680
20794
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
20681
20795
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
20682
20796
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
20683
20797
|
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;
|
|
20684
|
-
return `<article class="surface ${
|
|
20798
|
+
return `<article class="surface ${escapeHtml36(surface.status)}"><span>${escapeHtml36(surface.status.toUpperCase())}</span><h2>${escapeHtml36(key)}</h2><strong>${escapeHtml36(value)}</strong></article>`;
|
|
20685
20799
|
}).join("");
|
|
20686
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20800
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{background:#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>${escapeHtml36(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml36(report.status)}">Overall: ${escapeHtml36(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>`;
|
|
20687
20801
|
};
|
|
20688
20802
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
20689
20803
|
const path = options.path ?? "/api/voice/ops-status";
|
|
20690
|
-
const routes = new
|
|
20804
|
+
const routes = new Elysia34({
|
|
20691
20805
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
20692
20806
|
});
|
|
20693
20807
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -21120,8 +21234,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
21120
21234
|
};
|
|
21121
21235
|
};
|
|
21122
21236
|
// src/traceDeliveryRoutes.ts
|
|
21123
|
-
import { Elysia as
|
|
21124
|
-
var
|
|
21237
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
21238
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21125
21239
|
var getString12 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
21126
21240
|
var getNumber7 = (value) => {
|
|
21127
21241
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -21202,14 +21316,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
21202
21316
|
if (entries.length === 0) {
|
|
21203
21317
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
21204
21318
|
}
|
|
21205
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
21319
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml37(sinkId)}</strong>: ${escapeHtml37(result.status)}${result.deliveredTo ? ` to ${escapeHtml37(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml37(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
21206
21320
|
};
|
|
21207
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
21321
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml37(event.type)} <small>${escapeHtml37(event.id)}</small>${event.sessionId ? ` session=${escapeHtml37(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
21208
21322
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
21209
21323
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
21210
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
21211
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
21212
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
21324
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml37(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
21325
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml37(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml37(delivery.deliveryStatus)}</span><h2>${escapeHtml37(delivery.id)}</h2><p>${escapeHtml37(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml37(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml37(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
21326
|
+
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:#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>${escapeHtml37(title)}</h1><p>Checked ${escapeHtml37(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>`;
|
|
21213
21327
|
};
|
|
21214
21328
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
21215
21329
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -21229,7 +21343,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
21229
21343
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
21230
21344
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
21231
21345
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
21232
|
-
const routes = new
|
|
21346
|
+
const routes = new Elysia35({
|
|
21233
21347
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
21234
21348
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
21235
21349
|
if (htmlPath !== false) {
|
|
@@ -21247,8 +21361,8 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
21247
21361
|
return routes;
|
|
21248
21362
|
};
|
|
21249
21363
|
// src/traceTimeline.ts
|
|
21250
|
-
import { Elysia as
|
|
21251
|
-
var
|
|
21364
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
21365
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21252
21366
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
21253
21367
|
var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
21254
21368
|
var firstString3 = (payload, keys) => {
|
|
@@ -21416,20 +21530,20 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
21416
21530
|
};
|
|
21417
21531
|
};
|
|
21418
21532
|
var formatMs3 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
21419
|
-
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>${
|
|
21533
|
+
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>${escapeHtml38(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(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>`;
|
|
21420
21534
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
21421
|
-
const events = session.events.map((event) => `<tr class="${
|
|
21422
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
21423
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
21535
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml38(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml38(event.type)}</td><td>${escapeHtml38(event.label)}</td><td>${escapeHtml38(event.provider ?? "")}</td><td>${escapeHtml38(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
|
|
21536
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml38(issue.severity)}">${escapeHtml38(issue.code)}: ${escapeHtml38(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
21537
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(session.sessionId)}</h1><p class="status ${escapeHtml38(session.status)}">${escapeHtml38(session.status)}</p></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>${formatMs3(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>`;
|
|
21424
21538
|
};
|
|
21425
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
21539
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml38(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml38(session.sessionId)}</a></td><td>${escapeHtml38(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml38(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
21426
21540
|
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}}";
|
|
21427
|
-
var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
21541
|
+
var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml38(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><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>`;
|
|
21428
21542
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
21429
21543
|
const path = options.path ?? "/api/voice-traces";
|
|
21430
21544
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
21431
21545
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
21432
|
-
const routes = new
|
|
21546
|
+
const routes = new Elysia36({
|
|
21433
21547
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
21434
21548
|
});
|
|
21435
21549
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -22082,7 +22196,7 @@ var createVoiceMemoryStore = () => {
|
|
|
22082
22196
|
return { get, getOrCreate, list, remove, set };
|
|
22083
22197
|
};
|
|
22084
22198
|
// src/opsWebhook.ts
|
|
22085
|
-
import { Elysia as
|
|
22199
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
22086
22200
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
22087
22201
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
22088
22202
|
const encoder = new TextEncoder;
|
|
@@ -22212,7 +22326,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
22212
22326
|
};
|
|
22213
22327
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
22214
22328
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
22215
|
-
return new
|
|
22329
|
+
return new Elysia37().post(path, async ({ body, request, set }) => {
|
|
22216
22330
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
22217
22331
|
if (options.signingSecret) {
|
|
22218
22332
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -23157,6 +23271,7 @@ export {
|
|
|
23157
23271
|
renderVoiceEvalBaselineHTML,
|
|
23158
23272
|
renderVoiceDemoReadyHTML,
|
|
23159
23273
|
renderVoiceDeliverySinkHTML,
|
|
23274
|
+
renderVoiceDeliveryRuntimeHTML,
|
|
23160
23275
|
renderVoiceCampaignsHTML,
|
|
23161
23276
|
renderVoiceCampaignObservabilityHTML,
|
|
23162
23277
|
renderVoiceCallReviewMarkdown,
|
|
@@ -23378,6 +23493,8 @@ export {
|
|
|
23378
23493
|
createVoiceDeliverySinkRoutes,
|
|
23379
23494
|
createVoiceDeliverySinkPair,
|
|
23380
23495
|
createVoiceDeliverySinkDescriptor,
|
|
23496
|
+
createVoiceDeliveryRuntimeRoutes,
|
|
23497
|
+
createVoiceDeliveryRuntime,
|
|
23381
23498
|
createVoiceCampaignWorkerLoop,
|
|
23382
23499
|
createVoiceCampaignWorker,
|
|
23383
23500
|
createVoiceCampaignTelephonyOutcomeHandler,
|
|
@@ -23449,6 +23566,7 @@ export {
|
|
|
23449
23566
|
buildVoiceDiagnosticsMarkdown,
|
|
23450
23567
|
buildVoiceDemoReadyReport,
|
|
23451
23568
|
buildVoiceDeliverySinkReport,
|
|
23569
|
+
buildVoiceDeliveryRuntimeReport,
|
|
23452
23570
|
buildVoiceDataRetentionPlan,
|
|
23453
23571
|
buildVoiceCampaignObservabilityReport,
|
|
23454
23572
|
buildVoiceAuditTrailReport,
|