@absolutejs/voice 0.0.22-beta.303 → 0.0.22-beta.304
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +639 -431
- package/dist/realtimeProviderContracts.d.ts +115 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11239,9 +11239,212 @@ var createVoiceRealtimeChannelRoutes = (options) => {
|
|
|
11239
11239
|
}
|
|
11240
11240
|
return app;
|
|
11241
11241
|
};
|
|
11242
|
-
// src/
|
|
11242
|
+
// src/realtimeProviderContracts.ts
|
|
11243
11243
|
import { Elysia as Elysia10 } from "elysia";
|
|
11244
|
-
var
|
|
11244
|
+
var defaultRequiredCapabilities = [
|
|
11245
|
+
"browser-format-negotiation",
|
|
11246
|
+
"raw-pcm",
|
|
11247
|
+
"duplex-audio",
|
|
11248
|
+
"turn-commit",
|
|
11249
|
+
"first-audio-latency",
|
|
11250
|
+
"trace-evidence",
|
|
11251
|
+
"reconnect",
|
|
11252
|
+
"barge-in"
|
|
11253
|
+
];
|
|
11254
|
+
var defaultProviderEnv = {
|
|
11255
|
+
"gemini-live": ["GEMINI_API_KEY"],
|
|
11256
|
+
"openai-realtime": ["OPENAI_API_KEY"],
|
|
11257
|
+
"pipecat-bridge": []
|
|
11258
|
+
};
|
|
11259
|
+
var statusRank = {
|
|
11260
|
+
pass: 0,
|
|
11261
|
+
warn: 1,
|
|
11262
|
+
fail: 2
|
|
11263
|
+
};
|
|
11264
|
+
var statusExceeds = (actual, max) => statusRank[actual] > statusRank[max];
|
|
11265
|
+
var rollupStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
11266
|
+
var escapeHtml13 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11267
|
+
var buildVoiceRealtimeProviderContractMatrix = (input) => {
|
|
11268
|
+
const rows = input.contracts.map((contract) => {
|
|
11269
|
+
const configured = contract.configured !== false;
|
|
11270
|
+
const requiredEnv = contract.requiredEnv ?? defaultProviderEnv[contract.provider] ?? [];
|
|
11271
|
+
const missingEnv = requiredEnv.filter((name) => !contract.env?.[name]);
|
|
11272
|
+
const requiredCapabilities = contract.requiredCapabilities ?? defaultRequiredCapabilities;
|
|
11273
|
+
const presentCapabilities = new Set(contract.capabilities ?? []);
|
|
11274
|
+
const missingCapabilities = requiredCapabilities.filter((capability) => !presentCapabilities.has(capability));
|
|
11275
|
+
const realtimeChannel = contract.realtimeChannel;
|
|
11276
|
+
const checks = [
|
|
11277
|
+
{
|
|
11278
|
+
detail: configured ? "Provider is configured for this deployment." : "Provider is declared but not configured.",
|
|
11279
|
+
key: "configured",
|
|
11280
|
+
label: "Configured",
|
|
11281
|
+
status: configured ? "pass" : "fail"
|
|
11282
|
+
},
|
|
11283
|
+
{
|
|
11284
|
+
detail: missingEnv.length === 0 ? "Required environment is present." : `Missing env: ${missingEnv.join(", ")}.`,
|
|
11285
|
+
key: "env",
|
|
11286
|
+
label: "Required env",
|
|
11287
|
+
status: missingEnv.length === 0 ? "pass" : "fail"
|
|
11288
|
+
},
|
|
11289
|
+
{
|
|
11290
|
+
detail: missingCapabilities.length === 0 ? "Required realtime capabilities are declared." : `Missing capabilities: ${missingCapabilities.join(", ")}.`,
|
|
11291
|
+
key: "capabilities",
|
|
11292
|
+
label: "Realtime capabilities",
|
|
11293
|
+
status: missingCapabilities.length === 0 ? "pass" : "warn"
|
|
11294
|
+
},
|
|
11295
|
+
{
|
|
11296
|
+
detail: realtimeChannel ? `Realtime channel proof is ${realtimeChannel.status}.` : "No realtime channel proof linked.",
|
|
11297
|
+
key: "realtimeChannel",
|
|
11298
|
+
label: "Realtime channel proof",
|
|
11299
|
+
status: realtimeChannel?.status === "pass" ? "pass" : realtimeChannel ? "warn" : "fail"
|
|
11300
|
+
},
|
|
11301
|
+
{
|
|
11302
|
+
detail: contract.latencyBudgetMs !== undefined ? `First audio latency budget is ${String(contract.latencyBudgetMs)}ms.` : "No first-audio latency budget declared.",
|
|
11303
|
+
key: "latencyBudget",
|
|
11304
|
+
label: "Latency budget",
|
|
11305
|
+
status: contract.latencyBudgetMs !== undefined ? "pass" : "warn"
|
|
11306
|
+
},
|
|
11307
|
+
{
|
|
11308
|
+
detail: (contract.fallbackProviders ?? []).length > 0 ? `Fallback providers: ${contract.fallbackProviders?.join(", ")}.` : "No realtime fallback provider declared.",
|
|
11309
|
+
key: "fallback",
|
|
11310
|
+
label: "Fallback",
|
|
11311
|
+
status: (contract.fallbackProviders ?? []).length > 0 ? "pass" : "warn"
|
|
11312
|
+
},
|
|
11313
|
+
{
|
|
11314
|
+
detail: contract.traceHref ? `Trace evidence: ${contract.traceHref}.` : "Trace evidence link is missing.",
|
|
11315
|
+
key: "traceEvidence",
|
|
11316
|
+
label: "Trace evidence",
|
|
11317
|
+
status: contract.traceHref ? "pass" : "warn"
|
|
11318
|
+
},
|
|
11319
|
+
{
|
|
11320
|
+
detail: contract.readinessHref ? `Readiness gate: ${contract.readinessHref}.` : "Readiness gate link is missing.",
|
|
11321
|
+
key: "readiness",
|
|
11322
|
+
label: "Readiness gate",
|
|
11323
|
+
status: contract.readinessHref ? "pass" : "warn"
|
|
11324
|
+
}
|
|
11325
|
+
];
|
|
11326
|
+
return {
|
|
11327
|
+
checks,
|
|
11328
|
+
configured,
|
|
11329
|
+
provider: contract.provider,
|
|
11330
|
+
selected: contract.selected === true,
|
|
11331
|
+
status: rollupStatus(checks)
|
|
11332
|
+
};
|
|
11333
|
+
});
|
|
11334
|
+
const failed = rows.filter((row) => row.status === "fail").length;
|
|
11335
|
+
const warned = rows.filter((row) => row.status === "warn").length;
|
|
11336
|
+
return {
|
|
11337
|
+
failed,
|
|
11338
|
+
passed: rows.filter((row) => row.status === "pass").length,
|
|
11339
|
+
rows,
|
|
11340
|
+
status: failed > 0 ? "fail" : warned > 0 ? "warn" : "pass",
|
|
11341
|
+
total: rows.length,
|
|
11342
|
+
warned
|
|
11343
|
+
};
|
|
11344
|
+
};
|
|
11345
|
+
var evaluateVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
11346
|
+
const issues = [];
|
|
11347
|
+
const maxStatus = input.maxStatus ?? "pass";
|
|
11348
|
+
const maxFailed = input.maxFailed ?? 0;
|
|
11349
|
+
const maxWarned = input.maxWarned ?? 0;
|
|
11350
|
+
const minRows = input.minRows ?? 1;
|
|
11351
|
+
const providers = [...new Set(report.rows.map((row) => row.provider))].sort();
|
|
11352
|
+
const selectedProviders = [
|
|
11353
|
+
...new Set(report.rows.filter((row) => row.selected).map((row) => row.provider))
|
|
11354
|
+
].sort();
|
|
11355
|
+
if (statusExceeds(report.status, maxStatus)) {
|
|
11356
|
+
issues.push(`Expected realtime provider contract status at most ${maxStatus}, found ${report.status}.`);
|
|
11357
|
+
}
|
|
11358
|
+
if (report.failed > maxFailed) {
|
|
11359
|
+
issues.push(`Expected at most ${String(maxFailed)} failing realtime provider row(s), found ${String(report.failed)}.`);
|
|
11360
|
+
}
|
|
11361
|
+
if (report.warned > maxWarned) {
|
|
11362
|
+
issues.push(`Expected at most ${String(maxWarned)} warning realtime provider row(s), found ${String(report.warned)}.`);
|
|
11363
|
+
}
|
|
11364
|
+
if (report.total < minRows) {
|
|
11365
|
+
issues.push(`Expected at least ${String(minRows)} realtime provider row(s), found ${String(report.total)}.`);
|
|
11366
|
+
}
|
|
11367
|
+
for (const provider of input.requiredProviders ?? []) {
|
|
11368
|
+
if (!providers.includes(provider)) {
|
|
11369
|
+
issues.push(`Missing realtime provider contract provider: ${provider}.`);
|
|
11370
|
+
}
|
|
11371
|
+
}
|
|
11372
|
+
for (const key of input.requiredCheckKeys ?? []) {
|
|
11373
|
+
const missingRows = report.rows.filter((row) => !row.checks.some((check) => check.key === key)).length;
|
|
11374
|
+
if (missingRows > 0) {
|
|
11375
|
+
issues.push(`Realtime provider contract check ${key} is missing from ${String(missingRows)} row(s).`);
|
|
11376
|
+
}
|
|
11377
|
+
}
|
|
11378
|
+
for (const capability of input.requiredCapabilities ?? []) {
|
|
11379
|
+
const missingRows = report.rows.filter((row) => {
|
|
11380
|
+
const capabilityCheck = row.checks.find((check) => check.key === "capabilities");
|
|
11381
|
+
return capabilityCheck?.detail?.includes(capability) === true;
|
|
11382
|
+
}).length;
|
|
11383
|
+
if (missingRows > 0) {
|
|
11384
|
+
issues.push(`Realtime provider capability ${capability} is missing from ${String(missingRows)} row(s).`);
|
|
11385
|
+
}
|
|
11386
|
+
}
|
|
11387
|
+
if ((input.requireSelected ?? true) && selectedProviders.length === 0) {
|
|
11388
|
+
issues.push("Missing selected realtime provider contract row.");
|
|
11389
|
+
}
|
|
11390
|
+
return {
|
|
11391
|
+
failed: report.failed,
|
|
11392
|
+
issues,
|
|
11393
|
+
ok: issues.length === 0,
|
|
11394
|
+
providers,
|
|
11395
|
+
selectedProviders,
|
|
11396
|
+
status: report.status,
|
|
11397
|
+
total: report.total,
|
|
11398
|
+
warned: report.warned
|
|
11399
|
+
};
|
|
11400
|
+
};
|
|
11401
|
+
var assertVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
11402
|
+
const assertion = evaluateVoiceRealtimeProviderContractEvidence(report, input);
|
|
11403
|
+
if (!assertion.ok) {
|
|
11404
|
+
throw new Error(`Voice realtime provider contract assertion failed: ${assertion.issues.join(" ")}`);
|
|
11405
|
+
}
|
|
11406
|
+
return assertion;
|
|
11407
|
+
};
|
|
11408
|
+
var resolveMatrix = async (matrix) => typeof matrix === "function" ? await matrix() : matrix;
|
|
11409
|
+
var renderVoiceRealtimeProviderContractHTML = (report, title = "Voice Realtime Provider Contracts") => {
|
|
11410
|
+
const rows = report.rows.map((row) => {
|
|
11411
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml13(check.status)}"><strong>${escapeHtml13(check.label)}</strong><span>${escapeHtml13(check.detail ?? check.status)}</span></li>`).join("");
|
|
11412
|
+
return `<article class="row ${escapeHtml13(row.status)}"><div><p class="eyebrow">${row.selected ? "selected" : "available"}</p><h2>${escapeHtml13(row.provider)}</h2><p class="status ${escapeHtml13(row.status)}">${escapeHtml13(row.status)}</p></div><ul>${checks}</ul></article>`;
|
|
11413
|
+
}).join("");
|
|
11414
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml13(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.row{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.1))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.row{display:grid;gap:18px;grid-template-columns:minmax(190px,.4fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#101814;border:1px solid #2e3d36;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.pass{color:#86efac}.warn{color:#fde68a}.fail{color:#fecaca}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime provider contracts</p><h1>${escapeHtml13(title)}</h1><p>Provider-level proof for duplex audio, browser format negotiation, turn commit, latency, reconnect, barge-in, trace evidence, fallback, and readiness gates.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section>${rows || '<article class="row"><p>No realtime provider contracts configured.</p></article>'}</main></body></html>`;
|
|
11415
|
+
};
|
|
11416
|
+
var createVoiceRealtimeProviderContractRoutes = (options) => {
|
|
11417
|
+
const path = options.path ?? "/api/voice/realtime-provider-contracts";
|
|
11418
|
+
const htmlPath = options.htmlPath ?? "/voice/realtime-provider-contracts";
|
|
11419
|
+
const title = options.title ?? "Voice Realtime Provider Contracts";
|
|
11420
|
+
const report = async () => buildVoiceRealtimeProviderContractMatrix(await resolveMatrix(options.matrix));
|
|
11421
|
+
const routes = new Elysia10({
|
|
11422
|
+
name: options.name ?? "voice-realtime-provider-contracts"
|
|
11423
|
+
}).get(path, async () => {
|
|
11424
|
+
return new Response(JSON.stringify(await report(), null, 2), {
|
|
11425
|
+
headers: {
|
|
11426
|
+
"content-type": "application/json; charset=utf-8",
|
|
11427
|
+
...options.headers
|
|
11428
|
+
}
|
|
11429
|
+
});
|
|
11430
|
+
});
|
|
11431
|
+
if (htmlPath !== false) {
|
|
11432
|
+
routes.get(htmlPath, async () => {
|
|
11433
|
+
const current = await report();
|
|
11434
|
+
const body = options.render ? await options.render(current) : renderVoiceRealtimeProviderContractHTML(current, title);
|
|
11435
|
+
return new Response(body, {
|
|
11436
|
+
headers: {
|
|
11437
|
+
"content-type": "text/html; charset=utf-8",
|
|
11438
|
+
...options.headers
|
|
11439
|
+
}
|
|
11440
|
+
});
|
|
11441
|
+
});
|
|
11442
|
+
}
|
|
11443
|
+
return routes;
|
|
11444
|
+
};
|
|
11445
|
+
// src/diagnosticsRoutes.ts
|
|
11446
|
+
import { Elysia as Elysia11 } from "elysia";
|
|
11447
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11245
11448
|
var getString6 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
11246
11449
|
var getNumber4 = (value) => {
|
|
11247
11450
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
|
|
@@ -11307,9 +11510,9 @@ var renderDiagnosticsIndex = (input) => {
|
|
|
11307
11510
|
const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
|
|
11308
11511
|
const summary = summarizeVoiceTrace(events);
|
|
11309
11512
|
const encoded = encodeURIComponent(sessionId);
|
|
11310
|
-
return `<tr><td>${
|
|
11513
|
+
return `<tr><td>${escapeHtml14(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
|
|
11311
11514
|
}).join("");
|
|
11312
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11515
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml14(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml14(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
11313
11516
|
};
|
|
11314
11517
|
var withRedaction = (events, query, defaultRedact) => {
|
|
11315
11518
|
const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
|
|
@@ -11318,7 +11521,7 @@ var withRedaction = (events, query, defaultRedact) => {
|
|
|
11318
11521
|
var createVoiceDiagnosticsRoutes = (options) => {
|
|
11319
11522
|
const path = options.path ?? "/diagnostics";
|
|
11320
11523
|
const title = options.title ?? "AbsoluteJS Voice Diagnostics";
|
|
11321
|
-
const routes = new
|
|
11524
|
+
const routes = new Elysia11({
|
|
11322
11525
|
name: options.name ?? "absolutejs-voice-diagnostics"
|
|
11323
11526
|
});
|
|
11324
11527
|
routes.get(path, async () => {
|
|
@@ -11375,9 +11578,9 @@ var createVoiceDiagnosticsRoutes = (options) => {
|
|
|
11375
11578
|
return routes;
|
|
11376
11579
|
};
|
|
11377
11580
|
// src/demoReadyRoutes.ts
|
|
11378
|
-
import { Elysia as
|
|
11379
|
-
var
|
|
11380
|
-
var
|
|
11581
|
+
import { Elysia as Elysia12 } from "elysia";
|
|
11582
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11583
|
+
var rollupStatus2 = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
11381
11584
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
11382
11585
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
11383
11586
|
const query = input.query ?? {};
|
|
@@ -11433,7 +11636,7 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11433
11636
|
return {
|
|
11434
11637
|
checkedAt: Date.now(),
|
|
11435
11638
|
sections,
|
|
11436
|
-
status: sections.length === 0 ? "warn" :
|
|
11639
|
+
status: sections.length === 0 ? "warn" : rollupStatus2(sections),
|
|
11437
11640
|
summary: {
|
|
11438
11641
|
opsStatus: opsStatus ? {
|
|
11439
11642
|
failed: opsStatus.failed,
|
|
@@ -11460,17 +11663,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11460
11663
|
};
|
|
11461
11664
|
};
|
|
11462
11665
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
11463
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
11464
|
-
<div><span>${
|
|
11465
|
-
<strong>${
|
|
11466
|
-
${section.href ? `<a href="${
|
|
11666
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml15(section.status)}">
|
|
11667
|
+
<div><span>${escapeHtml15(section.status.toUpperCase())}</span><h2>${escapeHtml15(section.label)}</h2>${section.description ? `<p>${escapeHtml15(section.description)}</p>` : ""}</div>
|
|
11668
|
+
<strong>${escapeHtml15(String(section.value ?? section.status))}</strong>
|
|
11669
|
+
${section.href ? `<a href="${escapeHtml15(section.href)}">Open</a>` : ""}
|
|
11467
11670
|
</article>`).join("");
|
|
11468
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11671
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(report.title)}</title><style>body{background:#0d141b;color:#f8f3e7;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,.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}.sections{display:grid;gap:14px}.section{align-items:center;background:#151d26;border:1px solid #283544;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.section span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.section h2{margin:.2rem 0}.section p{color:#b9c0c8;margin:.2rem 0 0}.section strong{font-size:1.4rem}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.65)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}@media(max-width:760px){main{padding:20px}.section{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Demo readiness</p><h1>${escapeHtml15(report.title)}</h1><p>One customer-facing checklist for the self-hosted voice proof surfaces: ops status, production readiness, phone setup, and phone smoke traces.</p><p class="status ${escapeHtml15(report.status)}">Overall: ${escapeHtml15(report.status.toUpperCase())}</p><p>Checked ${escapeHtml15(new Date(report.checkedAt).toLocaleString())}</p></section><section class="sections">${sections || '<article class="section warn"><div><span>WARN</span><h2>No checks configured</h2><p>Add ops status, production readiness, phone setup, or phone smoke loaders.</p></div><strong>warn</strong></article>'}</section></main></body></html>`;
|
|
11469
11672
|
};
|
|
11470
11673
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
11471
11674
|
const path = options.path ?? "/api/demo-ready";
|
|
11472
11675
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
11473
|
-
const routes = new
|
|
11676
|
+
const routes = new Elysia12({
|
|
11474
11677
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
11475
11678
|
});
|
|
11476
11679
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -11489,7 +11692,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
11489
11692
|
return routes;
|
|
11490
11693
|
};
|
|
11491
11694
|
// src/deliverySinkRoutes.ts
|
|
11492
|
-
import { Elysia as
|
|
11695
|
+
import { Elysia as Elysia13 } from "elysia";
|
|
11493
11696
|
|
|
11494
11697
|
// src/queue.ts
|
|
11495
11698
|
var releaseLeaseScript = `
|
|
@@ -12432,7 +12635,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
12432
12635
|
};
|
|
12433
12636
|
|
|
12434
12637
|
// src/deliverySinkRoutes.ts
|
|
12435
|
-
var
|
|
12638
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12436
12639
|
var deliveryStatus = (summary) => {
|
|
12437
12640
|
if (!summary) {
|
|
12438
12641
|
return "warn";
|
|
@@ -12531,13 +12734,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
12531
12734
|
return "";
|
|
12532
12735
|
}
|
|
12533
12736
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
12534
|
-
const body = `<span>${
|
|
12535
|
-
return `<article>${surface.href ? `<a href="${
|
|
12737
|
+
const body = `<span>${escapeHtml16(surface.label)}</span><strong>${escapeHtml16(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
12738
|
+
return `<article>${surface.href ? `<a href="${escapeHtml16(surface.href)}">${body}</a>` : body}</article>`;
|
|
12536
12739
|
};
|
|
12537
12740
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
12538
12741
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
12539
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
12540
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12742
|
+
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${escapeHtml16(sink.kind)}</span><strong style="font-size:1.5rem">${escapeHtml16(sink.label)}</strong>${sink.description ? `<p class="muted">${escapeHtml16(sink.description)}</p>` : ""}${sink.mode ? `<p class="muted">Mode: ${escapeHtml16(sink.mode)}</p>` : ""}${sink.target ? `<p class="muted">Target: <code>${escapeHtml16(sink.target)}</code></p>` : ""}${sink.href ? `<p><a href="${escapeHtml16(sink.href)}">Open sink</a></p>` : ""}</article>`).join("") : '<article><span>Sink</span><strong style="font-size:1.5rem">Not described</strong><p class="muted">Pass sink descriptors to document your file, webhook, S3, SQLite, or Postgres targets.</p></article>';
|
|
12743
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{background:#11120d;color:#fbf7e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{max-width:1120px;margin:auto;padding:32px}a{color:#fde68a;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(253,230,138,.2),rgba(34,197,94,.14));border:1px solid #3a3420;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fde68a;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.65)}.status.fail{border-color:rgba(239,68,68,.75)}.muted{color:#b8b093}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#191a13;border:1px solid #33311f;border-radius:22px;padding:18px}article span{color:#b8b093;display:block;font-weight:800}article strong{display:block;font-size:2.4rem;margin-top:8px}pre{background:#0c0d09;border:1px solid #33311f;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}code{color:#fef3c7}</style></head><body><main><p><a href="/production-readiness">Production readiness</a></p><section class="hero"><p class="eyebrow">Composable sink primitive</p><h1>${escapeHtml16(title)}</h1><p class="muted">Delivery queues prove audit and trace exports without owning your infrastructure. Swap file, webhook, S3, SQLite, or Postgres sinks behind the same readiness surface.</p><p class="status ${escapeHtml16(report.status)}">Overall: ${escapeHtml16(report.status.toUpperCase())}</p><p class="muted">Checked ${escapeHtml16(new Date(report.checkedAt).toLocaleString())}</p></section><section class="grid">${renderSurfaceCard(report.auditDeliveries)}${renderSurfaceCard(report.traceDeliveries)}${sinks}</section><section class="card"><h2>Primitive shape</h2><p class="muted">Mount delivery sink routes beside audit and trace delivery queues. Production readiness can consume the same stores for pass/fail evidence.</p><pre>createVoiceDeliverySinkRoutes({
|
|
12541
12744
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
12542
12745
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
12543
12746
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -12549,7 +12752,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
12549
12752
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
12550
12753
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
12551
12754
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
12552
|
-
const routes = new
|
|
12755
|
+
const routes = new Elysia13({
|
|
12553
12756
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
12554
12757
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
12555
12758
|
if (htmlPath !== false) {
|
|
@@ -12567,7 +12770,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
12567
12770
|
return routes;
|
|
12568
12771
|
};
|
|
12569
12772
|
// src/opsActionAuditRoutes.ts
|
|
12570
|
-
import { Elysia as
|
|
12773
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12571
12774
|
var readRecordBody = (body) => {
|
|
12572
12775
|
if (!body || typeof body !== "object") {
|
|
12573
12776
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -12642,7 +12845,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
12642
12845
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
12643
12846
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
12644
12847
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
12645
|
-
const routes = new
|
|
12848
|
+
const routes = new Elysia14({
|
|
12646
12849
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
12647
12850
|
}).post(path, async ({ body, request, set }) => {
|
|
12648
12851
|
try {
|
|
@@ -12692,13 +12895,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
12692
12895
|
total: entries.length
|
|
12693
12896
|
};
|
|
12694
12897
|
};
|
|
12695
|
-
var
|
|
12898
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12696
12899
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
12697
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
12900
|
+
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml17(entry.ok ? "success" : "error")}</span><strong>${escapeHtml17(entry.actionId)}</strong><p>${escapeHtml17(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml17(entry.error)}</p>` : ""}</article>`).join("");
|
|
12698
12901
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Ops Action History</title><style>body{background:#11140f;color:#f7f1df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,article{background:#181d15;border:1px solid #2c3327;border-radius:24px;padding:20px}.hero{margin-bottom:16px}h1{font-size:clamp(2rem,6vw,4rem);line-height:.95}section{display:grid;gap:12px}article.ok{border-color:rgba(34,197,94,.55)}article.fail{border-color:rgba(239,68,68,.75)}span{color:#facc15;font-weight:900;text-transform:uppercase}p{color:#c8ccb8}</style></head><body><main><section class="hero"><span>Operator proof</span><h1>Voice Ops Action History</h1><p>${String(report.total)} action(s), ${String(report.failed)} failed.</p></section><section>${rows || "<p>No operator actions have been recorded.</p>"}</section></main></body></html>`;
|
|
12699
12902
|
};
|
|
12700
12903
|
// src/platformCoverage.ts
|
|
12701
|
-
import { Elysia as
|
|
12904
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12702
12905
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
12703
12906
|
const coverage = input.coverage ?? [];
|
|
12704
12907
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -12759,7 +12962,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
12759
12962
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
12760
12963
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
12761
12964
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
12762
|
-
const routes = new
|
|
12965
|
+
const routes = new Elysia15({
|
|
12763
12966
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
12764
12967
|
});
|
|
12765
12968
|
routes.get(path, async () => {
|
|
@@ -12771,8 +12974,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
12771
12974
|
return routes;
|
|
12772
12975
|
};
|
|
12773
12976
|
// src/competitiveCoverage.ts
|
|
12774
|
-
import { Elysia as
|
|
12775
|
-
var
|
|
12977
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12978
|
+
var escapeHtml18 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12776
12979
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
12777
12980
|
var resolveSurfaceStatus = (surface) => {
|
|
12778
12981
|
if (surface.status)
|
|
@@ -12940,24 +13143,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
12940
13143
|
`);
|
|
12941
13144
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
12942
13145
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
12943
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
12944
|
-
return `<article class="surface ${
|
|
12945
|
-
<header><div><p class="eyebrow">${
|
|
12946
|
-
<p>${
|
|
13146
|
+
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${escapeHtml18(item.name)}</strong>${item.kind ? ` <span>${escapeHtml18(item.kind)}</span>` : ""}${item.status ? ` <em>${escapeHtml18(item.status)}</em>` : ""}${item.href ? ` <a href="${escapeHtml18(item.href)}">open</a>` : ""}</li>`).join("");
|
|
13147
|
+
return `<article class="surface ${escapeHtml18(surface.status)} ${escapeHtml18(surface.depth)}">
|
|
13148
|
+
<header><div><p class="eyebrow">${escapeHtml18(surface.coverage)} \xB7 ${escapeHtml18(surface.depth)}</p><h2>${escapeHtml18(surface.surface)}</h2></div><strong>${escapeHtml18(surface.status)}</strong></header>
|
|
13149
|
+
<p>${escapeHtml18(surface.why)}</p>
|
|
12947
13150
|
<dl>
|
|
12948
|
-
<div><dt>Competitors</dt><dd>${
|
|
12949
|
-
<div><dt>Operations record</dt><dd>${
|
|
12950
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
12951
|
-
<div><dt>Frameworks</dt><dd>${
|
|
13151
|
+
<div><dt>Competitors</dt><dd>${escapeHtml18((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
13152
|
+
<div><dt>Operations record</dt><dd>${escapeHtml18(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
13153
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml18(surface.readinessGate ?? "unknown")}</dd></div>
|
|
13154
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml18((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
12952
13155
|
</dl>
|
|
12953
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
12954
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
13156
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml18(surface.remainingGap)}</p>` : ""}
|
|
13157
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml18(surface.nextMove)}</p>` : ""}
|
|
12955
13158
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
12956
13159
|
</article>`;
|
|
12957
13160
|
}).join(`
|
|
12958
13161
|
`);
|
|
12959
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
12960
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13162
|
+
const issueList = report.issues.map((issue) => `<li class="${escapeHtml18(issue.severity)}"><strong>${escapeHtml18(issue.code)}</strong>${issue.surface ? ` ${escapeHtml18(issue.surface)}` : ""}: ${escapeHtml18(issue.message)}</li>`).join("");
|
|
13163
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(title)}</title><style>body{background:#0e1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.surface,.issues{background:#17201c;border:1px solid #2e3c35;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.16),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.surfaces{display:grid;gap:14px}.surface header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.surface.pass{border-color:rgba(34,197,94,.55)}.surface.warn{border-color:rgba(245,158,11,.72)}.surface.fail{border-color:rgba(239,68,68,.75)}.surface.advantage h2{color:#bbf7d0}.surface.intentional-gap h2{color:#cbd5e1}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}dt{color:#9fb0a8;font-size:.8rem;font-weight:800}dd{margin:0;overflow-wrap:anywhere}.gap{color:#fde68a}.next{color:#bfdbfe}.muted{color:#a8b5ad}a{color:#5eead4}.issues li{margin:.4rem 0}.issues .error{color:#fecaca}.issues .warning{color:#fde68a}@media(max-width:760px){main{padding:18px}.surface header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted market proof</p><h1>${escapeHtml18(title)}</h1><p>Generated ${escapeHtml18(report.generatedAt)}. This report scores whether AbsoluteJS Voice merely covers a hosted-platform buyer surface or beats it for a code-owned/self-hosted buyer.</p><div class="summary"><span class="pill">Status ${escapeHtml18(report.status)}</span><span class="pill">Vapi-style ${escapeHtml18(report.vapiCoverageEstimate)}</span><span class="pill">Market ${escapeHtml18(report.marketCoverageEstimate)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.advantage)} advantage</span><span class="pill">${String(report.summary.intentionalGaps)} intentional gaps</span></div></section><section class="issues"><h2>Issues</h2><ul>${issueList || "<li>No issues.</li>"}</ul></section><section class="surfaces">${surfaceCards || '<article class="surface"><p>No competitive surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
12961
13164
|
};
|
|
12962
13165
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
12963
13166
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -12970,7 +13173,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12970
13173
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
12971
13174
|
return normalizeCompetitiveCoverageReport(value);
|
|
12972
13175
|
};
|
|
12973
|
-
const app = new
|
|
13176
|
+
const app = new Elysia16({
|
|
12974
13177
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
12975
13178
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
12976
13179
|
headers: {
|
|
@@ -13001,7 +13204,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13001
13204
|
return app;
|
|
13002
13205
|
};
|
|
13003
13206
|
// src/proofTrends.ts
|
|
13004
|
-
import { Elysia as
|
|
13207
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13005
13208
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
13006
13209
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
13007
13210
|
var toTimeMs = (value) => {
|
|
@@ -13152,7 +13355,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
13152
13355
|
};
|
|
13153
13356
|
var createVoiceProofTrendRoutes = (options) => {
|
|
13154
13357
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
13155
|
-
const routes = new
|
|
13358
|
+
const routes = new Elysia17({
|
|
13156
13359
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
13157
13360
|
});
|
|
13158
13361
|
routes.get(path, async () => {
|
|
@@ -13185,11 +13388,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
13185
13388
|
return `${days}d ${hours % 24}h`;
|
|
13186
13389
|
};
|
|
13187
13390
|
// src/providerDecisionTraces.ts
|
|
13188
|
-
import { Elysia as
|
|
13391
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13189
13392
|
|
|
13190
13393
|
// src/resilienceRoutes.ts
|
|
13191
|
-
import { Elysia as
|
|
13192
|
-
var
|
|
13394
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
13395
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13193
13396
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
13194
13397
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13195
13398
|
var getBoolean2 = (value) => value === true;
|
|
@@ -13337,13 +13540,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
13337
13540
|
};
|
|
13338
13541
|
var renderProviderCards = (title, providers) => {
|
|
13339
13542
|
if (providers.length === 0) {
|
|
13340
|
-
return `<p class="muted">No ${
|
|
13543
|
+
return `<p class="muted">No ${escapeHtml19(title)} provider health yet.</p>`;
|
|
13341
13544
|
}
|
|
13342
13545
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
13343
|
-
<article class="card provider ${
|
|
13546
|
+
<article class="card provider ${escapeHtml19(provider.status)}">
|
|
13344
13547
|
<div class="card-header">
|
|
13345
|
-
<strong>${
|
|
13346
|
-
<span>${
|
|
13548
|
+
<strong>${escapeHtml19(provider.provider)}</strong>
|
|
13549
|
+
<span>${escapeHtml19(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
13347
13550
|
</div>
|
|
13348
13551
|
<dl>
|
|
13349
13552
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -13352,7 +13555,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
13352
13555
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
13353
13556
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
13354
13557
|
</dl>
|
|
13355
|
-
${provider.lastError ? `<p class="muted">${
|
|
13558
|
+
${provider.lastError ? `<p class="muted">${escapeHtml19(provider.lastError)}</p>` : ""}
|
|
13356
13559
|
</article>
|
|
13357
13560
|
`).join("")}</div>`;
|
|
13358
13561
|
};
|
|
@@ -13361,24 +13564,24 @@ var renderTimeline2 = (events) => {
|
|
|
13361
13564
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
13362
13565
|
}
|
|
13363
13566
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
13364
|
-
<article class="card event ${
|
|
13567
|
+
<article class="card event ${escapeHtml19(event.status ?? "unknown")}">
|
|
13365
13568
|
<div class="card-header">
|
|
13366
|
-
<strong>${
|
|
13569
|
+
<strong>${escapeHtml19(event.kind.toUpperCase())} ${escapeHtml19(event.operation ?? "generate")}</strong>
|
|
13367
13570
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
13368
13571
|
</div>
|
|
13369
13572
|
<p>
|
|
13370
|
-
<span class="pill">${
|
|
13371
|
-
<span class="pill">provider: ${
|
|
13372
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
13573
|
+
<span class="pill">${escapeHtml19(event.status ?? "unknown")}</span>
|
|
13574
|
+
<span class="pill">provider: ${escapeHtml19(event.provider ?? "unknown")}</span>
|
|
13575
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml19(event.fallbackProvider)}</span>` : ""}
|
|
13373
13576
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
13374
13577
|
</p>
|
|
13375
13578
|
<dl>
|
|
13376
13579
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
13377
13580
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
13378
13581
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
13379
|
-
<div><dt>Session</dt><dd>${
|
|
13582
|
+
<div><dt>Session</dt><dd>${escapeHtml19(event.sessionId)}</dd></div>
|
|
13380
13583
|
</dl>
|
|
13381
|
-
${event.error ? `<p class="muted">${
|
|
13584
|
+
${event.error ? `<p class="muted">${escapeHtml19(event.error)}</p>` : ""}
|
|
13382
13585
|
</article>
|
|
13383
13586
|
`).join("")}</div>`;
|
|
13384
13587
|
};
|
|
@@ -13388,9 +13591,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
13388
13591
|
const status = latest?.status ?? "idle";
|
|
13389
13592
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
13390
13593
|
return `<div>
|
|
13391
|
-
<dt>${
|
|
13392
|
-
<dd>${
|
|
13393
|
-
<small>${
|
|
13594
|
+
<dt>${escapeHtml19(kind.toUpperCase())}</dt>
|
|
13595
|
+
<dd>${escapeHtml19(provider)}${escapeHtml19(fallback)}</dd>
|
|
13596
|
+
<small>${escapeHtml19(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>
|
|
13394
13597
|
</div>`;
|
|
13395
13598
|
};
|
|
13396
13599
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -13398,10 +13601,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
13398
13601
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
13399
13602
|
}
|
|
13400
13603
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
13401
|
-
<article class="card session ${
|
|
13604
|
+
<article class="card session ${escapeHtml19(session.status)}">
|
|
13402
13605
|
<div class="card-header">
|
|
13403
|
-
<strong>${
|
|
13404
|
-
<span>${
|
|
13606
|
+
<strong>${escapeHtml19(session.sessionId)}</strong>
|
|
13607
|
+
<span>${escapeHtml19(session.status)}</span>
|
|
13405
13608
|
</div>
|
|
13406
13609
|
<p>
|
|
13407
13610
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -13428,21 +13631,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
13428
13631
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
13429
13632
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
13430
13633
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
13431
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
13432
|
-
<p class="muted">${
|
|
13634
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml19(pathPrefix)}">
|
|
13635
|
+
<p class="muted">${escapeHtml19(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
13433
13636
|
<div class="simulate-actions">
|
|
13434
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
13435
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
13637
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml19(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml19(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
13638
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml19(provider.provider)}">Mark ${escapeHtml19(provider.provider)} recovered</button>`).join("")}
|
|
13436
13639
|
</div>
|
|
13437
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
13640
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml19(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
13438
13641
|
<pre class="simulate-output" hidden></pre>
|
|
13439
13642
|
</div>`;
|
|
13440
13643
|
};
|
|
13441
13644
|
var renderVoiceResilienceHTML = (input) => {
|
|
13442
13645
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
13443
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
13444
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
13445
|
-
const snippet =
|
|
13646
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml19(kind)}: ${String(count)}</span>`).join("");
|
|
13647
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join(" \xB7 ") : "";
|
|
13648
|
+
const snippet = escapeHtml19(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
13446
13649
|
kind: 'stt',
|
|
13447
13650
|
providers: ['deepgram', 'assemblyai'],
|
|
13448
13651
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -13480,7 +13683,7 @@ app.use(
|
|
|
13480
13683
|
<head>
|
|
13481
13684
|
<meta charset="utf-8" />
|
|
13482
13685
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13483
|
-
<title>${
|
|
13686
|
+
<title>${escapeHtml19(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
13484
13687
|
<style>
|
|
13485
13688
|
:root { color-scheme: dark; }
|
|
13486
13689
|
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; }
|
|
@@ -13632,7 +13835,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
13632
13835
|
};
|
|
13633
13836
|
var createVoiceResilienceRoutes = (options) => {
|
|
13634
13837
|
const path = options.path ?? "/resilience";
|
|
13635
|
-
const routes = new
|
|
13838
|
+
const routes = new Elysia18({
|
|
13636
13839
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
13637
13840
|
}).get(path, async () => {
|
|
13638
13841
|
const events = await options.store.list();
|
|
@@ -13673,7 +13876,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
13673
13876
|
};
|
|
13674
13877
|
|
|
13675
13878
|
// src/providerDecisionTraces.ts
|
|
13676
|
-
var
|
|
13879
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13677
13880
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
13678
13881
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13679
13882
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -13688,8 +13891,8 @@ var surfaceForKind = (kind) => {
|
|
|
13688
13891
|
return "live-call";
|
|
13689
13892
|
}
|
|
13690
13893
|
};
|
|
13691
|
-
var
|
|
13692
|
-
var reportStatus = (issues) => issues.reduce((status, issue) =>
|
|
13894
|
+
var statusRank2 = { fail: 2, pass: 0, warn: 1 };
|
|
13895
|
+
var reportStatus = (issues) => issues.reduce((status, issue) => statusRank2[issue.status] > statusRank2[status] ? issue.status : status, "pass");
|
|
13693
13896
|
var uniqueSorted = (values) => [
|
|
13694
13897
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
13695
13898
|
].sort();
|
|
@@ -13914,7 +14117,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
13914
14117
|
<head>
|
|
13915
14118
|
<meta charset="utf-8" />
|
|
13916
14119
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13917
|
-
<title>${
|
|
14120
|
+
<title>${escapeHtml20(title)}</title>
|
|
13918
14121
|
<style>
|
|
13919
14122
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
13920
14123
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -13928,8 +14131,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13928
14131
|
</head>
|
|
13929
14132
|
<body>
|
|
13930
14133
|
<main>
|
|
13931
|
-
<p class="status ${report.status}">${
|
|
13932
|
-
<h1>${
|
|
14134
|
+
<p class="status ${report.status}">${escapeHtml20(report.status)}</p>
|
|
14135
|
+
<h1>${escapeHtml20(title)}</h1>
|
|
13933
14136
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
13934
14137
|
<section class="grid">
|
|
13935
14138
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -13940,10 +14143,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13940
14143
|
</section>
|
|
13941
14144
|
<section class="surfaces">
|
|
13942
14145
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
13943
|
-
<header><strong>${
|
|
14146
|
+
<header><strong>${escapeHtml20(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml20(surface.status)}</span></header>
|
|
13944
14147
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
13945
|
-
<p class="muted">Providers: ${
|
|
13946
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
14148
|
+
<p class="muted">Providers: ${escapeHtml20(surface.providers.join(", ") || "none")}</p>
|
|
14149
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml20(reason)}</code>`).join(" ")}</p>
|
|
13947
14150
|
</article>`).join(`
|
|
13948
14151
|
`)}
|
|
13949
14152
|
</section>
|
|
@@ -13957,7 +14160,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13957
14160
|
const headers = options.headers ?? {};
|
|
13958
14161
|
const title = options.title ?? "Provider Decision Traces";
|
|
13959
14162
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
13960
|
-
const app = new
|
|
14163
|
+
const app = new Elysia19({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13961
14164
|
headers: {
|
|
13962
14165
|
"content-type": "application/json; charset=utf-8",
|
|
13963
14166
|
...headers
|
|
@@ -13985,7 +14188,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13985
14188
|
return app;
|
|
13986
14189
|
};
|
|
13987
14190
|
// src/sloCalibration.ts
|
|
13988
|
-
import { Elysia as
|
|
14191
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
13989
14192
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
13990
14193
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
13991
14194
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -14165,7 +14368,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
14165
14368
|
};
|
|
14166
14369
|
};
|
|
14167
14370
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
14168
|
-
var
|
|
14371
|
+
var escapeHtml21 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14169
14372
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
14170
14373
|
var readinessThresholdRows = (report) => [
|
|
14171
14374
|
{
|
|
@@ -14256,15 +14459,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
14256
14459
|
};
|
|
14257
14460
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
14258
14461
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
14259
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
14260
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
14261
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
14262
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
14462
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml21(row.control)}</td><td>${escapeHtml21(formatMs(row.value))}</td><td>${escapeHtml21(row.usedBy)}</td></tr>`).join("");
|
|
14463
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml21(issue)}</li>`).join("");
|
|
14464
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml21(source)}</code></li>`).join("");
|
|
14465
|
+
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:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1040px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}.status{font-size:1.6rem;font-weight:800;text-transform:uppercase}</style></head><body><main><h1>${escapeHtml21(title)}</h1><p>This page shows the calibrated thresholds currently driving production readiness gates.</p><section class="summary"><div class="card"><strong>Status</strong><br><span class="status">${escapeHtml21(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml21(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml21(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml21(formatMs(report.bargeIn.thresholdMs))}</div></section><h2>Active Readiness Thresholds</h2><table><thead><tr><th>Threshold</th><th>Active value</th><th>Used by</th></tr></thead><tbody>${rows}</tbody></table><h2>Sources</h2><ul>${sources}</ul><h2>Issues</h2><ul>${issues}</ul></main></body></html>`;
|
|
14263
14466
|
};
|
|
14264
14467
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
14265
14468
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
14266
14469
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
14267
|
-
const routes = new
|
|
14470
|
+
const routes = new Elysia20({
|
|
14268
14471
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
14269
14472
|
});
|
|
14270
14473
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14288,7 +14491,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14288
14491
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
14289
14492
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
14290
14493
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
14291
|
-
const routes = new
|
|
14494
|
+
const routes = new Elysia20({
|
|
14292
14495
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
14293
14496
|
});
|
|
14294
14497
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14322,7 +14525,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14322
14525
|
return routes;
|
|
14323
14526
|
};
|
|
14324
14527
|
// src/liveOps.ts
|
|
14325
|
-
import { Elysia as
|
|
14528
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14326
14529
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
14327
14530
|
"assign",
|
|
14328
14531
|
"create-task",
|
|
@@ -14632,7 +14835,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14632
14835
|
const controller = createVoiceLiveOpsController(options);
|
|
14633
14836
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
14634
14837
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
14635
|
-
return new
|
|
14838
|
+
return new Elysia21({
|
|
14636
14839
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
14637
14840
|
}).post(path, async ({ request, set }) => {
|
|
14638
14841
|
try {
|
|
@@ -14654,15 +14857,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14654
14857
|
});
|
|
14655
14858
|
};
|
|
14656
14859
|
// src/deliveryRuntime.ts
|
|
14657
|
-
import { Elysia as
|
|
14860
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14658
14861
|
import { mkdir } from "fs/promises";
|
|
14659
14862
|
import { dirname, join } from "path";
|
|
14660
|
-
var
|
|
14863
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14661
14864
|
var renderSummaryCard = (label, summary) => {
|
|
14662
14865
|
if (!summary) {
|
|
14663
|
-
return `<article><span>${
|
|
14866
|
+
return `<article><span>${escapeHtml22(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
14664
14867
|
}
|
|
14665
|
-
return `<article><span>${
|
|
14868
|
+
return `<article><span>${escapeHtml22(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>`;
|
|
14666
14869
|
};
|
|
14667
14870
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
14668
14871
|
audit: leases,
|
|
@@ -14873,9 +15076,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
14873
15076
|
});
|
|
14874
15077
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
14875
15078
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
14876
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
14877
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
14878
|
-
const snippet =
|
|
15079
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml22(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
15080
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml22(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
15081
|
+
const snippet = escapeHtml22(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
14879
15082
|
createVoiceDeliveryRuntimePresetConfig({
|
|
14880
15083
|
audit: {
|
|
14881
15084
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -14901,14 +15104,14 @@ app.use(
|
|
|
14901
15104
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
14902
15105
|
})
|
|
14903
15106
|
);`);
|
|
14904
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15107
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}.primitive{background:#111a15;border-color:#41604a}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}.primitive p{color:#c8d8ca;line-height:1.55}.primitive code{color:#bbf7d0}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml22(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml22(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceDeliveryRuntimeRoutes(...)</code> builds this control plane</h2><p>Own the audit and trace delivery queues in your app, mount one runtime route group, and pass the same runtime into production readiness so failed or dead-lettered exports block deploys.</p><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
14905
15108
|
};
|
|
14906
15109
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
14907
15110
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
14908
15111
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
14909
15112
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
14910
15113
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
14911
|
-
const routes = new
|
|
15114
|
+
const routes = new Elysia22({
|
|
14912
15115
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
14913
15116
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
14914
15117
|
if (tickPath !== false) {
|
|
@@ -14944,7 +15147,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
14944
15147
|
return routes;
|
|
14945
15148
|
};
|
|
14946
15149
|
// src/dataControl.ts
|
|
14947
|
-
import { Elysia as
|
|
15150
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
14948
15151
|
var voiceComplianceRedactionDefaults = {
|
|
14949
15152
|
keys: [
|
|
14950
15153
|
"apiKey",
|
|
@@ -15183,7 +15386,7 @@ var parseRetentionScopes = (value) => {
|
|
|
15183
15386
|
const allowed = new Set(allRetentionScopes);
|
|
15184
15387
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
15185
15388
|
};
|
|
15186
|
-
var
|
|
15389
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15187
15390
|
var buildStorageSurfaces = (options) => [
|
|
15188
15391
|
{
|
|
15189
15392
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -15420,12 +15623,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
15420
15623
|
zeroRetentionAvailable: true
|
|
15421
15624
|
};
|
|
15422
15625
|
};
|
|
15423
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
15626
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml23(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml23(scope.skippedReason ?? "")}</td><td><code>${escapeHtml23(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
15424
15627
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
15425
15628
|
const title = options.title ?? "Voice Data Control";
|
|
15426
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
15427
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
15428
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
15629
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml23(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml23(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
15630
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml23(key.name)}</td><td><code>${escapeHtml23(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml23(key.recommendation)}</td></tr>`).join("");
|
|
15631
|
+
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:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1120px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml23(title)}</h1><p>Self-hosted data-control proof for retention, redaction, audit export, deletion planning, customer-owned storage, and provider key handling.</p><section class="summary"><div class="card"><strong>Redaction</strong><br>${report.redaction.enabled ? "enabled" : "disabled"}</div><div class="card"><strong>Retention dry-run deletes</strong><br>${report.retentionPlan.deletedCount}</div><div class="card"><strong>Audit export events</strong><br>${report.auditExport?.events.length ?? 0}</div><div class="card"><strong>Zero retention recipe</strong><br>${report.zeroRetentionAvailable ? "available" : "missing"}</div></section><h2>Customer-Owned Storage</h2><table><thead><tr><th>Surface</th><th>Status</th><th>Control</th><th>Self-hosted</th></tr></thead><tbody>${storageRows}</tbody></table><h2>Retention Plan</h2><table><thead><tr><th>Scope</th><th>Scanned</th><th>Would delete</th><th>Skipped</th><th>Ids</th></tr></thead><tbody>${renderDataRetentionReportRows(report.retentionPlan)}</tbody></table><h2>Provider Keys</h2><table><thead><tr><th>Provider</th><th>Env</th><th>Required</th><th>Recommendation</th></tr></thead><tbody>${keyRows}</tbody></table><p><a href="./data-control/audit.md">Redacted audit Markdown</a> \xB7 <a href="./data-control/audit.html">Redacted audit HTML</a></p></main></body></html>`;
|
|
15429
15632
|
};
|
|
15430
15633
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
15431
15634
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -15483,7 +15686,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
15483
15686
|
var createVoiceDataControlRoutes = (options) => {
|
|
15484
15687
|
const path = options.path ?? "/data-control";
|
|
15485
15688
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
15486
|
-
const routes = new
|
|
15689
|
+
const routes = new Elysia23({
|
|
15487
15690
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
15488
15691
|
});
|
|
15489
15692
|
routes.get(path, async ({ query }) => {
|
|
@@ -15559,16 +15762,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
15559
15762
|
return routes;
|
|
15560
15763
|
};
|
|
15561
15764
|
// src/evalRoutes.ts
|
|
15562
|
-
import { Elysia as
|
|
15765
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
15563
15766
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
15564
15767
|
import { dirname as dirname2 } from "path";
|
|
15565
15768
|
|
|
15566
15769
|
// src/qualityRoutes.ts
|
|
15567
|
-
import { Elysia as
|
|
15770
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15568
15771
|
|
|
15569
15772
|
// src/handoffHealth.ts
|
|
15570
|
-
import { Elysia as
|
|
15571
|
-
var
|
|
15773
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15774
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15572
15775
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15573
15776
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
15574
15777
|
var increment3 = (record, key) => {
|
|
@@ -15686,10 +15889,10 @@ var renderActionSummary = (summary) => {
|
|
|
15686
15889
|
return [
|
|
15687
15890
|
'<section class="voice-handoff-health-columns">',
|
|
15688
15891
|
"<article><h3>Actions</h3>",
|
|
15689
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
15892
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml24(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
15690
15893
|
"</article>",
|
|
15691
15894
|
"<article><h3>Adapters</h3>",
|
|
15692
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
15895
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml24(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
15693
15896
|
"</article>",
|
|
15694
15897
|
"</section>"
|
|
15695
15898
|
].join("");
|
|
@@ -15703,22 +15906,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
15703
15906
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
15704
15907
|
'<div class="voice-handoff-health-events">',
|
|
15705
15908
|
...summary.events.map((event) => [
|
|
15706
|
-
`<article class="${
|
|
15909
|
+
`<article class="${escapeHtml24(event.status)}">`,
|
|
15707
15910
|
'<div class="voice-handoff-health-event-header">',
|
|
15708
|
-
`<strong>${
|
|
15709
|
-
`<span>${
|
|
15911
|
+
`<strong>${escapeHtml24(event.action ?? "handoff")}</strong>`,
|
|
15912
|
+
`<span>${escapeHtml24(event.status)}</span>`,
|
|
15710
15913
|
"</div>",
|
|
15711
|
-
`<p><small>${
|
|
15712
|
-
event.target ? `<p>Target: ${
|
|
15713
|
-
event.reason ? `<p>Reason: ${
|
|
15914
|
+
`<p><small>${escapeHtml24(event.sessionId)}</small></p>`,
|
|
15915
|
+
event.target ? `<p>Target: ${escapeHtml24(event.target)}</p>` : "",
|
|
15916
|
+
event.reason ? `<p>Reason: ${escapeHtml24(event.reason)}</p>` : "",
|
|
15714
15917
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
15715
15918
|
"<li>",
|
|
15716
|
-
`${
|
|
15717
|
-
delivery.deliveredTo ? ` to ${
|
|
15718
|
-
delivery.error ? ` (${
|
|
15919
|
+
`${escapeHtml24(delivery.adapterId)}: ${escapeHtml24(delivery.status)}`,
|
|
15920
|
+
delivery.deliveredTo ? ` to ${escapeHtml24(delivery.deliveredTo)}` : "",
|
|
15921
|
+
delivery.error ? ` (${escapeHtml24(delivery.error)})` : "",
|
|
15719
15922
|
"</li>"
|
|
15720
15923
|
].join("")).join("")}</ul>` : "",
|
|
15721
|
-
event.replayHref ? `<p><a href="${
|
|
15924
|
+
event.replayHref ? `<p><a href="${escapeHtml24(event.replayHref)}">Open replay</a></p>` : "",
|
|
15722
15925
|
"</article>"
|
|
15723
15926
|
].join("")),
|
|
15724
15927
|
"</div>"
|
|
@@ -15750,7 +15953,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
15750
15953
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
15751
15954
|
const path = options.path ?? "/api/voice-handoffs";
|
|
15752
15955
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
15753
|
-
const routes = new
|
|
15956
|
+
const routes = new Elysia24({
|
|
15754
15957
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
15755
15958
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
15756
15959
|
if (htmlPath) {
|
|
@@ -15871,17 +16074,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
15871
16074
|
thresholds
|
|
15872
16075
|
};
|
|
15873
16076
|
};
|
|
15874
|
-
var
|
|
16077
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15875
16078
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
15876
16079
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
15877
16080
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
15878
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
15879
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16081
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml25(metric.label)}</td><td>${escapeHtml25(formatMetricValue(metric))}</td><td>${escapeHtml25(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml25(key)}</code></td></tr>`).join("");
|
|
16082
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15880
16083
|
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>`;
|
|
15881
16084
|
};
|
|
15882
16085
|
var createVoiceQualityRoutes = (options) => {
|
|
15883
16086
|
const path = options.path ?? "/quality";
|
|
15884
|
-
const routes = new
|
|
16087
|
+
const routes = new Elysia25({
|
|
15885
16088
|
name: options.name ?? "absolutejs-voice-quality"
|
|
15886
16089
|
});
|
|
15887
16090
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -15910,7 +16113,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
15910
16113
|
};
|
|
15911
16114
|
|
|
15912
16115
|
// src/evalRoutes.ts
|
|
15913
|
-
var
|
|
16116
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15914
16117
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
15915
16118
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
15916
16119
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -16232,7 +16435,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
16232
16435
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
16233
16436
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
16234
16437
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
16235
|
-
const snippet =
|
|
16438
|
+
const snippet = escapeHtml26(`app.use(
|
|
16236
16439
|
createVoiceEvalRoutes({
|
|
16237
16440
|
path: '/evals',
|
|
16238
16441
|
store: traceStore,
|
|
@@ -16253,48 +16456,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
16253
16456
|
};
|
|
16254
16457
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
16255
16458
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
16256
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16257
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
16459
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16460
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml26(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>';
|
|
16258
16461
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
16259
16462
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
16260
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16261
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16463
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml26(session.operationsRecordHref)}">${escapeHtml26(session.sessionId)}</a>` : escapeHtml26(session.sessionId);
|
|
16464
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml26(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml26(formatTime(session.endedAt))}</td><td>${escapeHtml26(failedMetrics || "none")}</td></tr>`;
|
|
16262
16465
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
16263
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16466
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,.primitive{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3;margin:1rem 0}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}<h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
16264
16467
|
};
|
|
16265
16468
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
16266
16469
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
16267
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16268
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
16269
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
16270
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
16271
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16470
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16471
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml26(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
16472
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml26(id)}</li>`).join("") : "<li>none</li>";
|
|
16473
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml26(id)}</li>`).join("") : "<li>none</li>";
|
|
16474
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{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>${escapeHtml26(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml26(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml26(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>${escapeHtml26(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>`;
|
|
16272
16475
|
};
|
|
16273
16476
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
16274
16477
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
16275
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16478
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16276
16479
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
16277
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
16480
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml26(issue)}</li>`).join("")}</ul>` : "";
|
|
16278
16481
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
16279
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16280
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16482
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml26(session.operationsRecordHref)}">${escapeHtml26(session.sessionId)}</a>` : escapeHtml26(session.sessionId);
|
|
16483
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml26(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml26(session.issues.join(", ") || "none")}</td></tr>`;
|
|
16281
16484
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
16282
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
16485
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml26(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml26(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>`;
|
|
16283
16486
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
16284
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16487
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${scenarios}</main></body></html>`;
|
|
16285
16488
|
};
|
|
16286
16489
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
16287
16490
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
16288
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16491
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16289
16492
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
16290
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
16291
|
-
return `<section class="${fixture.status}"><h2>${
|
|
16493
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml26(scenario.label)}</td><td>${escapeHtml26(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml26([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
16494
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml26(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml26(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>`;
|
|
16292
16495
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
16293
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16496
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${fixtures}</main></body></html>`;
|
|
16294
16497
|
};
|
|
16295
16498
|
var createVoiceEvalRoutes = (options) => {
|
|
16296
16499
|
const path = options.path ?? "/evals";
|
|
16297
|
-
const routes = new
|
|
16500
|
+
const routes = new Elysia26({
|
|
16298
16501
|
name: options.name ?? "absolutejs-voice-evals"
|
|
16299
16502
|
});
|
|
16300
16503
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -16431,11 +16634,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
16431
16634
|
return routes;
|
|
16432
16635
|
};
|
|
16433
16636
|
// src/simulationSuite.ts
|
|
16434
|
-
import { Elysia as
|
|
16637
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
16435
16638
|
|
|
16436
16639
|
// src/outcomeContract.ts
|
|
16437
|
-
import { Elysia as
|
|
16438
|
-
var
|
|
16640
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16641
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16439
16642
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
16440
16643
|
if (value === false) {
|
|
16441
16644
|
return;
|
|
@@ -16646,13 +16849,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
16646
16849
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
16647
16850
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
16648
16851
|
const contracts = report.contracts.map((contract) => {
|
|
16649
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
16852
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml27(href)}">${escapeHtml27(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
16650
16853
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16651
16854
|
<div class="contract-header">
|
|
16652
16855
|
<div>
|
|
16653
|
-
<p class="eyebrow">${
|
|
16654
|
-
<h2>${
|
|
16655
|
-
${contract.description ? `<p>${
|
|
16856
|
+
<p class="eyebrow">${escapeHtml27(contract.contractId)}</p>
|
|
16857
|
+
<h2>${escapeHtml27(contract.label ?? contract.contractId)}</h2>
|
|
16858
|
+
${contract.description ? `<p>${escapeHtml27(contract.description)}</p>` : ""}
|
|
16656
16859
|
${sessionLinks}
|
|
16657
16860
|
</div>
|
|
16658
16861
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -16664,10 +16867,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
16664
16867
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
16665
16868
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
16666
16869
|
</div>
|
|
16667
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
16870
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml27(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
16668
16871
|
</section>`;
|
|
16669
16872
|
}).join("");
|
|
16670
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16873
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml27(title)}</title><style>body{background:#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>${escapeHtml27(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>`;
|
|
16671
16874
|
};
|
|
16672
16875
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
16673
16876
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -16683,7 +16886,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
16683
16886
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
16684
16887
|
const path = options.path ?? "/api/outcome-contracts";
|
|
16685
16888
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16686
|
-
const routes = new
|
|
16889
|
+
const routes = new Elysia27({
|
|
16687
16890
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
16688
16891
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
16689
16892
|
if (htmlPath) {
|
|
@@ -16693,7 +16896,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
16693
16896
|
};
|
|
16694
16897
|
|
|
16695
16898
|
// src/toolContract.ts
|
|
16696
|
-
import { Elysia as
|
|
16899
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16697
16900
|
|
|
16698
16901
|
// src/toolRuntime.ts
|
|
16699
16902
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -16902,7 +17105,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
16902
17105
|
});
|
|
16903
17106
|
var defaultApi = {};
|
|
16904
17107
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
16905
|
-
var
|
|
17108
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16906
17109
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
16907
17110
|
if (value === false) {
|
|
16908
17111
|
return;
|
|
@@ -17151,7 +17354,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
17151
17354
|
};
|
|
17152
17355
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
17153
17356
|
const title = options.title ?? "Voice Tool Contracts";
|
|
17154
|
-
const snippet =
|
|
17357
|
+
const snippet = escapeHtml28(`app.use(
|
|
17155
17358
|
createVoiceToolContractRoutes({
|
|
17156
17359
|
htmlPath: '/tool-contracts',
|
|
17157
17360
|
path: '/api/tool-contracts',
|
|
@@ -17177,20 +17380,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17177
17380
|
);`);
|
|
17178
17381
|
const contracts = report.contracts.map((contract) => {
|
|
17179
17382
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
17180
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
17383
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml28(testCase.operationsRecordHref)}">${escapeHtml28(testCase.label ?? testCase.caseId)}</a>` : escapeHtml28(testCase.label ?? testCase.caseId)}</td>
|
|
17181
17384
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
17182
|
-
<td>${
|
|
17183
|
-
<td>${
|
|
17385
|
+
<td>${escapeHtml28(testCase.status)}</td>
|
|
17386
|
+
<td>${escapeHtml28(testCase.sessionId)}</td>
|
|
17184
17387
|
<td>${String(testCase.attempts)}</td>
|
|
17185
17388
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
17186
17389
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
17187
|
-
<td>${
|
|
17390
|
+
<td>${escapeHtml28(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
17188
17391
|
</tr>`).join("");
|
|
17189
17392
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17190
17393
|
<div class="contract-header">
|
|
17191
17394
|
<div>
|
|
17192
|
-
<p class="eyebrow">${
|
|
17193
|
-
<h2>${
|
|
17395
|
+
<p class="eyebrow">${escapeHtml28(contract.toolName)}</p>
|
|
17396
|
+
<h2>${escapeHtml28(contract.label ?? contract.contractId)}</h2>
|
|
17194
17397
|
</div>
|
|
17195
17398
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
17196
17399
|
</div>
|
|
@@ -17200,7 +17403,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17200
17403
|
</table>
|
|
17201
17404
|
</section>`;
|
|
17202
17405
|
}).join("");
|
|
17203
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17406
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.primitive{background:#151b20;border-color:#5a4421}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}.primitive p{color:#d8dee6;line-height:1.55}.primitive pre{background:#0f1217;border:1px solid #2a323a;border-radius:16px;color:#fef3c7;overflow:auto;padding:14px}.primitive code{color:#fef3c7}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml28(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml28(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceToolContractRoutes(...)</code> certifies tool behavior</h2><p>Define deterministic tool cases for retries, idempotency, timeouts, result shape, and error handling so assistant tools fail in pre-production instead of live calls.</p><pre><code>${snippet}</code></pre></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
|
|
17204
17407
|
};
|
|
17205
17408
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
17206
17409
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -17217,7 +17420,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
17217
17420
|
var createVoiceToolContractRoutes = (options) => {
|
|
17218
17421
|
const path = options.path ?? "/api/tool-contracts";
|
|
17219
17422
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17220
|
-
const routes = new
|
|
17423
|
+
const routes = new Elysia28({
|
|
17221
17424
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
17222
17425
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
17223
17426
|
if (htmlPath) {
|
|
@@ -17227,7 +17430,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
17227
17430
|
};
|
|
17228
17431
|
|
|
17229
17432
|
// src/simulationSuite.ts
|
|
17230
|
-
var
|
|
17433
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17231
17434
|
var summarizeSection = (report) => ({
|
|
17232
17435
|
failed: report.failed,
|
|
17233
17436
|
passed: report.passed,
|
|
@@ -17423,15 +17626,15 @@ var renderSection = (label, summary) => {
|
|
|
17423
17626
|
if (!summary) {
|
|
17424
17627
|
return "";
|
|
17425
17628
|
}
|
|
17426
|
-
return `<article class="${
|
|
17629
|
+
return `<article class="${escapeHtml29(summary.status)}"><span>${escapeHtml29(label)}</span><strong>${escapeHtml29(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
17427
17630
|
};
|
|
17428
17631
|
var renderAction = (action) => {
|
|
17429
|
-
const content = `<strong>${
|
|
17430
|
-
return action.href ? `<a class="action" href="${
|
|
17632
|
+
const content = `<strong>${escapeHtml29(action.label)}</strong><p>${escapeHtml29(action.description)}</p><span>${escapeHtml29(action.section)} / ${escapeHtml29(action.severity)}</span>`;
|
|
17633
|
+
return action.href ? `<a class="action" href="${escapeHtml29(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
17431
17634
|
};
|
|
17432
17635
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
17433
17636
|
const title = options.title ?? "Voice Simulation Suite";
|
|
17434
|
-
const snippet =
|
|
17637
|
+
const snippet = escapeHtml29(`app.use(
|
|
17435
17638
|
createVoiceSimulationSuiteRoutes({
|
|
17436
17639
|
htmlPath: '/voice/simulations',
|
|
17437
17640
|
path: '/api/voice/simulations',
|
|
@@ -17464,12 +17667,12 @@ app.use(
|
|
|
17464
17667
|
store: traceStore
|
|
17465
17668
|
})
|
|
17466
17669
|
);`);
|
|
17467
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17670
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml29(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#355078}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p,.primitive p{color:#d8dee6;line-height:1.55;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}.primitive pre{background:#0b1118;color:#dbeafe}.primitive code{color:#bfdbfe}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml29(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml29(report.status)}">Status: ${escapeHtml29(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceSimulationSuiteRoutes(...)</code> builds this pre-production proof surface</h2><p>Run session quality checks, scenario evals, fixture-backed simulations, tool contracts, and outcome contracts from one route group before live traffic sees a regression.</p><pre><code>${snippet}</code></pre></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml29(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
17468
17671
|
};
|
|
17469
17672
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
17470
17673
|
const path = options.path ?? "/api/voice/simulations";
|
|
17471
17674
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
17472
|
-
const app = new
|
|
17675
|
+
const app = new Elysia29({
|
|
17473
17676
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
17474
17677
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
17475
17678
|
if (htmlPath) {
|
|
@@ -17781,9 +17984,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
17781
17984
|
};
|
|
17782
17985
|
};
|
|
17783
17986
|
// src/sessionReplay.ts
|
|
17784
|
-
import { Elysia as
|
|
17987
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
17785
17988
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
17786
|
-
var
|
|
17989
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17787
17990
|
var increment4 = (record, key) => {
|
|
17788
17991
|
record[key] = (record[key] ?? 0) + 1;
|
|
17789
17992
|
};
|
|
@@ -17977,10 +18180,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
17977
18180
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
17978
18181
|
'<div class="voice-sessions-list">',
|
|
17979
18182
|
...sessions.map((session) => [
|
|
17980
|
-
`<article class="voice-session-card ${
|
|
18183
|
+
`<article class="voice-session-card ${escapeHtml30(session.status)}">`,
|
|
17981
18184
|
'<div class="voice-session-card-header">',
|
|
17982
|
-
`<strong>${
|
|
17983
|
-
`<span>${
|
|
18185
|
+
`<strong>${escapeHtml30(session.sessionId)}</strong>`,
|
|
18186
|
+
`<span>${escapeHtml30(session.status)}</span>`,
|
|
17984
18187
|
"</div>",
|
|
17985
18188
|
"<dl>",
|
|
17986
18189
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -17988,9 +18191,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
17988
18191
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
17989
18192
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
17990
18193
|
"</dl>",
|
|
17991
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
17992
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
17993
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
18194
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml30(session.latestOutcome)}</p>` : "",
|
|
18195
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml30).join(", ")}</p>` : "",
|
|
18196
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml30(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml30(session.replayHref)}">Open replay</a></p>` : "",
|
|
17994
18197
|
"</article>"
|
|
17995
18198
|
].join("")),
|
|
17996
18199
|
"</div>"
|
|
@@ -18021,7 +18224,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
18021
18224
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
18022
18225
|
const path = options.path ?? "/api/voice-sessions";
|
|
18023
18226
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18024
|
-
const routes = new
|
|
18227
|
+
const routes = new Elysia30({
|
|
18025
18228
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
18026
18229
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
18027
18230
|
if (htmlPath) {
|
|
@@ -18049,7 +18252,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
18049
18252
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
18050
18253
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
18051
18254
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18052
|
-
const routes = new
|
|
18255
|
+
const routes = new Elysia30({
|
|
18053
18256
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
18054
18257
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
18055
18258
|
if (htmlPath) {
|
|
@@ -18363,10 +18566,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
18363
18566
|
return report;
|
|
18364
18567
|
};
|
|
18365
18568
|
// src/turnLatency.ts
|
|
18366
|
-
import { Elysia as
|
|
18569
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
18367
18570
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
18368
18571
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
18369
|
-
var
|
|
18572
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18370
18573
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18371
18574
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
18372
18575
|
var createTraceStageIndex = (events) => {
|
|
@@ -18498,11 +18701,11 @@ await traceStore.append({
|
|
|
18498
18701
|
turnId,
|
|
18499
18702
|
type: 'turn_latency.stage'
|
|
18500
18703
|
});`;
|
|
18501
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18502
|
-
<header><div><p class="eyebrow">${
|
|
18503
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
18704
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml31(turn.status)}">
|
|
18705
|
+
<header><div><p class="eyebrow">${escapeHtml31(turn.sessionId)} \xB7 ${escapeHtml31(turn.turnId)}</p><h2>${escapeHtml31(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml31(turn.status)}</strong></header>
|
|
18706
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml31(stage.label)}</dt><dd>${escapeHtml31(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
18504
18707
|
</article>`).join("");
|
|
18505
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18708
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn,.primitive{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml31(title)}</h1><div class="summary"><span class="pill ${escapeHtml31(report.status)}">${escapeHtml31(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml31(formatMs2(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml31(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
18506
18709
|
};
|
|
18507
18710
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
18508
18711
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -18519,7 +18722,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
18519
18722
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
18520
18723
|
const path = options.path ?? "/api/turn-latency";
|
|
18521
18724
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18522
|
-
const routes = new
|
|
18725
|
+
const routes = new Elysia31({
|
|
18523
18726
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
18524
18727
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
18525
18728
|
if (htmlPath) {
|
|
@@ -18528,8 +18731,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
18528
18731
|
return routes;
|
|
18529
18732
|
};
|
|
18530
18733
|
// src/liveLatency.ts
|
|
18531
|
-
import { Elysia as
|
|
18532
|
-
var
|
|
18734
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
18735
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18533
18736
|
var percentile3 = (values, percentileValue) => {
|
|
18534
18737
|
if (values.length === 0) {
|
|
18535
18738
|
return;
|
|
@@ -18596,13 +18799,13 @@ await traceStore.append({
|
|
|
18596
18799
|
sessionId,
|
|
18597
18800
|
type: 'client.live_latency'
|
|
18598
18801
|
});`;
|
|
18599
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
18600
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18802
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml32(sample.sessionId)}</td><td>${escapeHtml32(formatMs3(sample.latencyMs))}</td><td>${escapeHtml32(sample.status ?? "unknown")}</td><td>${escapeHtml32(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
18803
|
+
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:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml32(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml32(report.status)}">Status: ${escapeHtml32(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml32(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml32(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml32(formatMs3(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml32(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
18601
18804
|
};
|
|
18602
18805
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
18603
18806
|
const path = options.path ?? "/api/live-latency";
|
|
18604
18807
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
18605
|
-
const routes = new
|
|
18808
|
+
const routes = new Elysia32({
|
|
18606
18809
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
18607
18810
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
18608
18811
|
if (htmlPath) {
|
|
@@ -18921,9 +19124,9 @@ None.
|
|
|
18921
19124
|
`}`;
|
|
18922
19125
|
};
|
|
18923
19126
|
// src/turnQuality.ts
|
|
18924
|
-
import { Elysia as
|
|
19127
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18925
19128
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
18926
|
-
var
|
|
19129
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18927
19130
|
var getTurnLatencyMs = (turn) => {
|
|
18928
19131
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18929
19132
|
if (firstTranscriptAt === undefined) {
|
|
@@ -18994,24 +19197,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
18994
19197
|
};
|
|
18995
19198
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
18996
19199
|
const title = options.title ?? "Voice Turn Quality";
|
|
18997
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19200
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml33(turn.status)}">
|
|
18998
19201
|
<div class="turn-header">
|
|
18999
19202
|
<div>
|
|
19000
|
-
<p class="eyebrow">${
|
|
19001
|
-
<h2>${
|
|
19203
|
+
<p class="eyebrow">${escapeHtml33(turn.sessionId)} \xB7 ${escapeHtml33(turn.turnId)}</p>
|
|
19204
|
+
<h2>${escapeHtml33(turn.text || "Empty turn")}</h2>
|
|
19002
19205
|
</div>
|
|
19003
|
-
<strong>${
|
|
19206
|
+
<strong>${escapeHtml33(turn.status)}</strong>
|
|
19004
19207
|
</div>
|
|
19005
19208
|
<dl>
|
|
19006
|
-
<div><dt>Source</dt><dd>${
|
|
19209
|
+
<div><dt>Source</dt><dd>${escapeHtml33(turn.source ?? "unknown")}</dd></div>
|
|
19007
19210
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
19008
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
19009
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
19211
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml33(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
19212
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml33(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
19010
19213
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
19011
19214
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
19012
19215
|
</dl>
|
|
19013
19216
|
</article>`).join("");
|
|
19014
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19217
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(title)}</title><style>body{background:#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>${escapeHtml33(title)}</h1><div class="summary"><span class="pill ${escapeHtml33(report.status)}">${escapeHtml33(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>`;
|
|
19015
19218
|
};
|
|
19016
19219
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
19017
19220
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -19028,7 +19231,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
19028
19231
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
19029
19232
|
const path = options.path ?? "/api/turn-quality";
|
|
19030
19233
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19031
|
-
const routes = new
|
|
19234
|
+
const routes = new Elysia33({
|
|
19032
19235
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
19033
19236
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
19034
19237
|
if (htmlPath) {
|
|
@@ -19037,7 +19240,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
19037
19240
|
return routes;
|
|
19038
19241
|
};
|
|
19039
19242
|
// src/telephonyOutcome.ts
|
|
19040
|
-
import { Elysia as
|
|
19243
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19041
19244
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
19042
19245
|
"answered",
|
|
19043
19246
|
"completed",
|
|
@@ -19798,7 +20001,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
19798
20001
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
19799
20002
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
19800
20003
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
19801
|
-
return new
|
|
20004
|
+
return new Elysia34({
|
|
19802
20005
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
19803
20006
|
}).post(path, async ({ query, request }) => {
|
|
19804
20007
|
try {
|
|
@@ -19819,12 +20022,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
19819
20022
|
});
|
|
19820
20023
|
};
|
|
19821
20024
|
// src/phoneAgent.ts
|
|
19822
|
-
import { Elysia as
|
|
20025
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
19823
20026
|
|
|
19824
20027
|
// src/telephony/plivo.ts
|
|
19825
20028
|
import { Buffer as Buffer5 } from "buffer";
|
|
19826
20029
|
import { Database } from "bun:sqlite";
|
|
19827
|
-
import { Elysia as
|
|
20030
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
19828
20031
|
|
|
19829
20032
|
// src/telephony/contract.ts
|
|
19830
20033
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -19908,7 +20111,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
19908
20111
|
|
|
19909
20112
|
// src/telephony/twilio.ts
|
|
19910
20113
|
import { Buffer as Buffer4 } from "buffer";
|
|
19911
|
-
import { Elysia as
|
|
20114
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19912
20115
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
19913
20116
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
19914
20117
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -19938,7 +20141,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
19938
20141
|
return parameters;
|
|
19939
20142
|
};
|
|
19940
20143
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19941
|
-
var
|
|
20144
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19942
20145
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
19943
20146
|
if (!webhook?.verificationUrl) {
|
|
19944
20147
|
return;
|
|
@@ -19981,23 +20184,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
19981
20184
|
};
|
|
19982
20185
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19983
20186
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
19984
|
-
<h1>${
|
|
20187
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
19985
20188
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
19986
20189
|
<section>
|
|
19987
20190
|
<h2>URLs</h2>
|
|
19988
20191
|
<ul>
|
|
19989
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19990
|
-
<li><strong>Media stream:</strong> <code>${
|
|
19991
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
20192
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml34(status.urls.twiml)}</code></li>
|
|
20193
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml34(status.urls.stream)}</code></li>
|
|
20194
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml34(status.urls.webhook)}</code></li>
|
|
19992
20195
|
</ul>
|
|
19993
20196
|
</section>
|
|
19994
20197
|
<section>
|
|
19995
20198
|
<h2>Signing</h2>
|
|
19996
20199
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
19997
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
20200
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml34(status.signing.verificationUrl)}</code></p>` : ""}
|
|
19998
20201
|
</section>
|
|
19999
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20000
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
20202
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml34(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
20203
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml34(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
20001
20204
|
</main>`;
|
|
20002
20205
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
20003
20206
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -20008,20 +20211,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
20008
20211
|
});
|
|
20009
20212
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20010
20213
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
20011
|
-
<h1>${
|
|
20214
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
20012
20215
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20013
20216
|
<section>
|
|
20014
20217
|
<h2>Checks</h2>
|
|
20015
20218
|
<ul>
|
|
20016
|
-
${report.checks.map((check) => `<li><strong>${
|
|
20219
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml34(check.name)}</strong>: ${escapeHtml34(check.status)}${check.message ? ` - ${escapeHtml34(check.message)}` : ""}</li>`).join("")}
|
|
20017
20220
|
</ul>
|
|
20018
20221
|
</section>
|
|
20019
20222
|
<section>
|
|
20020
20223
|
<h2>Observed URLs</h2>
|
|
20021
20224
|
<ul>
|
|
20022
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20023
|
-
<li><strong>Stream:</strong> <code>${
|
|
20024
|
-
<li><strong>Webhook:</strong> <code>${
|
|
20225
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml34(report.setup.urls.twiml)}</code></li>
|
|
20226
|
+
<li><strong>Stream:</strong> <code>${escapeHtml34(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
20227
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml34(report.setup.urls.webhook)}</code></li>
|
|
20025
20228
|
</ul>
|
|
20026
20229
|
</section>
|
|
20027
20230
|
</main>`;
|
|
@@ -20481,7 +20684,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20481
20684
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
20482
20685
|
const bridges = new WeakMap;
|
|
20483
20686
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
20484
|
-
const app = new
|
|
20687
|
+
const app = new Elysia35({
|
|
20485
20688
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
20486
20689
|
}).get(twimlPath, async ({ query, request }) => {
|
|
20487
20690
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -20618,7 +20821,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20618
20821
|
|
|
20619
20822
|
// src/telephony/plivo.ts
|
|
20620
20823
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20621
|
-
var
|
|
20824
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20622
20825
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20623
20826
|
var resolveRequestOrigin2 = (request) => {
|
|
20624
20827
|
const url = new URL(request.url);
|
|
@@ -21048,21 +21251,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
21048
21251
|
};
|
|
21049
21252
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21050
21253
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
21051
|
-
<h1>${
|
|
21254
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21052
21255
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21053
21256
|
<ul>
|
|
21054
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
21055
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
21056
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21257
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml35(status.urls.answer)}</code></li>
|
|
21258
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml35(status.urls.stream)}</code></li>
|
|
21259
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml35(status.urls.webhook)}</code></li>
|
|
21057
21260
|
</ul>
|
|
21058
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21059
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21261
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml35(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21262
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml35(warning)}</li>`).join("")}</ul>` : ""}
|
|
21060
21263
|
</main>`;
|
|
21061
21264
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21062
21265
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
21063
|
-
<h1>${
|
|
21266
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21064
21267
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21065
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21268
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml35(check.name)}</strong>: ${escapeHtml35(check.status)}${check.message ? ` - ${escapeHtml35(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21066
21269
|
</main>`;
|
|
21067
21270
|
var runPlivoSmokeTest = async (input) => {
|
|
21068
21271
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -21152,7 +21355,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21152
21355
|
nonceStore: options.webhook.nonceStore,
|
|
21153
21356
|
verificationUrl: options.webhook.verificationUrl
|
|
21154
21357
|
}) : undefined);
|
|
21155
|
-
const app = new
|
|
21358
|
+
const app = new Elysia36({
|
|
21156
21359
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
21157
21360
|
}).get(answerPath, async ({ query, request }) => {
|
|
21158
21361
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -21264,9 +21467,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21264
21467
|
// src/telephony/telnyx.ts
|
|
21265
21468
|
import { Buffer as Buffer6 } from "buffer";
|
|
21266
21469
|
import { Database as Database2 } from "bun:sqlite";
|
|
21267
|
-
import { Elysia as
|
|
21470
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
21268
21471
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21269
|
-
var
|
|
21472
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21270
21473
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21271
21474
|
var resolveRequestOrigin3 = (request) => {
|
|
21272
21475
|
const url = new URL(request.url);
|
|
@@ -21659,21 +21862,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
21659
21862
|
};
|
|
21660
21863
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21661
21864
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
21662
|
-
<h1>${
|
|
21865
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
21663
21866
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21664
21867
|
<ul>
|
|
21665
|
-
<li><strong>TeXML:</strong> <code>${
|
|
21666
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21667
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21868
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml36(status.urls.texml)}</code></li>
|
|
21869
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml36(status.urls.stream)}</code></li>
|
|
21870
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml36(status.urls.webhook)}</code></li>
|
|
21668
21871
|
</ul>
|
|
21669
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21670
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21872
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml36(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21873
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml36(warning)}</li>`).join("")}</ul>` : ""}
|
|
21671
21874
|
</main>`;
|
|
21672
21875
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21673
21876
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
21674
|
-
<h1>${
|
|
21877
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
21675
21878
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21676
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21879
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml36(check.name)}</strong>: ${escapeHtml36(check.status)}${check.message ? ` - ${escapeHtml36(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21677
21880
|
</main>`;
|
|
21678
21881
|
var runTelnyxSmokeTest = async (input) => {
|
|
21679
21882
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -21766,7 +21969,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21766
21969
|
publicKey: options.webhook.publicKey,
|
|
21767
21970
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
21768
21971
|
}) : undefined);
|
|
21769
|
-
const app = new
|
|
21972
|
+
const app = new Elysia37({
|
|
21770
21973
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
21771
21974
|
}).get(texmlPath, async ({ query, request }) => {
|
|
21772
21975
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -21876,8 +22079,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21876
22079
|
};
|
|
21877
22080
|
|
|
21878
22081
|
// src/telephony/matrix.ts
|
|
21879
|
-
import { Elysia as
|
|
21880
|
-
var
|
|
22082
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
22083
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21881
22084
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
21882
22085
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
21883
22086
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -21938,13 +22141,13 @@ var badgeStyles = {
|
|
|
21938
22141
|
};
|
|
21939
22142
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
21940
22143
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
21941
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
22144
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml37(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
21942
22145
|
<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>
|
|
21943
22146
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
21944
22147
|
${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);">
|
|
21945
22148
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
21946
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
21947
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
22149
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml37(entry.name)}</h2>
|
|
22150
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml37(entry.status.toUpperCase())}</span>
|
|
21948
22151
|
</div>
|
|
21949
22152
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
21950
22153
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -21952,15 +22155,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
21952
22155
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
21953
22156
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
21954
22157
|
</dl>
|
|
21955
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
21956
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
21957
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
22158
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml37(entry.setup.urls.stream || "missing")}</code></p>
|
|
22159
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml37(entry.setup.urls.webhook || "missing")}</code></p>
|
|
22160
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml37(issue.severity)}: ${escapeHtml37(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
21958
22161
|
</article>`).join("")}
|
|
21959
22162
|
</section>
|
|
21960
22163
|
</main>`;
|
|
21961
22164
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
21962
22165
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
21963
|
-
return new
|
|
22166
|
+
return new Elysia38({
|
|
21964
22167
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
21965
22168
|
}).get(path, async ({ query, request }) => {
|
|
21966
22169
|
const providers = await options.load({ query, request });
|
|
@@ -21982,7 +22185,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
21982
22185
|
};
|
|
21983
22186
|
|
|
21984
22187
|
// src/phoneAgentProductionSmoke.ts
|
|
21985
|
-
import { Elysia as
|
|
22188
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
21986
22189
|
var defaultRequirements = [
|
|
21987
22190
|
"media-started",
|
|
21988
22191
|
"transcript",
|
|
@@ -21990,7 +22193,7 @@ var defaultRequirements = [
|
|
|
21990
22193
|
"lifecycle-outcome",
|
|
21991
22194
|
"no-session-error"
|
|
21992
22195
|
];
|
|
21993
|
-
var
|
|
22196
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21994
22197
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
21995
22198
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
21996
22199
|
const value = event.payload[key];
|
|
@@ -22099,10 +22302,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
22099
22302
|
});
|
|
22100
22303
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
22101
22304
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
22102
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
22103
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
22104
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
22105
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22305
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml38(issue.requirement)}</strong>: ${escapeHtml38(issue.message)}</li>`).join("");
|
|
22306
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml38(outcome)}</span>`).join("");
|
|
22307
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml38(requirement)}</span>`).join("");
|
|
22308
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(title)}</title><style>body{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>${escapeHtml38(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml38(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml38(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml38(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>`;
|
|
22106
22309
|
};
|
|
22107
22310
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
22108
22311
|
query,
|
|
@@ -22125,7 +22328,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
22125
22328
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
22126
22329
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
22127
22330
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
22128
|
-
const routes = new
|
|
22331
|
+
const routes = new Elysia39({
|
|
22129
22332
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
22130
22333
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
22131
22334
|
if (htmlPath) {
|
|
@@ -22168,7 +22371,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
22168
22371
|
"completed",
|
|
22169
22372
|
"failed"
|
|
22170
22373
|
];
|
|
22171
|
-
var
|
|
22374
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22172
22375
|
var loadRouteJson = async (input) => {
|
|
22173
22376
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
22174
22377
|
headers: {
|
|
@@ -22406,10 +22609,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
22406
22609
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
22407
22610
|
const urls = entry?.setup.urls;
|
|
22408
22611
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
22409
|
-
return `<tr><td>${
|
|
22612
|
+
return `<tr><td>${escapeHtml39(carrier.name ?? carrier.provider)}</td><td>${escapeHtml39(carrier.provider)}</td><td><code>${escapeHtml39(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml39(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml39(entry.status)}">${escapeHtml39(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml39(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml39(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml39(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
22410
22613
|
}).join("");
|
|
22411
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
22412
|
-
const snippet =
|
|
22614
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml39(stage)}</code></li>`).join("");
|
|
22615
|
+
const snippet = escapeHtml39(`const phoneAgent = createVoicePhoneAgent({
|
|
22413
22616
|
carriers: [
|
|
22414
22617
|
{
|
|
22415
22618
|
provider: 'twilio',
|
|
@@ -22443,11 +22646,11 @@ app.use(
|
|
|
22443
22646
|
);`);
|
|
22444
22647
|
const checklist = report.carriers.map((carrier) => {
|
|
22445
22648
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
22446
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
22447
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
22448
|
-
return `<article><h3>${
|
|
22649
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml39(issue)}</li>`).join("") ?? "";
|
|
22650
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml39(step)}</li>`).join("") ?? "";
|
|
22651
|
+
return `<article><h3>${escapeHtml39(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
22449
22652
|
}).join("");
|
|
22450
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22653
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#365a60}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.primitive p{color:#cbd5de;line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #283544;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml39(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="${escapeHtml39(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoicePhoneAgent(...)</code> builds this carrier control plane</h2><p>Mount carrier routes once, expose setup and smoke proof, then feed the same carrier matrix and phone-agent smoke reports into production readiness so carrier regressions block deploys.</p><pre><code>${snippet}</code></pre></section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
|
|
22451
22654
|
};
|
|
22452
22655
|
var createVoicePhoneAgent = (options) => {
|
|
22453
22656
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -22456,7 +22659,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
22456
22659
|
setupPath: resolveSetupPath(carrier),
|
|
22457
22660
|
smokePath: resolveSmokePath(carrier)
|
|
22458
22661
|
}));
|
|
22459
|
-
const app = new
|
|
22662
|
+
const app = new Elysia40({
|
|
22460
22663
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
22461
22664
|
});
|
|
22462
22665
|
for (const carrier of options.carriers) {
|
|
@@ -24590,8 +24793,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24590
24793
|
};
|
|
24591
24794
|
};
|
|
24592
24795
|
// src/providerCapabilities.ts
|
|
24593
|
-
import { Elysia as
|
|
24594
|
-
var
|
|
24796
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
24797
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24595
24798
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
24596
24799
|
configured: true,
|
|
24597
24800
|
features: options.features?.[provider],
|
|
@@ -24654,27 +24857,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
24654
24857
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
24655
24858
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
24656
24859
|
const cards = report.capabilities.map((capability) => {
|
|
24657
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
24658
|
-
return `<article class="card ${
|
|
24860
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml40(feature)}</span>`).join("");
|
|
24861
|
+
return `<article class="card ${escapeHtml40(capability.status)}">
|
|
24659
24862
|
<div class="card-header">
|
|
24660
24863
|
<div>
|
|
24661
|
-
<p class="eyebrow">${
|
|
24662
|
-
<h2>${
|
|
24864
|
+
<p class="eyebrow">${escapeHtml40(capability.kind)}</p>
|
|
24865
|
+
<h2>${escapeHtml40(capability.label ?? capability.provider)}</h2>
|
|
24663
24866
|
</div>
|
|
24664
|
-
<strong>${
|
|
24867
|
+
<strong>${escapeHtml40(capability.status)}</strong>
|
|
24665
24868
|
</div>
|
|
24666
|
-
${capability.description ? `<p>${
|
|
24869
|
+
${capability.description ? `<p>${escapeHtml40(capability.description)}</p>` : ""}
|
|
24667
24870
|
<dl>
|
|
24668
24871
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
24669
24872
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
24670
|
-
<div><dt>Model</dt><dd>${
|
|
24873
|
+
<div><dt>Model</dt><dd>${escapeHtml40(capability.model ?? "default")}</dd></div>
|
|
24671
24874
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
24672
24875
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
24673
24876
|
</dl>
|
|
24674
24877
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
24675
24878
|
</article>`;
|
|
24676
24879
|
}).join("");
|
|
24677
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24880
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(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>${escapeHtml40(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>`;
|
|
24678
24881
|
};
|
|
24679
24882
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
24680
24883
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -24691,7 +24894,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
24691
24894
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
24692
24895
|
const path = options.path ?? "/api/provider-capabilities";
|
|
24693
24896
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
24694
|
-
const routes = new
|
|
24897
|
+
const routes = new Elysia41({
|
|
24695
24898
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
24696
24899
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
24697
24900
|
if (htmlPath) {
|
|
@@ -24700,7 +24903,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
24700
24903
|
return routes;
|
|
24701
24904
|
};
|
|
24702
24905
|
// src/providerOrchestration.ts
|
|
24703
|
-
import { Elysia as
|
|
24906
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
24704
24907
|
var defaultRequirement = {
|
|
24705
24908
|
minProviders: 1,
|
|
24706
24909
|
requireBudgetPolicy: false,
|
|
@@ -24708,12 +24911,12 @@ var defaultRequirement = {
|
|
|
24708
24911
|
requireFallback: false,
|
|
24709
24912
|
requireTimeoutBudget: false
|
|
24710
24913
|
};
|
|
24711
|
-
var
|
|
24914
|
+
var statusRank3 = {
|
|
24712
24915
|
pass: 0,
|
|
24713
24916
|
warn: 1,
|
|
24714
24917
|
fail: 2
|
|
24715
24918
|
};
|
|
24716
|
-
var
|
|
24919
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24717
24920
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24718
24921
|
var uniqueSorted6 = (values) => [
|
|
24719
24922
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -24724,7 +24927,7 @@ var surfaceProviderNames = (surface) => uniqueSorted6([
|
|
|
24724
24927
|
...isProviderList(surface.fallback) ? surface.fallback : [],
|
|
24725
24928
|
...isProviderList(surface.allowProviders) ? surface.allowProviders : []
|
|
24726
24929
|
]);
|
|
24727
|
-
var surfaceStatus = (issues) => issues.reduce((status, issue) =>
|
|
24930
|
+
var surfaceStatus = (issues) => issues.reduce((status, issue) => statusRank3[issue.status] > statusRank3[status] ? issue.status : status, "pass");
|
|
24728
24931
|
var resolvedRequirement = (surface, options) => ({
|
|
24729
24932
|
...defaultRequirement,
|
|
24730
24933
|
...options.defaultRequirement ?? {},
|
|
@@ -24856,27 +25059,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
24856
25059
|
};
|
|
24857
25060
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
24858
25061
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
24859
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
24860
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
25062
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml41(surface.status)}">
|
|
25063
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml41(surface.surface)}</p><h2>${escapeHtml41(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml41(surface.status)}</strong></div>
|
|
24861
25064
|
<dl>
|
|
24862
|
-
<div><dt>Providers</dt><dd>${
|
|
24863
|
-
<div><dt>Fallback</dt><dd>${
|
|
25065
|
+
<div><dt>Providers</dt><dd>${escapeHtml41(surface.providers.join(", ") || "none")}</dd></div>
|
|
25066
|
+
<div><dt>Fallback</dt><dd>${escapeHtml41(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
24864
25067
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
24865
25068
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
24866
25069
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
24867
25070
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
24868
25071
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
24869
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
25072
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml41(surface.fallbackMode || "default")}</dd></div>
|
|
24870
25073
|
</dl>
|
|
24871
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
25074
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml41(issue.status)}</strong> ${escapeHtml41(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
24872
25075
|
</article>`).join("");
|
|
24873
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25076
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#172033;border:1px solid #2d3b55;border-radius:22px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(59,130,246,.18),rgba(20,184,166,.12))}.eyebrow{color:#93c5fd;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f172a;border:1px solid #334155;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass strong{color:#86efac}.warn strong{color:#fde68a}.fail strong{color:#fca5a5}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0;overflow-wrap:anywhere}li{margin:.35rem 0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Policy Proof</p><h1>${escapeHtml41(title)}</h1><div class="summary"><span class="pill">${escapeHtml41(report.profileId)}</span><span class="pill">${escapeHtml41(report.status)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.providers)} providers</span><span class="pill">${String(report.issues.length)} issues</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider orchestration surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
24874
25077
|
};
|
|
24875
25078
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
24876
25079
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
24877
25080
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
24878
25081
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
24879
|
-
const routes = new
|
|
25082
|
+
const routes = new Elysia42({
|
|
24880
25083
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
24881
25084
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
24882
25085
|
if (htmlPath) {
|
|
@@ -25047,7 +25250,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
25047
25250
|
return report;
|
|
25048
25251
|
};
|
|
25049
25252
|
// src/providerSlo.ts
|
|
25050
|
-
import { Elysia as
|
|
25253
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
25051
25254
|
var defaultThresholds = {
|
|
25052
25255
|
llm: {
|
|
25053
25256
|
maxAverageElapsedMs: 2500,
|
|
@@ -25075,12 +25278,12 @@ var defaultThresholds = {
|
|
|
25075
25278
|
}
|
|
25076
25279
|
};
|
|
25077
25280
|
var providerKinds = ["llm", "stt", "tts"];
|
|
25078
|
-
var
|
|
25281
|
+
var statusRank4 = {
|
|
25079
25282
|
pass: 0,
|
|
25080
25283
|
warn: 1,
|
|
25081
25284
|
fail: 2
|
|
25082
25285
|
};
|
|
25083
|
-
var
|
|
25286
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25084
25287
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
25085
25288
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
25086
25289
|
var uniqueSorted7 = (values) => [
|
|
@@ -25272,7 +25475,7 @@ var evaluateVoiceProviderSloEvidence = (report, input = {}) => {
|
|
|
25272
25475
|
const timeouts = kindReports.reduce((total, kind) => total + kind.timeouts, 0);
|
|
25273
25476
|
const unresolvedErrors = kindReports.reduce((total, kind) => total + kind.unresolvedErrors, 0);
|
|
25274
25477
|
const maxStatus = input.maxStatus ?? "pass";
|
|
25275
|
-
if (
|
|
25478
|
+
if (statusRank4[report.status] > statusRank4[maxStatus]) {
|
|
25276
25479
|
issues.push(`Expected provider SLO status at most ${maxStatus}, found ${report.status}.`);
|
|
25277
25480
|
}
|
|
25278
25481
|
if (input.minEvents !== undefined && report.events < input.minEvents) {
|
|
@@ -25376,11 +25579,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25376
25579
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25377
25580
|
const kindCards = providerKinds.map((kind) => {
|
|
25378
25581
|
const kindReport = report.kinds[kind];
|
|
25379
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
25582
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml42(metric.label)}</dt><dd>${escapeHtml42(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml42(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
25380
25583
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25381
|
-
return `<article class="${
|
|
25584
|
+
return `<article class="${escapeHtml42(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml42(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml42(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
25382
25585
|
}).join("");
|
|
25383
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
25586
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml42(issue.status)}"><strong>${escapeHtml42(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml42(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
25384
25587
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25385
25588
|
store: runtimeStorage.traces,
|
|
25386
25589
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25390,7 +25593,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25390
25593
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25391
25594
|
}
|
|
25392
25595
|
})`;
|
|
25393
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25596
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#101318;color:#f8f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,article,.primitive{background:#171b22;border:1px solid #2c3340;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.2),rgba(245,158,11,.12))}.eyebrow{color:#7dd3fc;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.9rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status,article h2 span{border:1px solid #475569;border-radius:999px;display:inline-flex;font-size:.85rem;padding:6px 10px}.pass{border-color:rgba(34,197,94,.65)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}dt{color:#cbd5e1;font-size:.78rem;text-transform:uppercase}dd{font-size:1.7rem;font-weight:900;margin:0}small{color:#a8b3c2}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#101318;border:1px solid #2c3340;border-radius:16px;padding:12px}li span{color:#cbd5e1;display:block;margin-top:4px}.primitive{background:#11161d}.primitive code{color:#bae6fd}.primitive pre{background:#070b10;border:1px solid #243041;border-radius:16px;color:#e0f2fe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Provider latency and fallback proof</p><h1>${escapeHtml42(title)}</h1><p class="status ${escapeHtml42(report.status)}">${escapeHtml42(report.status)}</p><p>${report.events} provider routing event(s), ${report.eventsWithLatency} latency sample(s).</p></section><section class="grid">${kindCards}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderSloRoutes(...)</code> turns provider speed into release evidence</h2><p>Pair this report with production readiness so LLM/STT/TTS latency, timeout, fallback, and unresolved error regressions block deploys.</p><pre><code>${escapeHtml42(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
25394
25597
|
};
|
|
25395
25598
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25396
25599
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25401,7 +25604,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25401
25604
|
...options.headers ?? {}
|
|
25402
25605
|
};
|
|
25403
25606
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25404
|
-
const app = new
|
|
25607
|
+
const app = new Elysia43({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25405
25608
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25406
25609
|
if (markdownPath !== false) {
|
|
25407
25610
|
app.get(markdownPath, async () => {
|
|
@@ -25431,10 +25634,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25431
25634
|
return app;
|
|
25432
25635
|
};
|
|
25433
25636
|
// src/productionReadiness.ts
|
|
25434
|
-
import { Elysia as
|
|
25637
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
25435
25638
|
|
|
25436
25639
|
// src/telephony/security.ts
|
|
25437
|
-
import { Elysia as
|
|
25640
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25438
25641
|
|
|
25439
25642
|
// src/postgresStore.ts
|
|
25440
25643
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -26172,7 +26375,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
26172
26375
|
};
|
|
26173
26376
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
26174
26377
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
26175
|
-
return new
|
|
26378
|
+
return new Elysia44({
|
|
26176
26379
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
26177
26380
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
26178
26381
|
};
|
|
@@ -26229,8 +26432,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
26229
26432
|
};
|
|
26230
26433
|
|
|
26231
26434
|
// src/opsRecovery.ts
|
|
26232
|
-
import { Elysia as
|
|
26233
|
-
var
|
|
26435
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
26436
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26234
26437
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26235
26438
|
var hrefForSession = (value, sessionId) => {
|
|
26236
26439
|
if (typeof value === "function") {
|
|
@@ -26246,7 +26449,7 @@ var hrefForSession = (value, sessionId) => {
|
|
|
26246
26449
|
return value;
|
|
26247
26450
|
};
|
|
26248
26451
|
var operationsRecordHrefForSession = (links, sessionId) => hrefForSession(links?.operationsRecords, sessionId);
|
|
26249
|
-
var
|
|
26452
|
+
var rollupStatus3 = (issues) => issues.some((issue) => issue.severity === "fail") ? "fail" : issues.some((issue) => issue.severity === "warn") ? "warn" : "pass";
|
|
26250
26453
|
var providerUnresolved = (provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed";
|
|
26251
26454
|
var collectFailedSessions = (events, limit, links) => events.filter((event) => {
|
|
26252
26455
|
if (event.type !== "session.error") {
|
|
@@ -26394,7 +26597,7 @@ var buildVoiceOpsRecoveryReport = async (options = {}) => {
|
|
|
26394
26597
|
recoveredFallbacks: providers.reduce((total, provider) => total + provider.fallbackCount, 0),
|
|
26395
26598
|
unresolvedFailures: unresolvedProviders.length
|
|
26396
26599
|
},
|
|
26397
|
-
status:
|
|
26600
|
+
status: rollupStatus3(issues),
|
|
26398
26601
|
traceDeliveries
|
|
26399
26602
|
};
|
|
26400
26603
|
};
|
|
@@ -26444,19 +26647,19 @@ ${failedSessions || "None."}
|
|
|
26444
26647
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26445
26648
|
`;
|
|
26446
26649
|
};
|
|
26447
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
26650
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml43(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml43(label)}</span><strong>not configured</strong></article>`;
|
|
26448
26651
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26449
26652
|
const title = options.title ?? "Voice Ops Recovery";
|
|
26450
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
26451
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
26452
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
26453
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26653
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml43(issue.severity)}</td><td><code>${escapeHtml43(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml43(issue.href)}">${escapeHtml43(issue.label)}</a>` : escapeHtml43(issue.label)}</td><td>${escapeHtml43(String(issue.value ?? ""))}</td><td>${escapeHtml43(issue.detail ?? "")}</td></tr>`).join("");
|
|
26654
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml43(provider.provider)}</td><td>${escapeHtml43(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml43(provider.lastError ?? "")}</td></tr>`).join("");
|
|
26655
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml43(session.operationsRecordHref)}">${escapeHtml43(session.sessionId)}</a>` : escapeHtml43(session.sessionId)}${session.provider ? ` via ${escapeHtml43(session.provider)}` : ""}${session.error ? `: ${escapeHtml43(session.error)}` : ""}</li>`).join("");
|
|
26656
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml43(title)}</h1><p><span class="status">${escapeHtml43(report.status)}</span> Checked ${escapeHtml43(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml43(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
26454
26657
|
};
|
|
26455
26658
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26456
26659
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26457
26660
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26458
26661
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26459
|
-
const routes = new
|
|
26662
|
+
const routes = new Elysia45({
|
|
26460
26663
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26461
26664
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26462
26665
|
if (htmlPath) {
|
|
@@ -26486,18 +26689,18 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26486
26689
|
};
|
|
26487
26690
|
|
|
26488
26691
|
// src/observabilityExport.ts
|
|
26489
|
-
import { Elysia as
|
|
26692
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
26490
26693
|
import { Database as Database4 } from "bun:sqlite";
|
|
26491
26694
|
import { createHash } from "crypto";
|
|
26492
26695
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26493
26696
|
import { join as join3 } from "path";
|
|
26494
26697
|
|
|
26495
26698
|
// src/operationsRecord.ts
|
|
26496
|
-
import { Elysia as
|
|
26699
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
26497
26700
|
|
|
26498
26701
|
// src/traceTimeline.ts
|
|
26499
|
-
import { Elysia as
|
|
26500
|
-
var
|
|
26702
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26703
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26501
26704
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26502
26705
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26503
26706
|
var firstString3 = (payload, keys) => {
|
|
@@ -26680,17 +26883,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
26680
26883
|
};
|
|
26681
26884
|
};
|
|
26682
26885
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26683
|
-
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>${
|
|
26886
|
+
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>${escapeHtml44(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs4(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs4(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
|
|
26684
26887
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
26685
|
-
const events = session.events.map((event) => `<tr class="${
|
|
26686
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
26687
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
26688
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26888
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml44(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml44(event.type)}</td><td>${escapeHtml44(event.label)}</td><td>${escapeHtml44(event.provider ?? "")}</td><td>${escapeHtml44(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
26889
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml44(issue.severity)}">${escapeHtml44(issue.code)}: ${escapeHtml44(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
26890
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml44(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
26891
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(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>${escapeHtml44(session.sessionId)}</h1><p class="status ${escapeHtml44(session.status)}">${escapeHtml44(session.status)}</p>${supportLinks}</header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs4(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
|
|
26689
26892
|
};
|
|
26690
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
26893
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml44(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml44(session.operationsRecordHref)}">${escapeHtml44(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml44(session.sessionId)}</a>`}</td><td>${escapeHtml44(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs4(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml44(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
26691
26894
|
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}}";
|
|
26692
26895
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
26693
|
-
const snippet =
|
|
26896
|
+
const snippet = escapeHtml44(`const traceStore = createVoiceTraceSinkStore({
|
|
26694
26897
|
store: runtimeStorage.traces,
|
|
26695
26898
|
sinks: [
|
|
26696
26899
|
createVoiceTraceHTTPSink({
|
|
@@ -26716,13 +26919,13 @@ app.use(
|
|
|
26716
26919
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
26717
26920
|
})
|
|
26718
26921
|
);`);
|
|
26719
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26922
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml44(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
|
|
26720
26923
|
};
|
|
26721
26924
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
26722
26925
|
const path = options.path ?? "/api/voice-traces";
|
|
26723
26926
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
26724
26927
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
26725
|
-
const routes = new
|
|
26928
|
+
const routes = new Elysia46({
|
|
26726
26929
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
26727
26930
|
});
|
|
26728
26931
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -27151,7 +27354,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
27151
27354
|
}
|
|
27152
27355
|
return report;
|
|
27153
27356
|
};
|
|
27154
|
-
var
|
|
27357
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27155
27358
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27156
27359
|
var outcomeLabels = (outcome) => [
|
|
27157
27360
|
outcome.complete ? "complete" : undefined,
|
|
@@ -27231,20 +27434,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
27231
27434
|
`);
|
|
27232
27435
|
};
|
|
27233
27436
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
27234
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
27235
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
27236
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
27437
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml45(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs5(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
27438
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml45(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml45(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml45(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml45(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
27439
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml45(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml45(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml45(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml45(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml45(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml45(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml45(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml45(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
27237
27440
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
27238
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
27239
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
27240
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
27241
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
27242
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
27441
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml45(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml45(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml45(handoff.status ?? "")}</span><p>${escapeHtml45(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
27442
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml45(tool.toolName ?? "tool")}</strong> <span>${escapeHtml45(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml45(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
27443
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml45(review.title)}</strong> <span>${escapeHtml45(review.summary.outcome ?? "")}</span><p>${escapeHtml45(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
27444
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml45(task.title)}</strong> <span>${escapeHtml45(task.status)}</span><p>${escapeHtml45(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
27445
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml45(event.type)}</strong> <span>${escapeHtml45(event.deliveryStatus ?? "local")}</span><p>${escapeHtml45(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
27243
27446
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
27244
27447
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
27245
|
-
return `<li><strong>assistant.guardrail ${
|
|
27448
|
+
return `<li><strong>assistant.guardrail ${escapeHtml45(decision.stage ?? "unknown")}</strong> <span>${escapeHtml45(decision.status ?? "")}</span><p>Allowed: ${escapeHtml45(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml45(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml45(decision.turnId)}` : ""}</p><p>${escapeHtml45(findings)}</p></li>`;
|
|
27246
27449
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
27247
|
-
const snippet =
|
|
27450
|
+
const snippet = escapeHtml45(`app.use(
|
|
27248
27451
|
createVoiceOperationsRecordRoutes({
|
|
27249
27452
|
audit: auditStore,
|
|
27250
27453
|
integrationEvents: opsEvents,
|
|
@@ -27258,16 +27461,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
27258
27461
|
tasks: opsTasks
|
|
27259
27462
|
})
|
|
27260
27463
|
);`);
|
|
27261
|
-
const incidentMarkdown =
|
|
27262
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
27263
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27464
|
+
const incidentMarkdown = escapeHtml45(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
27465
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml45(options.incidentHref)}">Download incident.md</a>` : "";
|
|
27466
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml45(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml45(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml45(record.status)}">${escapeHtml45(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs5(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml45(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
|
|
27264
27467
|
};
|
|
27265
27468
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
27266
27469
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
27267
27470
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
27268
27471
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
27269
27472
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
27270
|
-
const routes = new
|
|
27473
|
+
const routes = new Elysia47({
|
|
27271
27474
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
27272
27475
|
});
|
|
27273
27476
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -27918,7 +28121,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
27918
28121
|
...options.headers ?? {}
|
|
27919
28122
|
};
|
|
27920
28123
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
27921
|
-
const app = new
|
|
28124
|
+
const app = new Elysia48({
|
|
27922
28125
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
27923
28126
|
});
|
|
27924
28127
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28727,7 +28930,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28727
28930
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
28728
28931
|
}
|
|
28729
28932
|
});
|
|
28730
|
-
const app = new
|
|
28933
|
+
const app = new Elysia48({
|
|
28731
28934
|
name: options.name ?? "absolute-voice-observability-export"
|
|
28732
28935
|
});
|
|
28733
28936
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28804,8 +29007,8 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28804
29007
|
};
|
|
28805
29008
|
|
|
28806
29009
|
// src/productionReadiness.ts
|
|
28807
|
-
var
|
|
28808
|
-
var
|
|
29010
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29011
|
+
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
28809
29012
|
var readinessGateCodes = {
|
|
28810
29013
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
28811
29014
|
"Audit evidence": "voice.readiness.audit_evidence",
|
|
@@ -30202,7 +30405,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30202
30405
|
profile: options.profile || undefined,
|
|
30203
30406
|
operationsRecords,
|
|
30204
30407
|
proofSources,
|
|
30205
|
-
status:
|
|
30408
|
+
status: rollupStatus4(checks),
|
|
30206
30409
|
summary: {
|
|
30207
30410
|
agentSquadContracts: agentSquadContractSummary,
|
|
30208
30411
|
audit,
|
|
@@ -30259,25 +30462,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30259
30462
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
30260
30463
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
30261
30464
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
30262
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
30263
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
30465
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml46(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
30466
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml46(report.profile.name)}</h2><p>${escapeHtml46(report.profile.description)}</p><p>${escapeHtml46(report.profile.purpose)}</p><div class="profile-surfaces">${report.profile.surfaces.map((surface) => `<article class="${surface.configured ? "pass" : "warn"}"><span>${surface.configured ? "CONFIGURED" : "EXPECTED"}</span><strong>${surface.href ? `<a href="${escapeHtml46(surface.href)}">${escapeHtml46(surface.label)}</a>` : escapeHtml46(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
30264
30467
|
const checks = report.checks.map((check, index) => {
|
|
30265
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
30266
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
30267
|
-
return `<article class="check ${
|
|
30468
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml46(action.href)}">${escapeHtml46(action.label)}</button>` : `<a href="${escapeHtml46(action.href)}">${escapeHtml46(action.label)}</a>`).join("");
|
|
30469
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml46(check.status)}: observed ${escapeHtml46(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml46(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml46(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml46(check.gateExplanation.unit)}` : ""}. ${escapeHtml46(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml46(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
30470
|
+
return `<article class="check ${escapeHtml46(check.status)}">
|
|
30268
30471
|
<div>
|
|
30269
|
-
<span>${
|
|
30270
|
-
<h2>${
|
|
30271
|
-
${check.detail ? `<p>${
|
|
30472
|
+
<span>${escapeHtml46(check.status.toUpperCase())}</span>
|
|
30473
|
+
<h2>${escapeHtml46(check.label)}</h2>
|
|
30474
|
+
${check.detail ? `<p>${escapeHtml46(check.detail)}</p>` : ""}
|
|
30272
30475
|
${explanation}
|
|
30273
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
30476
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml46(check.proofSource.href)}">${escapeHtml46(check.proofSource.sourceLabel)}</a>` : escapeHtml46(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml46(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
30274
30477
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
30275
30478
|
</div>
|
|
30276
|
-
<strong>${
|
|
30277
|
-
${check.href ? `<a href="${
|
|
30479
|
+
<strong>${escapeHtml46(String(check.value ?? check.status))}</strong>
|
|
30480
|
+
${check.href ? `<a href="${escapeHtml46(check.href)}">Open surface</a>` : ""}
|
|
30278
30481
|
</article>`;
|
|
30279
30482
|
}).join("");
|
|
30280
|
-
const snippet =
|
|
30483
|
+
const snippet = escapeHtml46(`createVoiceProductionReadinessRoutes({
|
|
30281
30484
|
htmlPath: '/production-readiness',
|
|
30282
30485
|
path: '/api/production-readiness',
|
|
30283
30486
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -30293,13 +30496,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
30293
30496
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
30294
30497
|
store: traceStore
|
|
30295
30498
|
});`);
|
|
30296
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30499
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero,.primitive,.profile{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.primitive,.profile{background:#111722}.primitive{border-color:#3a3f2d}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.primitive code{color:#fde68a}.primitive p{color:#c8ccd3;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#0b0f16;border:1px solid #2c3440;border-radius:18px;color:#fef3c7;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.check.pass,.profile-surfaces .pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn,.profile-surfaces .warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span,.profile-surfaces span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p,.profile p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check .gate-explanation{background:#0b0f16;border:1px solid #2c3440;border-radius:14px;color:#fef3c7;margin-top:10px;padding:10px}.check strong{font-size:1.5rem}.profile-surfaces{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}.profile-surfaces article{background:#141922;border:1px solid #26313d;border-radius:16px;padding:14px}.profile-surfaces strong{display:block;margin-top:6px}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml46(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 ${escapeHtml46(report.status)}">Overall: ${escapeHtml46(report.status.toUpperCase())}</p><p>Checked ${escapeHtml46(new Date(report.checkedAt).toLocaleString())}</p>${thresholdLink}</section>${profile}<section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProductionReadinessRoutes(...)</code> builds this deploy gate</h2><p>Mount one package primitive to expose JSON readiness, HTML readiness, and a machine-readable gate route. Feed it the proof stores and contract reports your app already owns.</p><pre><code>${snippet}</code></pre></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
|
|
30297
30500
|
};
|
|
30298
30501
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
30299
30502
|
const path = options.path ?? "/api/production-readiness";
|
|
30300
30503
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
30301
30504
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
30302
|
-
const routes = new
|
|
30505
|
+
const routes = new Elysia49({
|
|
30303
30506
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
30304
30507
|
});
|
|
30305
30508
|
const resolveOptions = async (input) => {
|
|
@@ -30347,10 +30550,10 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30347
30550
|
return routes;
|
|
30348
30551
|
};
|
|
30349
30552
|
// src/voiceMonitoring.ts
|
|
30350
|
-
import { Elysia as
|
|
30351
|
-
var
|
|
30553
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
30554
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30352
30555
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30353
|
-
var
|
|
30556
|
+
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30354
30557
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
30355
30558
|
const issues = new Map(initial.map((issue) => [issue.id, { ...issue }]));
|
|
30356
30559
|
return {
|
|
@@ -30432,7 +30635,7 @@ var buildVoiceMonitorRunReport = async (options) => {
|
|
|
30432
30635
|
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
30433
30636
|
issues,
|
|
30434
30637
|
runs,
|
|
30435
|
-
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 ||
|
|
30638
|
+
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 || rollupStatus5(runs) === "warn" ? "warn" : rollupStatus5(runs),
|
|
30436
30639
|
summary: {
|
|
30437
30640
|
acknowledged: issues.filter((issue) => issue.status === "acknowledged").length,
|
|
30438
30641
|
criticalOpen,
|
|
@@ -30601,14 +30804,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
30601
30804
|
};
|
|
30602
30805
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
30603
30806
|
const title = options.title ?? "Voice Monitors";
|
|
30604
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
30605
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
30606
|
-
const snippet =
|
|
30807
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml47(run.label)}</td><td class="${escapeHtml47(run.status)}">${escapeHtml47(run.status)}</td><td>${escapeHtml47(run.severity)}</td><td>${escapeHtml47(String(run.value ?? ""))}</td><td>${escapeHtml47(String(run.threshold ?? ""))}</td><td>${escapeHtml47(run.detail ?? "")}</td></tr>`).join("");
|
|
30808
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml47(issue.label)}</strong> <span class="${escapeHtml47(issue.status)}">${escapeHtml47(issue.status)}</span> ${escapeHtml47(issue.detail ?? "")}</li>`).join("");
|
|
30809
|
+
const snippet = escapeHtml47(`app.use(createVoiceMonitorRoutes({
|
|
30607
30810
|
evidence,
|
|
30608
30811
|
issueStore,
|
|
30609
30812
|
monitors: [defineVoiceMonitor(...)]
|
|
30610
30813
|
}));`);
|
|
30611
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30814
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml47(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml47(title)}</h1><p class="pill ${escapeHtml47(report.status)}">Status: ${escapeHtml47(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
30612
30815
|
};
|
|
30613
30816
|
var actorFromRequest = async (request) => {
|
|
30614
30817
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -30632,7 +30835,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30632
30835
|
monitors: options.monitors,
|
|
30633
30836
|
now: options.now
|
|
30634
30837
|
});
|
|
30635
|
-
const routes = new
|
|
30838
|
+
const routes = new Elysia50({
|
|
30636
30839
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
30637
30840
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
30638
30841
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -30679,7 +30882,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30679
30882
|
};
|
|
30680
30883
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
30681
30884
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
30682
|
-
return new
|
|
30885
|
+
return new Elysia50({
|
|
30683
30886
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
30684
30887
|
}).get(path, () => ({
|
|
30685
30888
|
isRunning: options.runner.isRunning()
|
|
@@ -31055,8 +31258,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
31055
31258
|
};
|
|
31056
31259
|
};
|
|
31057
31260
|
// src/providerStackRecommendations.ts
|
|
31058
|
-
import { Elysia as
|
|
31059
|
-
var
|
|
31261
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
31262
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31060
31263
|
var profileProviderPriorities = {
|
|
31061
31264
|
"meeting-recorder": {
|
|
31062
31265
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31108,7 +31311,7 @@ var profileRequiredCapabilities = {
|
|
|
31108
31311
|
tts: ["streaming speech", "barge-in friendly"]
|
|
31109
31312
|
}
|
|
31110
31313
|
};
|
|
31111
|
-
var
|
|
31314
|
+
var defaultProviderEnv2 = {
|
|
31112
31315
|
anthropic: ["ANTHROPIC_API_KEY"],
|
|
31113
31316
|
assemblyai: ["ASSEMBLYAI_API_KEY"],
|
|
31114
31317
|
deepgram: ["DEEPGRAM_API_KEY"],
|
|
@@ -31168,12 +31371,12 @@ var recommendVoiceProviderStack = (input) => {
|
|
|
31168
31371
|
};
|
|
31169
31372
|
};
|
|
31170
31373
|
var rollupContractStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
31171
|
-
var
|
|
31374
|
+
var statusRank5 = {
|
|
31172
31375
|
pass: 0,
|
|
31173
31376
|
warn: 1,
|
|
31174
31377
|
fail: 2
|
|
31175
31378
|
};
|
|
31176
|
-
var
|
|
31379
|
+
var statusExceeds2 = (actual, max) => statusRank5[actual] > statusRank5[max];
|
|
31177
31380
|
var buildVoiceProviderContractMatrix = (input) => {
|
|
31178
31381
|
const rows = input.contracts.map((contract) => {
|
|
31179
31382
|
const configured = contract.configured !== false;
|
|
@@ -31286,7 +31489,7 @@ var evaluateVoiceProviderContractMatrixEvidence = (report, input = {}) => {
|
|
|
31286
31489
|
const selectedKinds = [
|
|
31287
31490
|
...new Set(report.rows.filter((row) => row.selected).map((row) => row.kind))
|
|
31288
31491
|
].sort();
|
|
31289
|
-
if (
|
|
31492
|
+
if (statusExceeds2(report.status, maxStatus)) {
|
|
31290
31493
|
issues.push(`Expected provider contract matrix status at most ${maxStatus}, found ${report.status}.`);
|
|
31291
31494
|
}
|
|
31292
31495
|
if (report.failed > maxFailed) {
|
|
@@ -31348,11 +31551,11 @@ var createVoiceProviderContractMatrixPreset = (profile, options) => {
|
|
|
31348
31551
|
const contracts = ["llm", "stt", "tts"].flatMap((kind) => {
|
|
31349
31552
|
const providers = options.providers[kind] ?? [];
|
|
31350
31553
|
return providers.map((provider) => {
|
|
31351
|
-
const configured = options.configured?.[provider] ?? (
|
|
31554
|
+
const configured = options.configured?.[provider] ?? (defaultProviderEnv2[provider]?.length ? defaultProviderEnv2[provider].every((name) => options.env?.[name]) : true);
|
|
31352
31555
|
const fallbackProviders = options.fallbackProviders?.[kind] ?? providers.filter((candidate) => candidate !== provider);
|
|
31353
31556
|
const requiredCapabilities = profileRequiredCapabilities[profile][kind];
|
|
31354
31557
|
const capabilities = options.capabilities?.[kind]?.[provider] ?? defaultProviderCapabilities[provider] ?? [];
|
|
31355
|
-
const requiredEnv =
|
|
31558
|
+
const requiredEnv = defaultProviderEnv2[provider] ?? [];
|
|
31356
31559
|
return {
|
|
31357
31560
|
capabilities,
|
|
31358
31561
|
configured,
|
|
@@ -31375,17 +31578,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31375
31578
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31376
31579
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31377
31580
|
const rows = report.rows.map((row) => {
|
|
31378
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31379
|
-
return `<article class="row ${
|
|
31581
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml48(check.status)}"><strong>${escapeHtml48(check.label)}</strong><span>${escapeHtml48(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml48(check.remediation.href)}">${escapeHtml48(check.remediation.label)}</a>` : escapeHtml48(check.remediation.label)}: ${escapeHtml48(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
31582
|
+
return `<article class="row ${escapeHtml48(row.status)}">
|
|
31380
31583
|
<div>
|
|
31381
|
-
<p class="eyebrow">${
|
|
31382
|
-
<h2>${
|
|
31383
|
-
<p class="status ${
|
|
31584
|
+
<p class="eyebrow">${escapeHtml48(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
31585
|
+
<h2>${escapeHtml48(row.provider)}</h2>
|
|
31586
|
+
<p class="status ${escapeHtml48(row.status)}">${escapeHtml48(row.status.toUpperCase())}</p>
|
|
31384
31587
|
</div>
|
|
31385
31588
|
<ul>${checks}</ul>
|
|
31386
31589
|
</article>`;
|
|
31387
31590
|
}).join("");
|
|
31388
|
-
const snippet =
|
|
31591
|
+
const snippet = escapeHtml48(`const providerContracts = () =>
|
|
31389
31592
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31390
31593
|
env: process.env,
|
|
31391
31594
|
providers: {
|
|
@@ -31406,7 +31609,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31406
31609
|
providerContractMatrix: () =>
|
|
31407
31610
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31408
31611
|
});`);
|
|
31409
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31612
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml48(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
31410
31613
|
};
|
|
31411
31614
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31412
31615
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31421,7 +31624,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31421
31624
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31422
31625
|
const path = options.path ?? "/api/provider-contracts";
|
|
31423
31626
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31424
|
-
const routes = new
|
|
31627
|
+
const routes = new Elysia51({
|
|
31425
31628
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31426
31629
|
});
|
|
31427
31630
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -31488,7 +31691,7 @@ var evaluateVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31488
31691
|
const providers = [
|
|
31489
31692
|
...new Set(report.gaps.map((gap) => gap.provider).filter((provider) => provider !== undefined))
|
|
31490
31693
|
].sort();
|
|
31491
|
-
if (
|
|
31694
|
+
if (statusExceeds2(report.status, maxStatus)) {
|
|
31492
31695
|
issues.push(`Expected provider stack status at most ${maxStatus}, found ${report.status}.`);
|
|
31493
31696
|
}
|
|
31494
31697
|
if (report.missing > maxMissing) {
|
|
@@ -31539,7 +31742,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31539
31742
|
return assertion;
|
|
31540
31743
|
};
|
|
31541
31744
|
// src/opsConsoleRoutes.ts
|
|
31542
|
-
import { Elysia as
|
|
31745
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
31543
31746
|
var DEFAULT_LINKS = [
|
|
31544
31747
|
{
|
|
31545
31748
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -31574,7 +31777,7 @@ var DEFAULT_LINKS = [
|
|
|
31574
31777
|
label: "Handoffs"
|
|
31575
31778
|
}
|
|
31576
31779
|
];
|
|
31577
|
-
var
|
|
31780
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31578
31781
|
var countProviderStatuses = (providers) => {
|
|
31579
31782
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
31580
31783
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -31643,20 +31846,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
31643
31846
|
trace
|
|
31644
31847
|
};
|
|
31645
31848
|
};
|
|
31646
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
31849
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml49(input.label)}</span><strong>${escapeHtml49(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml49(input.status)}">${escapeHtml49(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml49(input.href)}">Open</a>` : ""}</article>`;
|
|
31647
31850
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
31648
31851
|
const links = report.links.map((link) => `<article class="surface">
|
|
31649
|
-
<div><h2>${
|
|
31650
|
-
<p><a href="${
|
|
31852
|
+
<div><h2>${escapeHtml49(link.label)}</h2>${link.description ? `<p>${escapeHtml49(link.description)}</p>` : ""}</div>
|
|
31853
|
+
<p><a href="${escapeHtml49(link.href)}">Open ${escapeHtml49(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml49(link.statusHref)}">Status</a>` : ""}</p>
|
|
31651
31854
|
</article>`).join("");
|
|
31652
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
31653
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
31855
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml49(session.sessionId)}</td><td>${escapeHtml49(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml49(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
31856
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml49(event.kind)}</td><td>${escapeHtml49(event.provider ?? "unknown")}</td><td>${escapeHtml49(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml49(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
31654
31857
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
31655
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31858
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml49(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>${escapeHtml49(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 ${escapeHtml49(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>`;
|
|
31656
31859
|
};
|
|
31657
31860
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
31658
31861
|
const path = options.path ?? "/ops-console";
|
|
31659
|
-
const routes = new
|
|
31862
|
+
const routes = new Elysia52({
|
|
31660
31863
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
31661
31864
|
});
|
|
31662
31865
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -31673,7 +31876,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
31673
31876
|
return routes;
|
|
31674
31877
|
};
|
|
31675
31878
|
// src/incidentBundle.ts
|
|
31676
|
-
import { Elysia as
|
|
31879
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31677
31880
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
31678
31881
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
31679
31882
|
return false;
|
|
@@ -31874,7 +32077,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
31874
32077
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
31875
32078
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
31876
32079
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
31877
|
-
const routes = new
|
|
32080
|
+
const routes = new Elysia53({
|
|
31878
32081
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
31879
32082
|
});
|
|
31880
32083
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -32075,19 +32278,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
32075
32278
|
};
|
|
32076
32279
|
};
|
|
32077
32280
|
// src/opsStatusRoutes.ts
|
|
32078
|
-
import { Elysia as
|
|
32079
|
-
var
|
|
32281
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
32282
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32080
32283
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
32081
32284
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
32082
32285
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
32083
32286
|
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;
|
|
32084
|
-
return `<article class="surface ${
|
|
32287
|
+
return `<article class="surface ${escapeHtml50(surface.status)}"><span>${escapeHtml50(surface.status.toUpperCase())}</span><h2>${escapeHtml50(key)}</h2><strong>${escapeHtml50(value)}</strong></article>`;
|
|
32085
32288
|
}).join("");
|
|
32086
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32289
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml50(title)}</title><style>body{background:#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>${escapeHtml50(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml50(report.status)}">Overall: ${escapeHtml50(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>`;
|
|
32087
32290
|
};
|
|
32088
32291
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
32089
32292
|
const path = options.path ?? "/api/voice/ops-status";
|
|
32090
|
-
const routes = new
|
|
32293
|
+
const routes = new Elysia54({
|
|
32091
32294
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
32092
32295
|
});
|
|
32093
32296
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -32520,8 +32723,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
32520
32723
|
};
|
|
32521
32724
|
};
|
|
32522
32725
|
// src/traceDeliveryRoutes.ts
|
|
32523
|
-
import { Elysia as
|
|
32524
|
-
var
|
|
32726
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32727
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32525
32728
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
32526
32729
|
var getNumber12 = (value) => {
|
|
32527
32730
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -32602,14 +32805,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
32602
32805
|
if (entries.length === 0) {
|
|
32603
32806
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
32604
32807
|
}
|
|
32605
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
32808
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml51(sinkId)}</strong>: ${escapeHtml51(result.status)}${result.deliveredTo ? ` to ${escapeHtml51(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml51(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
32606
32809
|
};
|
|
32607
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
32810
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml51(event.type)} <small>${escapeHtml51(event.id)}</small>${event.sessionId ? ` session=${escapeHtml51(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
32608
32811
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
32609
32812
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
32610
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
32611
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
32612
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32813
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml51(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
32814
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml51(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml51(delivery.deliveryStatus)}</span><h2>${escapeHtml51(delivery.id)}</h2><p>${escapeHtml51(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml51(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml51(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
32815
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml51(title)}</title><style>body{background:#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>${escapeHtml51(title)}</h1><p>Checked ${escapeHtml51(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>`;
|
|
32613
32816
|
};
|
|
32614
32817
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
32615
32818
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32629,7 +32832,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
32629
32832
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
32630
32833
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
32631
32834
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
32632
|
-
const routes = new
|
|
32835
|
+
const routes = new Elysia55({
|
|
32633
32836
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
32634
32837
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
32635
32838
|
if (htmlPath !== false) {
|
|
@@ -32726,7 +32929,7 @@ var createVoiceMemoryStore = () => {
|
|
|
32726
32929
|
return { get, getOrCreate, list, remove, set };
|
|
32727
32930
|
};
|
|
32728
32931
|
// src/opsWebhook.ts
|
|
32729
|
-
import { Elysia as
|
|
32932
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32730
32933
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
32731
32934
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
32732
32935
|
const encoder = new TextEncoder;
|
|
@@ -32856,7 +33059,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
32856
33059
|
};
|
|
32857
33060
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
32858
33061
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
32859
|
-
return new
|
|
33062
|
+
return new Elysia56().post(path, async ({ body, request, set }) => {
|
|
32860
33063
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
32861
33064
|
if (options.signingSecret) {
|
|
32862
33065
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -33311,7 +33514,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
33311
33514
|
};
|
|
33312
33515
|
};
|
|
33313
33516
|
// src/postCallAnalysis.ts
|
|
33314
|
-
import { Elysia as
|
|
33517
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
33315
33518
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
33316
33519
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
33317
33520
|
var getPathValue3 = (source, path) => {
|
|
@@ -33490,7 +33693,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
33490
33693
|
};
|
|
33491
33694
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
33492
33695
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
33493
|
-
const routes = new
|
|
33696
|
+
const routes = new Elysia57({
|
|
33494
33697
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
33495
33698
|
});
|
|
33496
33699
|
routes.get(path, async ({ query }) => {
|
|
@@ -33515,7 +33718,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
33515
33718
|
return routes;
|
|
33516
33719
|
};
|
|
33517
33720
|
// src/guardrails.ts
|
|
33518
|
-
import { Elysia as
|
|
33721
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
33519
33722
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
33520
33723
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
33521
33724
|
var matchesRule = async (rule, input) => {
|
|
@@ -33817,7 +34020,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
33817
34020
|
};
|
|
33818
34021
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
33819
34022
|
const path = options.path ?? "/api/voice/guardrails";
|
|
33820
|
-
const routes = new
|
|
34023
|
+
const routes = new Elysia58({
|
|
33821
34024
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
33822
34025
|
});
|
|
33823
34026
|
routes.all(path, async ({ request }) => {
|
|
@@ -34341,6 +34544,7 @@ export {
|
|
|
34341
34544
|
renderVoiceScenarioEvalHTML,
|
|
34342
34545
|
renderVoiceResilienceHTML,
|
|
34343
34546
|
renderVoiceReconnectContractHTML,
|
|
34547
|
+
renderVoiceRealtimeProviderContractHTML,
|
|
34344
34548
|
renderVoiceRealtimeChannelMarkdown,
|
|
34345
34549
|
renderVoiceRealtimeChannelHTML,
|
|
34346
34550
|
renderVoiceQualityHTML,
|
|
@@ -34438,6 +34642,7 @@ export {
|
|
|
34438
34642
|
evaluateVoiceTelephonyWebhookNormalizationEvidence,
|
|
34439
34643
|
evaluateVoiceTelephonyContract,
|
|
34440
34644
|
evaluateVoiceSimulationSuiteEvidence,
|
|
34645
|
+
evaluateVoiceRealtimeProviderContractEvidence,
|
|
34441
34646
|
evaluateVoiceRealtimeChannelEvidence,
|
|
34442
34647
|
evaluateVoiceQuality,
|
|
34443
34648
|
evaluateVoiceProviderStackGaps,
|
|
@@ -34568,6 +34773,7 @@ export {
|
|
|
34568
34773
|
createVoiceRedisPlivoWebhookNonceStore,
|
|
34569
34774
|
createVoiceRedisIdempotencyStore,
|
|
34570
34775
|
createVoiceReconnectContractRoutes,
|
|
34776
|
+
createVoiceRealtimeProviderContractRoutes,
|
|
34571
34777
|
createVoiceRealtimeChannelRoutes,
|
|
34572
34778
|
createVoiceReadinessProfile,
|
|
34573
34779
|
createVoiceQualityRoutes,
|
|
@@ -34772,6 +34978,7 @@ export {
|
|
|
34772
34978
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
34773
34979
|
buildVoiceSloReadinessThresholdReport,
|
|
34774
34980
|
buildVoiceSloCalibrationReport,
|
|
34981
|
+
buildVoiceRealtimeProviderContractMatrix,
|
|
34775
34982
|
buildVoiceRealtimeChannelRuntimeSamplesFromTrace,
|
|
34776
34983
|
buildVoiceRealtimeChannelReport,
|
|
34777
34984
|
buildVoiceProviderSloReport,
|
|
@@ -34817,6 +35024,7 @@ export {
|
|
|
34817
35024
|
assertVoiceTelephonyWebhookNormalizationEvidence,
|
|
34818
35025
|
assertVoiceSloCalibration,
|
|
34819
35026
|
assertVoiceSimulationSuiteEvidence,
|
|
35027
|
+
assertVoiceRealtimeProviderContractEvidence,
|
|
34820
35028
|
assertVoiceRealtimeChannelEvidence,
|
|
34821
35029
|
assertVoiceProviderStackEvidence,
|
|
34822
35030
|
assertVoiceProviderSloEvidence,
|