@absolutejs/voice 0.0.22-beta.303 → 0.0.22-beta.305
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 +640 -431
- package/dist/realtimeProviderContracts.d.ts +116 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11239,9 +11239,213 @@ 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 planned = contract.implementationStatus === "planned";
|
|
11271
|
+
const requiredEnv = contract.requiredEnv ?? defaultProviderEnv[contract.provider] ?? [];
|
|
11272
|
+
const missingEnv = requiredEnv.filter((name) => !contract.env?.[name]);
|
|
11273
|
+
const requiredCapabilities = contract.requiredCapabilities ?? defaultRequiredCapabilities;
|
|
11274
|
+
const presentCapabilities = new Set(contract.capabilities ?? []);
|
|
11275
|
+
const missingCapabilities = requiredCapabilities.filter((capability) => !presentCapabilities.has(capability));
|
|
11276
|
+
const realtimeChannel = contract.realtimeChannel;
|
|
11277
|
+
const checks = [
|
|
11278
|
+
{
|
|
11279
|
+
detail: planned ? "Provider contract is declared for roadmap coverage but is not enabled for this deployment." : configured ? "Provider is configured for this deployment." : "Provider is declared but not configured.",
|
|
11280
|
+
key: "configured",
|
|
11281
|
+
label: "Configured",
|
|
11282
|
+
status: configured ? "pass" : planned ? "warn" : "fail"
|
|
11283
|
+
},
|
|
11284
|
+
{
|
|
11285
|
+
detail: missingEnv.length === 0 ? "Required environment is present." : `Missing env: ${missingEnv.join(", ")}.`,
|
|
11286
|
+
key: "env",
|
|
11287
|
+
label: "Required env",
|
|
11288
|
+
status: missingEnv.length === 0 ? "pass" : planned ? "warn" : "fail"
|
|
11289
|
+
},
|
|
11290
|
+
{
|
|
11291
|
+
detail: missingCapabilities.length === 0 ? "Required realtime capabilities are declared." : `Missing capabilities: ${missingCapabilities.join(", ")}.`,
|
|
11292
|
+
key: "capabilities",
|
|
11293
|
+
label: "Realtime capabilities",
|
|
11294
|
+
status: missingCapabilities.length === 0 ? "pass" : "warn"
|
|
11295
|
+
},
|
|
11296
|
+
{
|
|
11297
|
+
detail: realtimeChannel ? `Realtime channel proof is ${realtimeChannel.status}.` : "No realtime channel proof linked.",
|
|
11298
|
+
key: "realtimeChannel",
|
|
11299
|
+
label: "Realtime channel proof",
|
|
11300
|
+
status: realtimeChannel?.status === "pass" ? "pass" : realtimeChannel ? "warn" : planned ? "warn" : "fail"
|
|
11301
|
+
},
|
|
11302
|
+
{
|
|
11303
|
+
detail: contract.latencyBudgetMs !== undefined ? `First audio latency budget is ${String(contract.latencyBudgetMs)}ms.` : "No first-audio latency budget declared.",
|
|
11304
|
+
key: "latencyBudget",
|
|
11305
|
+
label: "Latency budget",
|
|
11306
|
+
status: contract.latencyBudgetMs !== undefined ? "pass" : "warn"
|
|
11307
|
+
},
|
|
11308
|
+
{
|
|
11309
|
+
detail: (contract.fallbackProviders ?? []).length > 0 ? `Fallback providers: ${contract.fallbackProviders?.join(", ")}.` : "No realtime fallback provider declared.",
|
|
11310
|
+
key: "fallback",
|
|
11311
|
+
label: "Fallback",
|
|
11312
|
+
status: (contract.fallbackProviders ?? []).length > 0 ? "pass" : "warn"
|
|
11313
|
+
},
|
|
11314
|
+
{
|
|
11315
|
+
detail: contract.traceHref ? `Trace evidence: ${contract.traceHref}.` : "Trace evidence link is missing.",
|
|
11316
|
+
key: "traceEvidence",
|
|
11317
|
+
label: "Trace evidence",
|
|
11318
|
+
status: contract.traceHref ? "pass" : "warn"
|
|
11319
|
+
},
|
|
11320
|
+
{
|
|
11321
|
+
detail: contract.readinessHref ? `Readiness gate: ${contract.readinessHref}.` : "Readiness gate link is missing.",
|
|
11322
|
+
key: "readiness",
|
|
11323
|
+
label: "Readiness gate",
|
|
11324
|
+
status: contract.readinessHref ? "pass" : "warn"
|
|
11325
|
+
}
|
|
11326
|
+
];
|
|
11327
|
+
return {
|
|
11328
|
+
checks,
|
|
11329
|
+
configured,
|
|
11330
|
+
provider: contract.provider,
|
|
11331
|
+
selected: contract.selected === true,
|
|
11332
|
+
status: rollupStatus(checks)
|
|
11333
|
+
};
|
|
11334
|
+
});
|
|
11335
|
+
const failed = rows.filter((row) => row.status === "fail").length;
|
|
11336
|
+
const warned = rows.filter((row) => row.status === "warn").length;
|
|
11337
|
+
return {
|
|
11338
|
+
failed,
|
|
11339
|
+
passed: rows.filter((row) => row.status === "pass").length,
|
|
11340
|
+
rows,
|
|
11341
|
+
status: failed > 0 ? "fail" : warned > 0 ? "warn" : "pass",
|
|
11342
|
+
total: rows.length,
|
|
11343
|
+
warned
|
|
11344
|
+
};
|
|
11345
|
+
};
|
|
11346
|
+
var evaluateVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
11347
|
+
const issues = [];
|
|
11348
|
+
const maxStatus = input.maxStatus ?? "pass";
|
|
11349
|
+
const maxFailed = input.maxFailed ?? 0;
|
|
11350
|
+
const maxWarned = input.maxWarned ?? 0;
|
|
11351
|
+
const minRows = input.minRows ?? 1;
|
|
11352
|
+
const providers = [...new Set(report.rows.map((row) => row.provider))].sort();
|
|
11353
|
+
const selectedProviders = [
|
|
11354
|
+
...new Set(report.rows.filter((row) => row.selected).map((row) => row.provider))
|
|
11355
|
+
].sort();
|
|
11356
|
+
if (statusExceeds(report.status, maxStatus)) {
|
|
11357
|
+
issues.push(`Expected realtime provider contract status at most ${maxStatus}, found ${report.status}.`);
|
|
11358
|
+
}
|
|
11359
|
+
if (report.failed > maxFailed) {
|
|
11360
|
+
issues.push(`Expected at most ${String(maxFailed)} failing realtime provider row(s), found ${String(report.failed)}.`);
|
|
11361
|
+
}
|
|
11362
|
+
if (report.warned > maxWarned) {
|
|
11363
|
+
issues.push(`Expected at most ${String(maxWarned)} warning realtime provider row(s), found ${String(report.warned)}.`);
|
|
11364
|
+
}
|
|
11365
|
+
if (report.total < minRows) {
|
|
11366
|
+
issues.push(`Expected at least ${String(minRows)} realtime provider row(s), found ${String(report.total)}.`);
|
|
11367
|
+
}
|
|
11368
|
+
for (const provider of input.requiredProviders ?? []) {
|
|
11369
|
+
if (!providers.includes(provider)) {
|
|
11370
|
+
issues.push(`Missing realtime provider contract provider: ${provider}.`);
|
|
11371
|
+
}
|
|
11372
|
+
}
|
|
11373
|
+
for (const key of input.requiredCheckKeys ?? []) {
|
|
11374
|
+
const missingRows = report.rows.filter((row) => !row.checks.some((check) => check.key === key)).length;
|
|
11375
|
+
if (missingRows > 0) {
|
|
11376
|
+
issues.push(`Realtime provider contract check ${key} is missing from ${String(missingRows)} row(s).`);
|
|
11377
|
+
}
|
|
11378
|
+
}
|
|
11379
|
+
for (const capability of input.requiredCapabilities ?? []) {
|
|
11380
|
+
const missingRows = report.rows.filter((row) => {
|
|
11381
|
+
const capabilityCheck = row.checks.find((check) => check.key === "capabilities");
|
|
11382
|
+
return capabilityCheck?.detail?.includes(capability) === true;
|
|
11383
|
+
}).length;
|
|
11384
|
+
if (missingRows > 0) {
|
|
11385
|
+
issues.push(`Realtime provider capability ${capability} is missing from ${String(missingRows)} row(s).`);
|
|
11386
|
+
}
|
|
11387
|
+
}
|
|
11388
|
+
if ((input.requireSelected ?? true) && selectedProviders.length === 0) {
|
|
11389
|
+
issues.push("Missing selected realtime provider contract row.");
|
|
11390
|
+
}
|
|
11391
|
+
return {
|
|
11392
|
+
failed: report.failed,
|
|
11393
|
+
issues,
|
|
11394
|
+
ok: issues.length === 0,
|
|
11395
|
+
providers,
|
|
11396
|
+
selectedProviders,
|
|
11397
|
+
status: report.status,
|
|
11398
|
+
total: report.total,
|
|
11399
|
+
warned: report.warned
|
|
11400
|
+
};
|
|
11401
|
+
};
|
|
11402
|
+
var assertVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
11403
|
+
const assertion = evaluateVoiceRealtimeProviderContractEvidence(report, input);
|
|
11404
|
+
if (!assertion.ok) {
|
|
11405
|
+
throw new Error(`Voice realtime provider contract assertion failed: ${assertion.issues.join(" ")}`);
|
|
11406
|
+
}
|
|
11407
|
+
return assertion;
|
|
11408
|
+
};
|
|
11409
|
+
var resolveMatrix = async (matrix) => typeof matrix === "function" ? await matrix() : matrix;
|
|
11410
|
+
var renderVoiceRealtimeProviderContractHTML = (report, title = "Voice Realtime Provider Contracts") => {
|
|
11411
|
+
const rows = report.rows.map((row) => {
|
|
11412
|
+
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("");
|
|
11413
|
+
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>`;
|
|
11414
|
+
}).join("");
|
|
11415
|
+
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>`;
|
|
11416
|
+
};
|
|
11417
|
+
var createVoiceRealtimeProviderContractRoutes = (options) => {
|
|
11418
|
+
const path = options.path ?? "/api/voice/realtime-provider-contracts";
|
|
11419
|
+
const htmlPath = options.htmlPath ?? "/voice/realtime-provider-contracts";
|
|
11420
|
+
const title = options.title ?? "Voice Realtime Provider Contracts";
|
|
11421
|
+
const report = async () => buildVoiceRealtimeProviderContractMatrix(await resolveMatrix(options.matrix));
|
|
11422
|
+
const routes = new Elysia10({
|
|
11423
|
+
name: options.name ?? "voice-realtime-provider-contracts"
|
|
11424
|
+
}).get(path, async () => {
|
|
11425
|
+
return new Response(JSON.stringify(await report(), null, 2), {
|
|
11426
|
+
headers: {
|
|
11427
|
+
"content-type": "application/json; charset=utf-8",
|
|
11428
|
+
...options.headers
|
|
11429
|
+
}
|
|
11430
|
+
});
|
|
11431
|
+
});
|
|
11432
|
+
if (htmlPath !== false) {
|
|
11433
|
+
routes.get(htmlPath, async () => {
|
|
11434
|
+
const current = await report();
|
|
11435
|
+
const body = options.render ? await options.render(current) : renderVoiceRealtimeProviderContractHTML(current, title);
|
|
11436
|
+
return new Response(body, {
|
|
11437
|
+
headers: {
|
|
11438
|
+
"content-type": "text/html; charset=utf-8",
|
|
11439
|
+
...options.headers
|
|
11440
|
+
}
|
|
11441
|
+
});
|
|
11442
|
+
});
|
|
11443
|
+
}
|
|
11444
|
+
return routes;
|
|
11445
|
+
};
|
|
11446
|
+
// src/diagnosticsRoutes.ts
|
|
11447
|
+
import { Elysia as Elysia11 } from "elysia";
|
|
11448
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11245
11449
|
var getString6 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
11246
11450
|
var getNumber4 = (value) => {
|
|
11247
11451
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
|
|
@@ -11307,9 +11511,9 @@ var renderDiagnosticsIndex = (input) => {
|
|
|
11307
11511
|
const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
|
|
11308
11512
|
const summary = summarizeVoiceTrace(events);
|
|
11309
11513
|
const encoded = encodeURIComponent(sessionId);
|
|
11310
|
-
return `<tr><td>${
|
|
11514
|
+
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
11515
|
}).join("");
|
|
11312
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11516
|
+
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
11517
|
};
|
|
11314
11518
|
var withRedaction = (events, query, defaultRedact) => {
|
|
11315
11519
|
const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
|
|
@@ -11318,7 +11522,7 @@ var withRedaction = (events, query, defaultRedact) => {
|
|
|
11318
11522
|
var createVoiceDiagnosticsRoutes = (options) => {
|
|
11319
11523
|
const path = options.path ?? "/diagnostics";
|
|
11320
11524
|
const title = options.title ?? "AbsoluteJS Voice Diagnostics";
|
|
11321
|
-
const routes = new
|
|
11525
|
+
const routes = new Elysia11({
|
|
11322
11526
|
name: options.name ?? "absolutejs-voice-diagnostics"
|
|
11323
11527
|
});
|
|
11324
11528
|
routes.get(path, async () => {
|
|
@@ -11375,9 +11579,9 @@ var createVoiceDiagnosticsRoutes = (options) => {
|
|
|
11375
11579
|
return routes;
|
|
11376
11580
|
};
|
|
11377
11581
|
// src/demoReadyRoutes.ts
|
|
11378
|
-
import { Elysia as
|
|
11379
|
-
var
|
|
11380
|
-
var
|
|
11582
|
+
import { Elysia as Elysia12 } from "elysia";
|
|
11583
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11584
|
+
var rollupStatus2 = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
11381
11585
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
11382
11586
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
11383
11587
|
const query = input.query ?? {};
|
|
@@ -11433,7 +11637,7 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11433
11637
|
return {
|
|
11434
11638
|
checkedAt: Date.now(),
|
|
11435
11639
|
sections,
|
|
11436
|
-
status: sections.length === 0 ? "warn" :
|
|
11640
|
+
status: sections.length === 0 ? "warn" : rollupStatus2(sections),
|
|
11437
11641
|
summary: {
|
|
11438
11642
|
opsStatus: opsStatus ? {
|
|
11439
11643
|
failed: opsStatus.failed,
|
|
@@ -11460,17 +11664,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11460
11664
|
};
|
|
11461
11665
|
};
|
|
11462
11666
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
11463
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
11464
|
-
<div><span>${
|
|
11465
|
-
<strong>${
|
|
11466
|
-
${section.href ? `<a href="${
|
|
11667
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml15(section.status)}">
|
|
11668
|
+
<div><span>${escapeHtml15(section.status.toUpperCase())}</span><h2>${escapeHtml15(section.label)}</h2>${section.description ? `<p>${escapeHtml15(section.description)}</p>` : ""}</div>
|
|
11669
|
+
<strong>${escapeHtml15(String(section.value ?? section.status))}</strong>
|
|
11670
|
+
${section.href ? `<a href="${escapeHtml15(section.href)}">Open</a>` : ""}
|
|
11467
11671
|
</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>${
|
|
11672
|
+
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
11673
|
};
|
|
11470
11674
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
11471
11675
|
const path = options.path ?? "/api/demo-ready";
|
|
11472
11676
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
11473
|
-
const routes = new
|
|
11677
|
+
const routes = new Elysia12({
|
|
11474
11678
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
11475
11679
|
});
|
|
11476
11680
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -11489,7 +11693,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
11489
11693
|
return routes;
|
|
11490
11694
|
};
|
|
11491
11695
|
// src/deliverySinkRoutes.ts
|
|
11492
|
-
import { Elysia as
|
|
11696
|
+
import { Elysia as Elysia13 } from "elysia";
|
|
11493
11697
|
|
|
11494
11698
|
// src/queue.ts
|
|
11495
11699
|
var releaseLeaseScript = `
|
|
@@ -12432,7 +12636,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
12432
12636
|
};
|
|
12433
12637
|
|
|
12434
12638
|
// src/deliverySinkRoutes.ts
|
|
12435
|
-
var
|
|
12639
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12436
12640
|
var deliveryStatus = (summary) => {
|
|
12437
12641
|
if (!summary) {
|
|
12438
12642
|
return "warn";
|
|
@@ -12531,13 +12735,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
12531
12735
|
return "";
|
|
12532
12736
|
}
|
|
12533
12737
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
12534
|
-
const body = `<span>${
|
|
12535
|
-
return `<article>${surface.href ? `<a href="${
|
|
12738
|
+
const body = `<span>${escapeHtml16(surface.label)}</span><strong>${escapeHtml16(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
12739
|
+
return `<article>${surface.href ? `<a href="${escapeHtml16(surface.href)}">${body}</a>` : body}</article>`;
|
|
12536
12740
|
};
|
|
12537
12741
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
12538
12742
|
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>${
|
|
12743
|
+
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>';
|
|
12744
|
+
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
12745
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
12542
12746
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
12543
12747
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -12549,7 +12753,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
12549
12753
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
12550
12754
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
12551
12755
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
12552
|
-
const routes = new
|
|
12756
|
+
const routes = new Elysia13({
|
|
12553
12757
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
12554
12758
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
12555
12759
|
if (htmlPath !== false) {
|
|
@@ -12567,7 +12771,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
12567
12771
|
return routes;
|
|
12568
12772
|
};
|
|
12569
12773
|
// src/opsActionAuditRoutes.ts
|
|
12570
|
-
import { Elysia as
|
|
12774
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12571
12775
|
var readRecordBody = (body) => {
|
|
12572
12776
|
if (!body || typeof body !== "object") {
|
|
12573
12777
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -12642,7 +12846,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
12642
12846
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
12643
12847
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
12644
12848
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
12645
|
-
const routes = new
|
|
12849
|
+
const routes = new Elysia14({
|
|
12646
12850
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
12647
12851
|
}).post(path, async ({ body, request, set }) => {
|
|
12648
12852
|
try {
|
|
@@ -12692,13 +12896,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
12692
12896
|
total: entries.length
|
|
12693
12897
|
};
|
|
12694
12898
|
};
|
|
12695
|
-
var
|
|
12899
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12696
12900
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
12697
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
12901
|
+
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
12902
|
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
12903
|
};
|
|
12700
12904
|
// src/platformCoverage.ts
|
|
12701
|
-
import { Elysia as
|
|
12905
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12702
12906
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
12703
12907
|
const coverage = input.coverage ?? [];
|
|
12704
12908
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -12759,7 +12963,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
12759
12963
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
12760
12964
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
12761
12965
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
12762
|
-
const routes = new
|
|
12966
|
+
const routes = new Elysia15({
|
|
12763
12967
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
12764
12968
|
});
|
|
12765
12969
|
routes.get(path, async () => {
|
|
@@ -12771,8 +12975,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
12771
12975
|
return routes;
|
|
12772
12976
|
};
|
|
12773
12977
|
// src/competitiveCoverage.ts
|
|
12774
|
-
import { Elysia as
|
|
12775
|
-
var
|
|
12978
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12979
|
+
var escapeHtml18 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12776
12980
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
12777
12981
|
var resolveSurfaceStatus = (surface) => {
|
|
12778
12982
|
if (surface.status)
|
|
@@ -12940,24 +13144,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
12940
13144
|
`);
|
|
12941
13145
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
12942
13146
|
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>${
|
|
13147
|
+
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("");
|
|
13148
|
+
return `<article class="surface ${escapeHtml18(surface.status)} ${escapeHtml18(surface.depth)}">
|
|
13149
|
+
<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>
|
|
13150
|
+
<p>${escapeHtml18(surface.why)}</p>
|
|
12947
13151
|
<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>${
|
|
13152
|
+
<div><dt>Competitors</dt><dd>${escapeHtml18((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
13153
|
+
<div><dt>Operations record</dt><dd>${escapeHtml18(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
13154
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml18(surface.readinessGate ?? "unknown")}</dd></div>
|
|
13155
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml18((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
12952
13156
|
</dl>
|
|
12953
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
12954
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
13157
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml18(surface.remainingGap)}</p>` : ""}
|
|
13158
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml18(surface.nextMove)}</p>` : ""}
|
|
12955
13159
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
12956
13160
|
</article>`;
|
|
12957
13161
|
}).join(`
|
|
12958
13162
|
`);
|
|
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>${
|
|
13163
|
+
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("");
|
|
13164
|
+
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
13165
|
};
|
|
12962
13166
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
12963
13167
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -12970,7 +13174,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12970
13174
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
12971
13175
|
return normalizeCompetitiveCoverageReport(value);
|
|
12972
13176
|
};
|
|
12973
|
-
const app = new
|
|
13177
|
+
const app = new Elysia16({
|
|
12974
13178
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
12975
13179
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
12976
13180
|
headers: {
|
|
@@ -13001,7 +13205,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13001
13205
|
return app;
|
|
13002
13206
|
};
|
|
13003
13207
|
// src/proofTrends.ts
|
|
13004
|
-
import { Elysia as
|
|
13208
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13005
13209
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
13006
13210
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
13007
13211
|
var toTimeMs = (value) => {
|
|
@@ -13152,7 +13356,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
13152
13356
|
};
|
|
13153
13357
|
var createVoiceProofTrendRoutes = (options) => {
|
|
13154
13358
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
13155
|
-
const routes = new
|
|
13359
|
+
const routes = new Elysia17({
|
|
13156
13360
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
13157
13361
|
});
|
|
13158
13362
|
routes.get(path, async () => {
|
|
@@ -13185,11 +13389,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
13185
13389
|
return `${days}d ${hours % 24}h`;
|
|
13186
13390
|
};
|
|
13187
13391
|
// src/providerDecisionTraces.ts
|
|
13188
|
-
import { Elysia as
|
|
13392
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13189
13393
|
|
|
13190
13394
|
// src/resilienceRoutes.ts
|
|
13191
|
-
import { Elysia as
|
|
13192
|
-
var
|
|
13395
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
13396
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13193
13397
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
13194
13398
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13195
13399
|
var getBoolean2 = (value) => value === true;
|
|
@@ -13337,13 +13541,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
13337
13541
|
};
|
|
13338
13542
|
var renderProviderCards = (title, providers) => {
|
|
13339
13543
|
if (providers.length === 0) {
|
|
13340
|
-
return `<p class="muted">No ${
|
|
13544
|
+
return `<p class="muted">No ${escapeHtml19(title)} provider health yet.</p>`;
|
|
13341
13545
|
}
|
|
13342
13546
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
13343
|
-
<article class="card provider ${
|
|
13547
|
+
<article class="card provider ${escapeHtml19(provider.status)}">
|
|
13344
13548
|
<div class="card-header">
|
|
13345
|
-
<strong>${
|
|
13346
|
-
<span>${
|
|
13549
|
+
<strong>${escapeHtml19(provider.provider)}</strong>
|
|
13550
|
+
<span>${escapeHtml19(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
13347
13551
|
</div>
|
|
13348
13552
|
<dl>
|
|
13349
13553
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -13352,7 +13556,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
13352
13556
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
13353
13557
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
13354
13558
|
</dl>
|
|
13355
|
-
${provider.lastError ? `<p class="muted">${
|
|
13559
|
+
${provider.lastError ? `<p class="muted">${escapeHtml19(provider.lastError)}</p>` : ""}
|
|
13356
13560
|
</article>
|
|
13357
13561
|
`).join("")}</div>`;
|
|
13358
13562
|
};
|
|
@@ -13361,24 +13565,24 @@ var renderTimeline2 = (events) => {
|
|
|
13361
13565
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
13362
13566
|
}
|
|
13363
13567
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
13364
|
-
<article class="card event ${
|
|
13568
|
+
<article class="card event ${escapeHtml19(event.status ?? "unknown")}">
|
|
13365
13569
|
<div class="card-header">
|
|
13366
|
-
<strong>${
|
|
13570
|
+
<strong>${escapeHtml19(event.kind.toUpperCase())} ${escapeHtml19(event.operation ?? "generate")}</strong>
|
|
13367
13571
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
13368
13572
|
</div>
|
|
13369
13573
|
<p>
|
|
13370
|
-
<span class="pill">${
|
|
13371
|
-
<span class="pill">provider: ${
|
|
13372
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
13574
|
+
<span class="pill">${escapeHtml19(event.status ?? "unknown")}</span>
|
|
13575
|
+
<span class="pill">provider: ${escapeHtml19(event.provider ?? "unknown")}</span>
|
|
13576
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml19(event.fallbackProvider)}</span>` : ""}
|
|
13373
13577
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
13374
13578
|
</p>
|
|
13375
13579
|
<dl>
|
|
13376
13580
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
13377
13581
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
13378
13582
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
13379
|
-
<div><dt>Session</dt><dd>${
|
|
13583
|
+
<div><dt>Session</dt><dd>${escapeHtml19(event.sessionId)}</dd></div>
|
|
13380
13584
|
</dl>
|
|
13381
|
-
${event.error ? `<p class="muted">${
|
|
13585
|
+
${event.error ? `<p class="muted">${escapeHtml19(event.error)}</p>` : ""}
|
|
13382
13586
|
</article>
|
|
13383
13587
|
`).join("")}</div>`;
|
|
13384
13588
|
};
|
|
@@ -13388,9 +13592,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
13388
13592
|
const status = latest?.status ?? "idle";
|
|
13389
13593
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
13390
13594
|
return `<div>
|
|
13391
|
-
<dt>${
|
|
13392
|
-
<dd>${
|
|
13393
|
-
<small>${
|
|
13595
|
+
<dt>${escapeHtml19(kind.toUpperCase())}</dt>
|
|
13596
|
+
<dd>${escapeHtml19(provider)}${escapeHtml19(fallback)}</dd>
|
|
13597
|
+
<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
13598
|
</div>`;
|
|
13395
13599
|
};
|
|
13396
13600
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -13398,10 +13602,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
13398
13602
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
13399
13603
|
}
|
|
13400
13604
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
13401
|
-
<article class="card session ${
|
|
13605
|
+
<article class="card session ${escapeHtml19(session.status)}">
|
|
13402
13606
|
<div class="card-header">
|
|
13403
|
-
<strong>${
|
|
13404
|
-
<span>${
|
|
13607
|
+
<strong>${escapeHtml19(session.sessionId)}</strong>
|
|
13608
|
+
<span>${escapeHtml19(session.status)}</span>
|
|
13405
13609
|
</div>
|
|
13406
13610
|
<p>
|
|
13407
13611
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -13428,21 +13632,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
13428
13632
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
13429
13633
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
13430
13634
|
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">${
|
|
13635
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml19(pathPrefix)}">
|
|
13636
|
+
<p class="muted">${escapeHtml19(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
13433
13637
|
<div class="simulate-actions">
|
|
13434
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
13435
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
13638
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml19(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml19(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
13639
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml19(provider.provider)}">Mark ${escapeHtml19(provider.provider)} recovered</button>`).join("")}
|
|
13436
13640
|
</div>
|
|
13437
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
13641
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml19(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
13438
13642
|
<pre class="simulate-output" hidden></pre>
|
|
13439
13643
|
</div>`;
|
|
13440
13644
|
};
|
|
13441
13645
|
var renderVoiceResilienceHTML = (input) => {
|
|
13442
13646
|
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 =
|
|
13647
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml19(kind)}: ${String(count)}</span>`).join("");
|
|
13648
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join(" \xB7 ") : "";
|
|
13649
|
+
const snippet = escapeHtml19(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
13446
13650
|
kind: 'stt',
|
|
13447
13651
|
providers: ['deepgram', 'assemblyai'],
|
|
13448
13652
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -13480,7 +13684,7 @@ app.use(
|
|
|
13480
13684
|
<head>
|
|
13481
13685
|
<meta charset="utf-8" />
|
|
13482
13686
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13483
|
-
<title>${
|
|
13687
|
+
<title>${escapeHtml19(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
13484
13688
|
<style>
|
|
13485
13689
|
:root { color-scheme: dark; }
|
|
13486
13690
|
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 +13836,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
13632
13836
|
};
|
|
13633
13837
|
var createVoiceResilienceRoutes = (options) => {
|
|
13634
13838
|
const path = options.path ?? "/resilience";
|
|
13635
|
-
const routes = new
|
|
13839
|
+
const routes = new Elysia18({
|
|
13636
13840
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
13637
13841
|
}).get(path, async () => {
|
|
13638
13842
|
const events = await options.store.list();
|
|
@@ -13673,7 +13877,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
13673
13877
|
};
|
|
13674
13878
|
|
|
13675
13879
|
// src/providerDecisionTraces.ts
|
|
13676
|
-
var
|
|
13880
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13677
13881
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
13678
13882
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13679
13883
|
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 +13892,8 @@ var surfaceForKind = (kind) => {
|
|
|
13688
13892
|
return "live-call";
|
|
13689
13893
|
}
|
|
13690
13894
|
};
|
|
13691
|
-
var
|
|
13692
|
-
var reportStatus = (issues) => issues.reduce((status, issue) =>
|
|
13895
|
+
var statusRank2 = { fail: 2, pass: 0, warn: 1 };
|
|
13896
|
+
var reportStatus = (issues) => issues.reduce((status, issue) => statusRank2[issue.status] > statusRank2[status] ? issue.status : status, "pass");
|
|
13693
13897
|
var uniqueSorted = (values) => [
|
|
13694
13898
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
13695
13899
|
].sort();
|
|
@@ -13914,7 +14118,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
13914
14118
|
<head>
|
|
13915
14119
|
<meta charset="utf-8" />
|
|
13916
14120
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13917
|
-
<title>${
|
|
14121
|
+
<title>${escapeHtml20(title)}</title>
|
|
13918
14122
|
<style>
|
|
13919
14123
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
13920
14124
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -13928,8 +14132,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13928
14132
|
</head>
|
|
13929
14133
|
<body>
|
|
13930
14134
|
<main>
|
|
13931
|
-
<p class="status ${report.status}">${
|
|
13932
|
-
<h1>${
|
|
14135
|
+
<p class="status ${report.status}">${escapeHtml20(report.status)}</p>
|
|
14136
|
+
<h1>${escapeHtml20(title)}</h1>
|
|
13933
14137
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
13934
14138
|
<section class="grid">
|
|
13935
14139
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -13940,10 +14144,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13940
14144
|
</section>
|
|
13941
14145
|
<section class="surfaces">
|
|
13942
14146
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
13943
|
-
<header><strong>${
|
|
14147
|
+
<header><strong>${escapeHtml20(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml20(surface.status)}</span></header>
|
|
13944
14148
|
<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>${
|
|
14149
|
+
<p class="muted">Providers: ${escapeHtml20(surface.providers.join(", ") || "none")}</p>
|
|
14150
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml20(reason)}</code>`).join(" ")}</p>
|
|
13947
14151
|
</article>`).join(`
|
|
13948
14152
|
`)}
|
|
13949
14153
|
</section>
|
|
@@ -13957,7 +14161,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13957
14161
|
const headers = options.headers ?? {};
|
|
13958
14162
|
const title = options.title ?? "Provider Decision Traces";
|
|
13959
14163
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
13960
|
-
const app = new
|
|
14164
|
+
const app = new Elysia19({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13961
14165
|
headers: {
|
|
13962
14166
|
"content-type": "application/json; charset=utf-8",
|
|
13963
14167
|
...headers
|
|
@@ -13985,7 +14189,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13985
14189
|
return app;
|
|
13986
14190
|
};
|
|
13987
14191
|
// src/sloCalibration.ts
|
|
13988
|
-
import { Elysia as
|
|
14192
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
13989
14193
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
13990
14194
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
13991
14195
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -14165,7 +14369,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
14165
14369
|
};
|
|
14166
14370
|
};
|
|
14167
14371
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
14168
|
-
var
|
|
14372
|
+
var escapeHtml21 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14169
14373
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
14170
14374
|
var readinessThresholdRows = (report) => [
|
|
14171
14375
|
{
|
|
@@ -14256,15 +14460,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
14256
14460
|
};
|
|
14257
14461
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
14258
14462
|
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>${
|
|
14463
|
+
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("");
|
|
14464
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml21(issue)}</li>`).join("");
|
|
14465
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml21(source)}</code></li>`).join("");
|
|
14466
|
+
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
14467
|
};
|
|
14264
14468
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
14265
14469
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
14266
14470
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
14267
|
-
const routes = new
|
|
14471
|
+
const routes = new Elysia20({
|
|
14268
14472
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
14269
14473
|
});
|
|
14270
14474
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14288,7 +14492,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14288
14492
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
14289
14493
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
14290
14494
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
14291
|
-
const routes = new
|
|
14495
|
+
const routes = new Elysia20({
|
|
14292
14496
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
14293
14497
|
});
|
|
14294
14498
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14322,7 +14526,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14322
14526
|
return routes;
|
|
14323
14527
|
};
|
|
14324
14528
|
// src/liveOps.ts
|
|
14325
|
-
import { Elysia as
|
|
14529
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14326
14530
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
14327
14531
|
"assign",
|
|
14328
14532
|
"create-task",
|
|
@@ -14632,7 +14836,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14632
14836
|
const controller = createVoiceLiveOpsController(options);
|
|
14633
14837
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
14634
14838
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
14635
|
-
return new
|
|
14839
|
+
return new Elysia21({
|
|
14636
14840
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
14637
14841
|
}).post(path, async ({ request, set }) => {
|
|
14638
14842
|
try {
|
|
@@ -14654,15 +14858,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14654
14858
|
});
|
|
14655
14859
|
};
|
|
14656
14860
|
// src/deliveryRuntime.ts
|
|
14657
|
-
import { Elysia as
|
|
14861
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14658
14862
|
import { mkdir } from "fs/promises";
|
|
14659
14863
|
import { dirname, join } from "path";
|
|
14660
|
-
var
|
|
14864
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14661
14865
|
var renderSummaryCard = (label, summary) => {
|
|
14662
14866
|
if (!summary) {
|
|
14663
|
-
return `<article><span>${
|
|
14867
|
+
return `<article><span>${escapeHtml22(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
14664
14868
|
}
|
|
14665
|
-
return `<article><span>${
|
|
14869
|
+
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
14870
|
};
|
|
14667
14871
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
14668
14872
|
audit: leases,
|
|
@@ -14873,9 +15077,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
14873
15077
|
});
|
|
14874
15078
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
14875
15079
|
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 =
|
|
15080
|
+
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>`;
|
|
15081
|
+
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>`;
|
|
15082
|
+
const snippet = escapeHtml22(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
14879
15083
|
createVoiceDeliveryRuntimePresetConfig({
|
|
14880
15084
|
audit: {
|
|
14881
15085
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -14901,14 +15105,14 @@ app.use(
|
|
|
14901
15105
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
14902
15106
|
})
|
|
14903
15107
|
);`);
|
|
14904
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15108
|
+
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
15109
|
};
|
|
14906
15110
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
14907
15111
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
14908
15112
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
14909
15113
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
14910
15114
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
14911
|
-
const routes = new
|
|
15115
|
+
const routes = new Elysia22({
|
|
14912
15116
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
14913
15117
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
14914
15118
|
if (tickPath !== false) {
|
|
@@ -14944,7 +15148,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
14944
15148
|
return routes;
|
|
14945
15149
|
};
|
|
14946
15150
|
// src/dataControl.ts
|
|
14947
|
-
import { Elysia as
|
|
15151
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
14948
15152
|
var voiceComplianceRedactionDefaults = {
|
|
14949
15153
|
keys: [
|
|
14950
15154
|
"apiKey",
|
|
@@ -15183,7 +15387,7 @@ var parseRetentionScopes = (value) => {
|
|
|
15183
15387
|
const allowed = new Set(allRetentionScopes);
|
|
15184
15388
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
15185
15389
|
};
|
|
15186
|
-
var
|
|
15390
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15187
15391
|
var buildStorageSurfaces = (options) => [
|
|
15188
15392
|
{
|
|
15189
15393
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -15420,12 +15624,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
15420
15624
|
zeroRetentionAvailable: true
|
|
15421
15625
|
};
|
|
15422
15626
|
};
|
|
15423
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
15627
|
+
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
15628
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
15425
15629
|
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>${
|
|
15630
|
+
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("");
|
|
15631
|
+
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("");
|
|
15632
|
+
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
15633
|
};
|
|
15430
15634
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
15431
15635
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -15483,7 +15687,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
15483
15687
|
var createVoiceDataControlRoutes = (options) => {
|
|
15484
15688
|
const path = options.path ?? "/data-control";
|
|
15485
15689
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
15486
|
-
const routes = new
|
|
15690
|
+
const routes = new Elysia23({
|
|
15487
15691
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
15488
15692
|
});
|
|
15489
15693
|
routes.get(path, async ({ query }) => {
|
|
@@ -15559,16 +15763,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
15559
15763
|
return routes;
|
|
15560
15764
|
};
|
|
15561
15765
|
// src/evalRoutes.ts
|
|
15562
|
-
import { Elysia as
|
|
15766
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
15563
15767
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
15564
15768
|
import { dirname as dirname2 } from "path";
|
|
15565
15769
|
|
|
15566
15770
|
// src/qualityRoutes.ts
|
|
15567
|
-
import { Elysia as
|
|
15771
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15568
15772
|
|
|
15569
15773
|
// src/handoffHealth.ts
|
|
15570
|
-
import { Elysia as
|
|
15571
|
-
var
|
|
15774
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15775
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15572
15776
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15573
15777
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
15574
15778
|
var increment3 = (record, key) => {
|
|
@@ -15686,10 +15890,10 @@ var renderActionSummary = (summary) => {
|
|
|
15686
15890
|
return [
|
|
15687
15891
|
'<section class="voice-handoff-health-columns">',
|
|
15688
15892
|
"<article><h3>Actions</h3>",
|
|
15689
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
15893
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml24(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
15690
15894
|
"</article>",
|
|
15691
15895
|
"<article><h3>Adapters</h3>",
|
|
15692
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
15896
|
+
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
15897
|
"</article>",
|
|
15694
15898
|
"</section>"
|
|
15695
15899
|
].join("");
|
|
@@ -15703,22 +15907,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
15703
15907
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
15704
15908
|
'<div class="voice-handoff-health-events">',
|
|
15705
15909
|
...summary.events.map((event) => [
|
|
15706
|
-
`<article class="${
|
|
15910
|
+
`<article class="${escapeHtml24(event.status)}">`,
|
|
15707
15911
|
'<div class="voice-handoff-health-event-header">',
|
|
15708
|
-
`<strong>${
|
|
15709
|
-
`<span>${
|
|
15912
|
+
`<strong>${escapeHtml24(event.action ?? "handoff")}</strong>`,
|
|
15913
|
+
`<span>${escapeHtml24(event.status)}</span>`,
|
|
15710
15914
|
"</div>",
|
|
15711
|
-
`<p><small>${
|
|
15712
|
-
event.target ? `<p>Target: ${
|
|
15713
|
-
event.reason ? `<p>Reason: ${
|
|
15915
|
+
`<p><small>${escapeHtml24(event.sessionId)}</small></p>`,
|
|
15916
|
+
event.target ? `<p>Target: ${escapeHtml24(event.target)}</p>` : "",
|
|
15917
|
+
event.reason ? `<p>Reason: ${escapeHtml24(event.reason)}</p>` : "",
|
|
15714
15918
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
15715
15919
|
"<li>",
|
|
15716
|
-
`${
|
|
15717
|
-
delivery.deliveredTo ? ` to ${
|
|
15718
|
-
delivery.error ? ` (${
|
|
15920
|
+
`${escapeHtml24(delivery.adapterId)}: ${escapeHtml24(delivery.status)}`,
|
|
15921
|
+
delivery.deliveredTo ? ` to ${escapeHtml24(delivery.deliveredTo)}` : "",
|
|
15922
|
+
delivery.error ? ` (${escapeHtml24(delivery.error)})` : "",
|
|
15719
15923
|
"</li>"
|
|
15720
15924
|
].join("")).join("")}</ul>` : "",
|
|
15721
|
-
event.replayHref ? `<p><a href="${
|
|
15925
|
+
event.replayHref ? `<p><a href="${escapeHtml24(event.replayHref)}">Open replay</a></p>` : "",
|
|
15722
15926
|
"</article>"
|
|
15723
15927
|
].join("")),
|
|
15724
15928
|
"</div>"
|
|
@@ -15750,7 +15954,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
15750
15954
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
15751
15955
|
const path = options.path ?? "/api/voice-handoffs";
|
|
15752
15956
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
15753
|
-
const routes = new
|
|
15957
|
+
const routes = new Elysia24({
|
|
15754
15958
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
15755
15959
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
15756
15960
|
if (htmlPath) {
|
|
@@ -15871,17 +16075,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
15871
16075
|
thresholds
|
|
15872
16076
|
};
|
|
15873
16077
|
};
|
|
15874
|
-
var
|
|
16078
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15875
16079
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
15876
16080
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
15877
16081
|
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="${
|
|
16082
|
+
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("");
|
|
16083
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15880
16084
|
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
16085
|
};
|
|
15882
16086
|
var createVoiceQualityRoutes = (options) => {
|
|
15883
16087
|
const path = options.path ?? "/quality";
|
|
15884
|
-
const routes = new
|
|
16088
|
+
const routes = new Elysia25({
|
|
15885
16089
|
name: options.name ?? "absolutejs-voice-quality"
|
|
15886
16090
|
});
|
|
15887
16091
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -15910,7 +16114,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
15910
16114
|
};
|
|
15911
16115
|
|
|
15912
16116
|
// src/evalRoutes.ts
|
|
15913
|
-
var
|
|
16117
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15914
16118
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
15915
16119
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
15916
16120
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -16232,7 +16436,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
16232
16436
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
16233
16437
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
16234
16438
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
16235
|
-
const snippet =
|
|
16439
|
+
const snippet = escapeHtml26(`app.use(
|
|
16236
16440
|
createVoiceEvalRoutes({
|
|
16237
16441
|
path: '/evals',
|
|
16238
16442
|
store: traceStore,
|
|
@@ -16253,48 +16457,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
16253
16457
|
};
|
|
16254
16458
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
16255
16459
|
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>${
|
|
16460
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16461
|
+
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
16462
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
16259
16463
|
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>${
|
|
16464
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml26(session.operationsRecordHref)}">${escapeHtml26(session.sessionId)}</a>` : escapeHtml26(session.sessionId);
|
|
16465
|
+
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
16466
|
}).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>${
|
|
16467
|
+
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
16468
|
};
|
|
16265
16469
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
16266
16470
|
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>${
|
|
16471
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16472
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml26(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
16473
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml26(id)}</li>`).join("") : "<li>none</li>";
|
|
16474
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml26(id)}</li>`).join("") : "<li>none</li>";
|
|
16475
|
+
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
16476
|
};
|
|
16273
16477
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
16274
16478
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
16275
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16479
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16276
16480
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
16277
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
16481
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml26(issue)}</li>`).join("")}</ul>` : "";
|
|
16278
16482
|
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>${
|
|
16483
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml26(session.operationsRecordHref)}">${escapeHtml26(session.sessionId)}</a>` : escapeHtml26(session.sessionId);
|
|
16484
|
+
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
16485
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
16282
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
16486
|
+
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
16487
|
}).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>${
|
|
16488
|
+
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
16489
|
};
|
|
16286
16490
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
16287
16491
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
16288
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16492
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16289
16493
|
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>${
|
|
16494
|
+
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("");
|
|
16495
|
+
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
16496
|
}).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>${
|
|
16497
|
+
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
16498
|
};
|
|
16295
16499
|
var createVoiceEvalRoutes = (options) => {
|
|
16296
16500
|
const path = options.path ?? "/evals";
|
|
16297
|
-
const routes = new
|
|
16501
|
+
const routes = new Elysia26({
|
|
16298
16502
|
name: options.name ?? "absolutejs-voice-evals"
|
|
16299
16503
|
});
|
|
16300
16504
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -16431,11 +16635,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
16431
16635
|
return routes;
|
|
16432
16636
|
};
|
|
16433
16637
|
// src/simulationSuite.ts
|
|
16434
|
-
import { Elysia as
|
|
16638
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
16435
16639
|
|
|
16436
16640
|
// src/outcomeContract.ts
|
|
16437
|
-
import { Elysia as
|
|
16438
|
-
var
|
|
16641
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16642
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16439
16643
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
16440
16644
|
if (value === false) {
|
|
16441
16645
|
return;
|
|
@@ -16646,13 +16850,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
16646
16850
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
16647
16851
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
16648
16852
|
const contracts = report.contracts.map((contract) => {
|
|
16649
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
16853
|
+
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
16854
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16651
16855
|
<div class="contract-header">
|
|
16652
16856
|
<div>
|
|
16653
|
-
<p class="eyebrow">${
|
|
16654
|
-
<h2>${
|
|
16655
|
-
${contract.description ? `<p>${
|
|
16857
|
+
<p class="eyebrow">${escapeHtml27(contract.contractId)}</p>
|
|
16858
|
+
<h2>${escapeHtml27(contract.label ?? contract.contractId)}</h2>
|
|
16859
|
+
${contract.description ? `<p>${escapeHtml27(contract.description)}</p>` : ""}
|
|
16656
16860
|
${sessionLinks}
|
|
16657
16861
|
</div>
|
|
16658
16862
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -16664,10 +16868,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
16664
16868
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
16665
16869
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
16666
16870
|
</div>
|
|
16667
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
16871
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml27(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
16668
16872
|
</section>`;
|
|
16669
16873
|
}).join("");
|
|
16670
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16874
|
+
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
16875
|
};
|
|
16672
16876
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
16673
16877
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -16683,7 +16887,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
16683
16887
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
16684
16888
|
const path = options.path ?? "/api/outcome-contracts";
|
|
16685
16889
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16686
|
-
const routes = new
|
|
16890
|
+
const routes = new Elysia27({
|
|
16687
16891
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
16688
16892
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
16689
16893
|
if (htmlPath) {
|
|
@@ -16693,7 +16897,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
16693
16897
|
};
|
|
16694
16898
|
|
|
16695
16899
|
// src/toolContract.ts
|
|
16696
|
-
import { Elysia as
|
|
16900
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16697
16901
|
|
|
16698
16902
|
// src/toolRuntime.ts
|
|
16699
16903
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -16902,7 +17106,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
16902
17106
|
});
|
|
16903
17107
|
var defaultApi = {};
|
|
16904
17108
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
16905
|
-
var
|
|
17109
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16906
17110
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
16907
17111
|
if (value === false) {
|
|
16908
17112
|
return;
|
|
@@ -17151,7 +17355,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
17151
17355
|
};
|
|
17152
17356
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
17153
17357
|
const title = options.title ?? "Voice Tool Contracts";
|
|
17154
|
-
const snippet =
|
|
17358
|
+
const snippet = escapeHtml28(`app.use(
|
|
17155
17359
|
createVoiceToolContractRoutes({
|
|
17156
17360
|
htmlPath: '/tool-contracts',
|
|
17157
17361
|
path: '/api/tool-contracts',
|
|
@@ -17177,20 +17381,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17177
17381
|
);`);
|
|
17178
17382
|
const contracts = report.contracts.map((contract) => {
|
|
17179
17383
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
17180
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
17384
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml28(testCase.operationsRecordHref)}">${escapeHtml28(testCase.label ?? testCase.caseId)}</a>` : escapeHtml28(testCase.label ?? testCase.caseId)}</td>
|
|
17181
17385
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
17182
|
-
<td>${
|
|
17183
|
-
<td>${
|
|
17386
|
+
<td>${escapeHtml28(testCase.status)}</td>
|
|
17387
|
+
<td>${escapeHtml28(testCase.sessionId)}</td>
|
|
17184
17388
|
<td>${String(testCase.attempts)}</td>
|
|
17185
17389
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
17186
17390
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
17187
|
-
<td>${
|
|
17391
|
+
<td>${escapeHtml28(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
17188
17392
|
</tr>`).join("");
|
|
17189
17393
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17190
17394
|
<div class="contract-header">
|
|
17191
17395
|
<div>
|
|
17192
|
-
<p class="eyebrow">${
|
|
17193
|
-
<h2>${
|
|
17396
|
+
<p class="eyebrow">${escapeHtml28(contract.toolName)}</p>
|
|
17397
|
+
<h2>${escapeHtml28(contract.label ?? contract.contractId)}</h2>
|
|
17194
17398
|
</div>
|
|
17195
17399
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
17196
17400
|
</div>
|
|
@@ -17200,7 +17404,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17200
17404
|
</table>
|
|
17201
17405
|
</section>`;
|
|
17202
17406
|
}).join("");
|
|
17203
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17407
|
+
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
17408
|
};
|
|
17205
17409
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
17206
17410
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -17217,7 +17421,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
17217
17421
|
var createVoiceToolContractRoutes = (options) => {
|
|
17218
17422
|
const path = options.path ?? "/api/tool-contracts";
|
|
17219
17423
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17220
|
-
const routes = new
|
|
17424
|
+
const routes = new Elysia28({
|
|
17221
17425
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
17222
17426
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
17223
17427
|
if (htmlPath) {
|
|
@@ -17227,7 +17431,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
17227
17431
|
};
|
|
17228
17432
|
|
|
17229
17433
|
// src/simulationSuite.ts
|
|
17230
|
-
var
|
|
17434
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17231
17435
|
var summarizeSection = (report) => ({
|
|
17232
17436
|
failed: report.failed,
|
|
17233
17437
|
passed: report.passed,
|
|
@@ -17423,15 +17627,15 @@ var renderSection = (label, summary) => {
|
|
|
17423
17627
|
if (!summary) {
|
|
17424
17628
|
return "";
|
|
17425
17629
|
}
|
|
17426
|
-
return `<article class="${
|
|
17630
|
+
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
17631
|
};
|
|
17428
17632
|
var renderAction = (action) => {
|
|
17429
|
-
const content = `<strong>${
|
|
17430
|
-
return action.href ? `<a class="action" href="${
|
|
17633
|
+
const content = `<strong>${escapeHtml29(action.label)}</strong><p>${escapeHtml29(action.description)}</p><span>${escapeHtml29(action.section)} / ${escapeHtml29(action.severity)}</span>`;
|
|
17634
|
+
return action.href ? `<a class="action" href="${escapeHtml29(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
17431
17635
|
};
|
|
17432
17636
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
17433
17637
|
const title = options.title ?? "Voice Simulation Suite";
|
|
17434
|
-
const snippet =
|
|
17638
|
+
const snippet = escapeHtml29(`app.use(
|
|
17435
17639
|
createVoiceSimulationSuiteRoutes({
|
|
17436
17640
|
htmlPath: '/voice/simulations',
|
|
17437
17641
|
path: '/api/voice/simulations',
|
|
@@ -17464,12 +17668,12 @@ app.use(
|
|
|
17464
17668
|
store: traceStore
|
|
17465
17669
|
})
|
|
17466
17670
|
);`);
|
|
17467
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17671
|
+
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
17672
|
};
|
|
17469
17673
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
17470
17674
|
const path = options.path ?? "/api/voice/simulations";
|
|
17471
17675
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
17472
|
-
const app = new
|
|
17676
|
+
const app = new Elysia29({
|
|
17473
17677
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
17474
17678
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
17475
17679
|
if (htmlPath) {
|
|
@@ -17781,9 +17985,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
17781
17985
|
};
|
|
17782
17986
|
};
|
|
17783
17987
|
// src/sessionReplay.ts
|
|
17784
|
-
import { Elysia as
|
|
17988
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
17785
17989
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
17786
|
-
var
|
|
17990
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17787
17991
|
var increment4 = (record, key) => {
|
|
17788
17992
|
record[key] = (record[key] ?? 0) + 1;
|
|
17789
17993
|
};
|
|
@@ -17977,10 +18181,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
17977
18181
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
17978
18182
|
'<div class="voice-sessions-list">',
|
|
17979
18183
|
...sessions.map((session) => [
|
|
17980
|
-
`<article class="voice-session-card ${
|
|
18184
|
+
`<article class="voice-session-card ${escapeHtml30(session.status)}">`,
|
|
17981
18185
|
'<div class="voice-session-card-header">',
|
|
17982
|
-
`<strong>${
|
|
17983
|
-
`<span>${
|
|
18186
|
+
`<strong>${escapeHtml30(session.sessionId)}</strong>`,
|
|
18187
|
+
`<span>${escapeHtml30(session.status)}</span>`,
|
|
17984
18188
|
"</div>",
|
|
17985
18189
|
"<dl>",
|
|
17986
18190
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -17988,9 +18192,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
17988
18192
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
17989
18193
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
17990
18194
|
"</dl>",
|
|
17991
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
17992
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
17993
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
18195
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml30(session.latestOutcome)}</p>` : "",
|
|
18196
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml30).join(", ")}</p>` : "",
|
|
18197
|
+
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
18198
|
"</article>"
|
|
17995
18199
|
].join("")),
|
|
17996
18200
|
"</div>"
|
|
@@ -18021,7 +18225,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
18021
18225
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
18022
18226
|
const path = options.path ?? "/api/voice-sessions";
|
|
18023
18227
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18024
|
-
const routes = new
|
|
18228
|
+
const routes = new Elysia30({
|
|
18025
18229
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
18026
18230
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
18027
18231
|
if (htmlPath) {
|
|
@@ -18049,7 +18253,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
18049
18253
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
18050
18254
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
18051
18255
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18052
|
-
const routes = new
|
|
18256
|
+
const routes = new Elysia30({
|
|
18053
18257
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
18054
18258
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
18055
18259
|
if (htmlPath) {
|
|
@@ -18363,10 +18567,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
18363
18567
|
return report;
|
|
18364
18568
|
};
|
|
18365
18569
|
// src/turnLatency.ts
|
|
18366
|
-
import { Elysia as
|
|
18570
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
18367
18571
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
18368
18572
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
18369
|
-
var
|
|
18573
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18370
18574
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18371
18575
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
18372
18576
|
var createTraceStageIndex = (events) => {
|
|
@@ -18498,11 +18702,11 @@ await traceStore.append({
|
|
|
18498
18702
|
turnId,
|
|
18499
18703
|
type: 'turn_latency.stage'
|
|
18500
18704
|
});`;
|
|
18501
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18502
|
-
<header><div><p class="eyebrow">${
|
|
18503
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
18705
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml31(turn.status)}">
|
|
18706
|
+
<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>
|
|
18707
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml31(stage.label)}</dt><dd>${escapeHtml31(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
18504
18708
|
</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>${
|
|
18709
|
+
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
18710
|
};
|
|
18507
18711
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
18508
18712
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -18519,7 +18723,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
18519
18723
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
18520
18724
|
const path = options.path ?? "/api/turn-latency";
|
|
18521
18725
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18522
|
-
const routes = new
|
|
18726
|
+
const routes = new Elysia31({
|
|
18523
18727
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
18524
18728
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
18525
18729
|
if (htmlPath) {
|
|
@@ -18528,8 +18732,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
18528
18732
|
return routes;
|
|
18529
18733
|
};
|
|
18530
18734
|
// src/liveLatency.ts
|
|
18531
|
-
import { Elysia as
|
|
18532
|
-
var
|
|
18735
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
18736
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18533
18737
|
var percentile3 = (values, percentileValue) => {
|
|
18534
18738
|
if (values.length === 0) {
|
|
18535
18739
|
return;
|
|
@@ -18596,13 +18800,13 @@ await traceStore.append({
|
|
|
18596
18800
|
sessionId,
|
|
18597
18801
|
type: 'client.live_latency'
|
|
18598
18802
|
});`;
|
|
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>${
|
|
18803
|
+
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("");
|
|
18804
|
+
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
18805
|
};
|
|
18602
18806
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
18603
18807
|
const path = options.path ?? "/api/live-latency";
|
|
18604
18808
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
18605
|
-
const routes = new
|
|
18809
|
+
const routes = new Elysia32({
|
|
18606
18810
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
18607
18811
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
18608
18812
|
if (htmlPath) {
|
|
@@ -18921,9 +19125,9 @@ None.
|
|
|
18921
19125
|
`}`;
|
|
18922
19126
|
};
|
|
18923
19127
|
// src/turnQuality.ts
|
|
18924
|
-
import { Elysia as
|
|
19128
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18925
19129
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
18926
|
-
var
|
|
19130
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18927
19131
|
var getTurnLatencyMs = (turn) => {
|
|
18928
19132
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18929
19133
|
if (firstTranscriptAt === undefined) {
|
|
@@ -18994,24 +19198,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
18994
19198
|
};
|
|
18995
19199
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
18996
19200
|
const title = options.title ?? "Voice Turn Quality";
|
|
18997
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19201
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml33(turn.status)}">
|
|
18998
19202
|
<div class="turn-header">
|
|
18999
19203
|
<div>
|
|
19000
|
-
<p class="eyebrow">${
|
|
19001
|
-
<h2>${
|
|
19204
|
+
<p class="eyebrow">${escapeHtml33(turn.sessionId)} \xB7 ${escapeHtml33(turn.turnId)}</p>
|
|
19205
|
+
<h2>${escapeHtml33(turn.text || "Empty turn")}</h2>
|
|
19002
19206
|
</div>
|
|
19003
|
-
<strong>${
|
|
19207
|
+
<strong>${escapeHtml33(turn.status)}</strong>
|
|
19004
19208
|
</div>
|
|
19005
19209
|
<dl>
|
|
19006
|
-
<div><dt>Source</dt><dd>${
|
|
19210
|
+
<div><dt>Source</dt><dd>${escapeHtml33(turn.source ?? "unknown")}</dd></div>
|
|
19007
19211
|
<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 ${
|
|
19212
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml33(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
19213
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml33(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
19010
19214
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
19011
19215
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
19012
19216
|
</dl>
|
|
19013
19217
|
</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>${
|
|
19218
|
+
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
19219
|
};
|
|
19016
19220
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
19017
19221
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -19028,7 +19232,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
19028
19232
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
19029
19233
|
const path = options.path ?? "/api/turn-quality";
|
|
19030
19234
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19031
|
-
const routes = new
|
|
19235
|
+
const routes = new Elysia33({
|
|
19032
19236
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
19033
19237
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
19034
19238
|
if (htmlPath) {
|
|
@@ -19037,7 +19241,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
19037
19241
|
return routes;
|
|
19038
19242
|
};
|
|
19039
19243
|
// src/telephonyOutcome.ts
|
|
19040
|
-
import { Elysia as
|
|
19244
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19041
19245
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
19042
19246
|
"answered",
|
|
19043
19247
|
"completed",
|
|
@@ -19798,7 +20002,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
19798
20002
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
19799
20003
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
19800
20004
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
19801
|
-
return new
|
|
20005
|
+
return new Elysia34({
|
|
19802
20006
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
19803
20007
|
}).post(path, async ({ query, request }) => {
|
|
19804
20008
|
try {
|
|
@@ -19819,12 +20023,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
19819
20023
|
});
|
|
19820
20024
|
};
|
|
19821
20025
|
// src/phoneAgent.ts
|
|
19822
|
-
import { Elysia as
|
|
20026
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
19823
20027
|
|
|
19824
20028
|
// src/telephony/plivo.ts
|
|
19825
20029
|
import { Buffer as Buffer5 } from "buffer";
|
|
19826
20030
|
import { Database } from "bun:sqlite";
|
|
19827
|
-
import { Elysia as
|
|
20031
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
19828
20032
|
|
|
19829
20033
|
// src/telephony/contract.ts
|
|
19830
20034
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -19908,7 +20112,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
19908
20112
|
|
|
19909
20113
|
// src/telephony/twilio.ts
|
|
19910
20114
|
import { Buffer as Buffer4 } from "buffer";
|
|
19911
|
-
import { Elysia as
|
|
20115
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19912
20116
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
19913
20117
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
19914
20118
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -19938,7 +20142,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
19938
20142
|
return parameters;
|
|
19939
20143
|
};
|
|
19940
20144
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19941
|
-
var
|
|
20145
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19942
20146
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
19943
20147
|
if (!webhook?.verificationUrl) {
|
|
19944
20148
|
return;
|
|
@@ -19981,23 +20185,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
19981
20185
|
};
|
|
19982
20186
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19983
20187
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
19984
|
-
<h1>${
|
|
20188
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
19985
20189
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
19986
20190
|
<section>
|
|
19987
20191
|
<h2>URLs</h2>
|
|
19988
20192
|
<ul>
|
|
19989
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19990
|
-
<li><strong>Media stream:</strong> <code>${
|
|
19991
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
20193
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml34(status.urls.twiml)}</code></li>
|
|
20194
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml34(status.urls.stream)}</code></li>
|
|
20195
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml34(status.urls.webhook)}</code></li>
|
|
19992
20196
|
</ul>
|
|
19993
20197
|
</section>
|
|
19994
20198
|
<section>
|
|
19995
20199
|
<h2>Signing</h2>
|
|
19996
20200
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
19997
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
20201
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml34(status.signing.verificationUrl)}</code></p>` : ""}
|
|
19998
20202
|
</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>${
|
|
20203
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml34(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
20204
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml34(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
20001
20205
|
</main>`;
|
|
20002
20206
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
20003
20207
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -20008,20 +20212,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
20008
20212
|
});
|
|
20009
20213
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20010
20214
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
20011
|
-
<h1>${
|
|
20215
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
20012
20216
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20013
20217
|
<section>
|
|
20014
20218
|
<h2>Checks</h2>
|
|
20015
20219
|
<ul>
|
|
20016
|
-
${report.checks.map((check) => `<li><strong>${
|
|
20220
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml34(check.name)}</strong>: ${escapeHtml34(check.status)}${check.message ? ` - ${escapeHtml34(check.message)}` : ""}</li>`).join("")}
|
|
20017
20221
|
</ul>
|
|
20018
20222
|
</section>
|
|
20019
20223
|
<section>
|
|
20020
20224
|
<h2>Observed URLs</h2>
|
|
20021
20225
|
<ul>
|
|
20022
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20023
|
-
<li><strong>Stream:</strong> <code>${
|
|
20024
|
-
<li><strong>Webhook:</strong> <code>${
|
|
20226
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml34(report.setup.urls.twiml)}</code></li>
|
|
20227
|
+
<li><strong>Stream:</strong> <code>${escapeHtml34(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
20228
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml34(report.setup.urls.webhook)}</code></li>
|
|
20025
20229
|
</ul>
|
|
20026
20230
|
</section>
|
|
20027
20231
|
</main>`;
|
|
@@ -20481,7 +20685,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20481
20685
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
20482
20686
|
const bridges = new WeakMap;
|
|
20483
20687
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
20484
|
-
const app = new
|
|
20688
|
+
const app = new Elysia35({
|
|
20485
20689
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
20486
20690
|
}).get(twimlPath, async ({ query, request }) => {
|
|
20487
20691
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -20618,7 +20822,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20618
20822
|
|
|
20619
20823
|
// src/telephony/plivo.ts
|
|
20620
20824
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20621
|
-
var
|
|
20825
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20622
20826
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20623
20827
|
var resolveRequestOrigin2 = (request) => {
|
|
20624
20828
|
const url = new URL(request.url);
|
|
@@ -21048,21 +21252,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
21048
21252
|
};
|
|
21049
21253
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21050
21254
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
21051
|
-
<h1>${
|
|
21255
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21052
21256
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21053
21257
|
<ul>
|
|
21054
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
21055
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
21056
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21258
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml35(status.urls.answer)}</code></li>
|
|
21259
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml35(status.urls.stream)}</code></li>
|
|
21260
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml35(status.urls.webhook)}</code></li>
|
|
21057
21261
|
</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>${
|
|
21262
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml35(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21263
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml35(warning)}</li>`).join("")}</ul>` : ""}
|
|
21060
21264
|
</main>`;
|
|
21061
21265
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21062
21266
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
21063
|
-
<h1>${
|
|
21267
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21064
21268
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21065
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21269
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml35(check.name)}</strong>: ${escapeHtml35(check.status)}${check.message ? ` - ${escapeHtml35(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21066
21270
|
</main>`;
|
|
21067
21271
|
var runPlivoSmokeTest = async (input) => {
|
|
21068
21272
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -21152,7 +21356,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21152
21356
|
nonceStore: options.webhook.nonceStore,
|
|
21153
21357
|
verificationUrl: options.webhook.verificationUrl
|
|
21154
21358
|
}) : undefined);
|
|
21155
|
-
const app = new
|
|
21359
|
+
const app = new Elysia36({
|
|
21156
21360
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
21157
21361
|
}).get(answerPath, async ({ query, request }) => {
|
|
21158
21362
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -21264,9 +21468,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21264
21468
|
// src/telephony/telnyx.ts
|
|
21265
21469
|
import { Buffer as Buffer6 } from "buffer";
|
|
21266
21470
|
import { Database as Database2 } from "bun:sqlite";
|
|
21267
|
-
import { Elysia as
|
|
21471
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
21268
21472
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21269
|
-
var
|
|
21473
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21270
21474
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21271
21475
|
var resolveRequestOrigin3 = (request) => {
|
|
21272
21476
|
const url = new URL(request.url);
|
|
@@ -21659,21 +21863,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
21659
21863
|
};
|
|
21660
21864
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21661
21865
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
21662
|
-
<h1>${
|
|
21866
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
21663
21867
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21664
21868
|
<ul>
|
|
21665
|
-
<li><strong>TeXML:</strong> <code>${
|
|
21666
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21667
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21869
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml36(status.urls.texml)}</code></li>
|
|
21870
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml36(status.urls.stream)}</code></li>
|
|
21871
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml36(status.urls.webhook)}</code></li>
|
|
21668
21872
|
</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>${
|
|
21873
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml36(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21874
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml36(warning)}</li>`).join("")}</ul>` : ""}
|
|
21671
21875
|
</main>`;
|
|
21672
21876
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21673
21877
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
21674
|
-
<h1>${
|
|
21878
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
21675
21879
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21676
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21880
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml36(check.name)}</strong>: ${escapeHtml36(check.status)}${check.message ? ` - ${escapeHtml36(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21677
21881
|
</main>`;
|
|
21678
21882
|
var runTelnyxSmokeTest = async (input) => {
|
|
21679
21883
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -21766,7 +21970,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21766
21970
|
publicKey: options.webhook.publicKey,
|
|
21767
21971
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
21768
21972
|
}) : undefined);
|
|
21769
|
-
const app = new
|
|
21973
|
+
const app = new Elysia37({
|
|
21770
21974
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
21771
21975
|
}).get(texmlPath, async ({ query, request }) => {
|
|
21772
21976
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -21876,8 +22080,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21876
22080
|
};
|
|
21877
22081
|
|
|
21878
22082
|
// src/telephony/matrix.ts
|
|
21879
|
-
import { Elysia as
|
|
21880
|
-
var
|
|
22083
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
22084
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21881
22085
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
21882
22086
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
21883
22087
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -21938,13 +22142,13 @@ var badgeStyles = {
|
|
|
21938
22142
|
};
|
|
21939
22143
|
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
22144
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
21941
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
22145
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml37(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
21942
22146
|
<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
22147
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
21944
22148
|
${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
22149
|
<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]}">${
|
|
22150
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml37(entry.name)}</h2>
|
|
22151
|
+
<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
22152
|
</div>
|
|
21949
22153
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
21950
22154
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -21952,15 +22156,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
21952
22156
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
21953
22157
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
21954
22158
|
</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>${
|
|
22159
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml37(entry.setup.urls.stream || "missing")}</code></p>
|
|
22160
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml37(entry.setup.urls.webhook || "missing")}</code></p>
|
|
22161
|
+
${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
22162
|
</article>`).join("")}
|
|
21959
22163
|
</section>
|
|
21960
22164
|
</main>`;
|
|
21961
22165
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
21962
22166
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
21963
|
-
return new
|
|
22167
|
+
return new Elysia38({
|
|
21964
22168
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
21965
22169
|
}).get(path, async ({ query, request }) => {
|
|
21966
22170
|
const providers = await options.load({ query, request });
|
|
@@ -21982,7 +22186,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
21982
22186
|
};
|
|
21983
22187
|
|
|
21984
22188
|
// src/phoneAgentProductionSmoke.ts
|
|
21985
|
-
import { Elysia as
|
|
22189
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
21986
22190
|
var defaultRequirements = [
|
|
21987
22191
|
"media-started",
|
|
21988
22192
|
"transcript",
|
|
@@ -21990,7 +22194,7 @@ var defaultRequirements = [
|
|
|
21990
22194
|
"lifecycle-outcome",
|
|
21991
22195
|
"no-session-error"
|
|
21992
22196
|
];
|
|
21993
|
-
var
|
|
22197
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21994
22198
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
21995
22199
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
21996
22200
|
const value = event.payload[key];
|
|
@@ -22099,10 +22303,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
22099
22303
|
});
|
|
22100
22304
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
22101
22305
|
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>${
|
|
22306
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml38(issue.requirement)}</strong>: ${escapeHtml38(issue.message)}</li>`).join("");
|
|
22307
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml38(outcome)}</span>`).join("");
|
|
22308
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml38(requirement)}</span>`).join("");
|
|
22309
|
+
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
22310
|
};
|
|
22107
22311
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
22108
22312
|
query,
|
|
@@ -22125,7 +22329,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
22125
22329
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
22126
22330
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
22127
22331
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
22128
|
-
const routes = new
|
|
22332
|
+
const routes = new Elysia39({
|
|
22129
22333
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
22130
22334
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
22131
22335
|
if (htmlPath) {
|
|
@@ -22168,7 +22372,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
22168
22372
|
"completed",
|
|
22169
22373
|
"failed"
|
|
22170
22374
|
];
|
|
22171
|
-
var
|
|
22375
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22172
22376
|
var loadRouteJson = async (input) => {
|
|
22173
22377
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
22174
22378
|
headers: {
|
|
@@ -22406,10 +22610,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
22406
22610
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
22407
22611
|
const urls = entry?.setup.urls;
|
|
22408
22612
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
22409
|
-
return `<tr><td>${
|
|
22613
|
+
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
22614
|
}).join("");
|
|
22411
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
22412
|
-
const snippet =
|
|
22615
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml39(stage)}</code></li>`).join("");
|
|
22616
|
+
const snippet = escapeHtml39(`const phoneAgent = createVoicePhoneAgent({
|
|
22413
22617
|
carriers: [
|
|
22414
22618
|
{
|
|
22415
22619
|
provider: 'twilio',
|
|
@@ -22443,11 +22647,11 @@ app.use(
|
|
|
22443
22647
|
);`);
|
|
22444
22648
|
const checklist = report.carriers.map((carrier) => {
|
|
22445
22649
|
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>${
|
|
22650
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml39(issue)}</li>`).join("") ?? "";
|
|
22651
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml39(step)}</li>`).join("") ?? "";
|
|
22652
|
+
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
22653
|
}).join("");
|
|
22450
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22654
|
+
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
22655
|
};
|
|
22452
22656
|
var createVoicePhoneAgent = (options) => {
|
|
22453
22657
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -22456,7 +22660,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
22456
22660
|
setupPath: resolveSetupPath(carrier),
|
|
22457
22661
|
smokePath: resolveSmokePath(carrier)
|
|
22458
22662
|
}));
|
|
22459
|
-
const app = new
|
|
22663
|
+
const app = new Elysia40({
|
|
22460
22664
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
22461
22665
|
});
|
|
22462
22666
|
for (const carrier of options.carriers) {
|
|
@@ -24590,8 +24794,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24590
24794
|
};
|
|
24591
24795
|
};
|
|
24592
24796
|
// src/providerCapabilities.ts
|
|
24593
|
-
import { Elysia as
|
|
24594
|
-
var
|
|
24797
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
24798
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24595
24799
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
24596
24800
|
configured: true,
|
|
24597
24801
|
features: options.features?.[provider],
|
|
@@ -24654,27 +24858,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
24654
24858
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
24655
24859
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
24656
24860
|
const cards = report.capabilities.map((capability) => {
|
|
24657
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
24658
|
-
return `<article class="card ${
|
|
24861
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml40(feature)}</span>`).join("");
|
|
24862
|
+
return `<article class="card ${escapeHtml40(capability.status)}">
|
|
24659
24863
|
<div class="card-header">
|
|
24660
24864
|
<div>
|
|
24661
|
-
<p class="eyebrow">${
|
|
24662
|
-
<h2>${
|
|
24865
|
+
<p class="eyebrow">${escapeHtml40(capability.kind)}</p>
|
|
24866
|
+
<h2>${escapeHtml40(capability.label ?? capability.provider)}</h2>
|
|
24663
24867
|
</div>
|
|
24664
|
-
<strong>${
|
|
24868
|
+
<strong>${escapeHtml40(capability.status)}</strong>
|
|
24665
24869
|
</div>
|
|
24666
|
-
${capability.description ? `<p>${
|
|
24870
|
+
${capability.description ? `<p>${escapeHtml40(capability.description)}</p>` : ""}
|
|
24667
24871
|
<dl>
|
|
24668
24872
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
24669
24873
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
24670
|
-
<div><dt>Model</dt><dd>${
|
|
24874
|
+
<div><dt>Model</dt><dd>${escapeHtml40(capability.model ?? "default")}</dd></div>
|
|
24671
24875
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
24672
24876
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
24673
24877
|
</dl>
|
|
24674
24878
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
24675
24879
|
</article>`;
|
|
24676
24880
|
}).join("");
|
|
24677
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24881
|
+
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
24882
|
};
|
|
24679
24883
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
24680
24884
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -24691,7 +24895,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
24691
24895
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
24692
24896
|
const path = options.path ?? "/api/provider-capabilities";
|
|
24693
24897
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
24694
|
-
const routes = new
|
|
24898
|
+
const routes = new Elysia41({
|
|
24695
24899
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
24696
24900
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
24697
24901
|
if (htmlPath) {
|
|
@@ -24700,7 +24904,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
24700
24904
|
return routes;
|
|
24701
24905
|
};
|
|
24702
24906
|
// src/providerOrchestration.ts
|
|
24703
|
-
import { Elysia as
|
|
24907
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
24704
24908
|
var defaultRequirement = {
|
|
24705
24909
|
minProviders: 1,
|
|
24706
24910
|
requireBudgetPolicy: false,
|
|
@@ -24708,12 +24912,12 @@ var defaultRequirement = {
|
|
|
24708
24912
|
requireFallback: false,
|
|
24709
24913
|
requireTimeoutBudget: false
|
|
24710
24914
|
};
|
|
24711
|
-
var
|
|
24915
|
+
var statusRank3 = {
|
|
24712
24916
|
pass: 0,
|
|
24713
24917
|
warn: 1,
|
|
24714
24918
|
fail: 2
|
|
24715
24919
|
};
|
|
24716
|
-
var
|
|
24920
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24717
24921
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24718
24922
|
var uniqueSorted6 = (values) => [
|
|
24719
24923
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -24724,7 +24928,7 @@ var surfaceProviderNames = (surface) => uniqueSorted6([
|
|
|
24724
24928
|
...isProviderList(surface.fallback) ? surface.fallback : [],
|
|
24725
24929
|
...isProviderList(surface.allowProviders) ? surface.allowProviders : []
|
|
24726
24930
|
]);
|
|
24727
|
-
var surfaceStatus = (issues) => issues.reduce((status, issue) =>
|
|
24931
|
+
var surfaceStatus = (issues) => issues.reduce((status, issue) => statusRank3[issue.status] > statusRank3[status] ? issue.status : status, "pass");
|
|
24728
24932
|
var resolvedRequirement = (surface, options) => ({
|
|
24729
24933
|
...defaultRequirement,
|
|
24730
24934
|
...options.defaultRequirement ?? {},
|
|
@@ -24856,27 +25060,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
24856
25060
|
};
|
|
24857
25061
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
24858
25062
|
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">${
|
|
25063
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml41(surface.status)}">
|
|
25064
|
+
<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
25065
|
<dl>
|
|
24862
|
-
<div><dt>Providers</dt><dd>${
|
|
24863
|
-
<div><dt>Fallback</dt><dd>${
|
|
25066
|
+
<div><dt>Providers</dt><dd>${escapeHtml41(surface.providers.join(", ") || "none")}</dd></div>
|
|
25067
|
+
<div><dt>Fallback</dt><dd>${escapeHtml41(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
24864
25068
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
24865
25069
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
24866
25070
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
24867
25071
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
24868
25072
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
24869
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
25073
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml41(surface.fallbackMode || "default")}</dd></div>
|
|
24870
25074
|
</dl>
|
|
24871
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
25075
|
+
${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
25076
|
</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>${
|
|
25077
|
+
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
25078
|
};
|
|
24875
25079
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
24876
25080
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
24877
25081
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
24878
25082
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
24879
|
-
const routes = new
|
|
25083
|
+
const routes = new Elysia42({
|
|
24880
25084
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
24881
25085
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
24882
25086
|
if (htmlPath) {
|
|
@@ -25047,7 +25251,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
25047
25251
|
return report;
|
|
25048
25252
|
};
|
|
25049
25253
|
// src/providerSlo.ts
|
|
25050
|
-
import { Elysia as
|
|
25254
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
25051
25255
|
var defaultThresholds = {
|
|
25052
25256
|
llm: {
|
|
25053
25257
|
maxAverageElapsedMs: 2500,
|
|
@@ -25075,12 +25279,12 @@ var defaultThresholds = {
|
|
|
25075
25279
|
}
|
|
25076
25280
|
};
|
|
25077
25281
|
var providerKinds = ["llm", "stt", "tts"];
|
|
25078
|
-
var
|
|
25282
|
+
var statusRank4 = {
|
|
25079
25283
|
pass: 0,
|
|
25080
25284
|
warn: 1,
|
|
25081
25285
|
fail: 2
|
|
25082
25286
|
};
|
|
25083
|
-
var
|
|
25287
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25084
25288
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
25085
25289
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
25086
25290
|
var uniqueSorted7 = (values) => [
|
|
@@ -25272,7 +25476,7 @@ var evaluateVoiceProviderSloEvidence = (report, input = {}) => {
|
|
|
25272
25476
|
const timeouts = kindReports.reduce((total, kind) => total + kind.timeouts, 0);
|
|
25273
25477
|
const unresolvedErrors = kindReports.reduce((total, kind) => total + kind.unresolvedErrors, 0);
|
|
25274
25478
|
const maxStatus = input.maxStatus ?? "pass";
|
|
25275
|
-
if (
|
|
25479
|
+
if (statusRank4[report.status] > statusRank4[maxStatus]) {
|
|
25276
25480
|
issues.push(`Expected provider SLO status at most ${maxStatus}, found ${report.status}.`);
|
|
25277
25481
|
}
|
|
25278
25482
|
if (input.minEvents !== undefined && report.events < input.minEvents) {
|
|
@@ -25376,11 +25580,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25376
25580
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25377
25581
|
const kindCards = providerKinds.map((kind) => {
|
|
25378
25582
|
const kindReport = report.kinds[kind];
|
|
25379
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
25583
|
+
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
25584
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25381
|
-
return `<article class="${
|
|
25585
|
+
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
25586
|
}).join("");
|
|
25383
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
25587
|
+
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
25588
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25385
25589
|
store: runtimeStorage.traces,
|
|
25386
25590
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25390,7 +25594,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25390
25594
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25391
25595
|
}
|
|
25392
25596
|
})`;
|
|
25393
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25597
|
+
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
25598
|
};
|
|
25395
25599
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25396
25600
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25401,7 +25605,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25401
25605
|
...options.headers ?? {}
|
|
25402
25606
|
};
|
|
25403
25607
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25404
|
-
const app = new
|
|
25608
|
+
const app = new Elysia43({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25405
25609
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25406
25610
|
if (markdownPath !== false) {
|
|
25407
25611
|
app.get(markdownPath, async () => {
|
|
@@ -25431,10 +25635,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25431
25635
|
return app;
|
|
25432
25636
|
};
|
|
25433
25637
|
// src/productionReadiness.ts
|
|
25434
|
-
import { Elysia as
|
|
25638
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
25435
25639
|
|
|
25436
25640
|
// src/telephony/security.ts
|
|
25437
|
-
import { Elysia as
|
|
25641
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25438
25642
|
|
|
25439
25643
|
// src/postgresStore.ts
|
|
25440
25644
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -26172,7 +26376,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
26172
26376
|
};
|
|
26173
26377
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
26174
26378
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
26175
|
-
return new
|
|
26379
|
+
return new Elysia44({
|
|
26176
26380
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
26177
26381
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
26178
26382
|
};
|
|
@@ -26229,8 +26433,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
26229
26433
|
};
|
|
26230
26434
|
|
|
26231
26435
|
// src/opsRecovery.ts
|
|
26232
|
-
import { Elysia as
|
|
26233
|
-
var
|
|
26436
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
26437
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26234
26438
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26235
26439
|
var hrefForSession = (value, sessionId) => {
|
|
26236
26440
|
if (typeof value === "function") {
|
|
@@ -26246,7 +26450,7 @@ var hrefForSession = (value, sessionId) => {
|
|
|
26246
26450
|
return value;
|
|
26247
26451
|
};
|
|
26248
26452
|
var operationsRecordHrefForSession = (links, sessionId) => hrefForSession(links?.operationsRecords, sessionId);
|
|
26249
|
-
var
|
|
26453
|
+
var rollupStatus3 = (issues) => issues.some((issue) => issue.severity === "fail") ? "fail" : issues.some((issue) => issue.severity === "warn") ? "warn" : "pass";
|
|
26250
26454
|
var providerUnresolved = (provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed";
|
|
26251
26455
|
var collectFailedSessions = (events, limit, links) => events.filter((event) => {
|
|
26252
26456
|
if (event.type !== "session.error") {
|
|
@@ -26394,7 +26598,7 @@ var buildVoiceOpsRecoveryReport = async (options = {}) => {
|
|
|
26394
26598
|
recoveredFallbacks: providers.reduce((total, provider) => total + provider.fallbackCount, 0),
|
|
26395
26599
|
unresolvedFailures: unresolvedProviders.length
|
|
26396
26600
|
},
|
|
26397
|
-
status:
|
|
26601
|
+
status: rollupStatus3(issues),
|
|
26398
26602
|
traceDeliveries
|
|
26399
26603
|
};
|
|
26400
26604
|
};
|
|
@@ -26444,19 +26648,19 @@ ${failedSessions || "None."}
|
|
|
26444
26648
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26445
26649
|
`;
|
|
26446
26650
|
};
|
|
26447
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
26651
|
+
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
26652
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26449
26653
|
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>${
|
|
26654
|
+
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("");
|
|
26655
|
+
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("");
|
|
26656
|
+
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("");
|
|
26657
|
+
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
26658
|
};
|
|
26455
26659
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26456
26660
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26457
26661
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26458
26662
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26459
|
-
const routes = new
|
|
26663
|
+
const routes = new Elysia45({
|
|
26460
26664
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26461
26665
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26462
26666
|
if (htmlPath) {
|
|
@@ -26486,18 +26690,18 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26486
26690
|
};
|
|
26487
26691
|
|
|
26488
26692
|
// src/observabilityExport.ts
|
|
26489
|
-
import { Elysia as
|
|
26693
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
26490
26694
|
import { Database as Database4 } from "bun:sqlite";
|
|
26491
26695
|
import { createHash } from "crypto";
|
|
26492
26696
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26493
26697
|
import { join as join3 } from "path";
|
|
26494
26698
|
|
|
26495
26699
|
// src/operationsRecord.ts
|
|
26496
|
-
import { Elysia as
|
|
26700
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
26497
26701
|
|
|
26498
26702
|
// src/traceTimeline.ts
|
|
26499
|
-
import { Elysia as
|
|
26500
|
-
var
|
|
26703
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26704
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26501
26705
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26502
26706
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26503
26707
|
var firstString3 = (payload, keys) => {
|
|
@@ -26680,17 +26884,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
26680
26884
|
};
|
|
26681
26885
|
};
|
|
26682
26886
|
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>${
|
|
26887
|
+
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
26888
|
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>${
|
|
26889
|
+
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("");
|
|
26890
|
+
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>";
|
|
26891
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml44(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
26892
|
+
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
26893
|
};
|
|
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="${
|
|
26894
|
+
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
26895
|
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
26896
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
26693
|
-
const snippet =
|
|
26897
|
+
const snippet = escapeHtml44(`const traceStore = createVoiceTraceSinkStore({
|
|
26694
26898
|
store: runtimeStorage.traces,
|
|
26695
26899
|
sinks: [
|
|
26696
26900
|
createVoiceTraceHTTPSink({
|
|
@@ -26716,13 +26920,13 @@ app.use(
|
|
|
26716
26920
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
26717
26921
|
})
|
|
26718
26922
|
);`);
|
|
26719
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26923
|
+
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
26924
|
};
|
|
26721
26925
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
26722
26926
|
const path = options.path ?? "/api/voice-traces";
|
|
26723
26927
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
26724
26928
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
26725
|
-
const routes = new
|
|
26929
|
+
const routes = new Elysia46({
|
|
26726
26930
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
26727
26931
|
});
|
|
26728
26932
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -27151,7 +27355,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
27151
27355
|
}
|
|
27152
27356
|
return report;
|
|
27153
27357
|
};
|
|
27154
|
-
var
|
|
27358
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27155
27359
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27156
27360
|
var outcomeLabels = (outcome) => [
|
|
27157
27361
|
outcome.complete ? "complete" : undefined,
|
|
@@ -27231,20 +27435,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
27231
27435
|
`);
|
|
27232
27436
|
};
|
|
27233
27437
|
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>${
|
|
27438
|
+
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>';
|
|
27439
|
+
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>";
|
|
27440
|
+
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
27441
|
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>${
|
|
27442
|
+
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>";
|
|
27443
|
+
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>";
|
|
27444
|
+
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>";
|
|
27445
|
+
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>";
|
|
27446
|
+
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
27447
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
27244
27448
|
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 ${
|
|
27449
|
+
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
27450
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
27247
|
-
const snippet =
|
|
27451
|
+
const snippet = escapeHtml45(`app.use(
|
|
27248
27452
|
createVoiceOperationsRecordRoutes({
|
|
27249
27453
|
audit: auditStore,
|
|
27250
27454
|
integrationEvents: opsEvents,
|
|
@@ -27258,16 +27462,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
27258
27462
|
tasks: opsTasks
|
|
27259
27463
|
})
|
|
27260
27464
|
);`);
|
|
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>${
|
|
27465
|
+
const incidentMarkdown = escapeHtml45(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
27466
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml45(options.incidentHref)}">Download incident.md</a>` : "";
|
|
27467
|
+
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
27468
|
};
|
|
27265
27469
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
27266
27470
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
27267
27471
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
27268
27472
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
27269
27473
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
27270
|
-
const routes = new
|
|
27474
|
+
const routes = new Elysia47({
|
|
27271
27475
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
27272
27476
|
});
|
|
27273
27477
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -27918,7 +28122,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
27918
28122
|
...options.headers ?? {}
|
|
27919
28123
|
};
|
|
27920
28124
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
27921
|
-
const app = new
|
|
28125
|
+
const app = new Elysia48({
|
|
27922
28126
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
27923
28127
|
});
|
|
27924
28128
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28727,7 +28931,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28727
28931
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
28728
28932
|
}
|
|
28729
28933
|
});
|
|
28730
|
-
const app = new
|
|
28934
|
+
const app = new Elysia48({
|
|
28731
28935
|
name: options.name ?? "absolute-voice-observability-export"
|
|
28732
28936
|
});
|
|
28733
28937
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28804,8 +29008,8 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28804
29008
|
};
|
|
28805
29009
|
|
|
28806
29010
|
// src/productionReadiness.ts
|
|
28807
|
-
var
|
|
28808
|
-
var
|
|
29011
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29012
|
+
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
28809
29013
|
var readinessGateCodes = {
|
|
28810
29014
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
28811
29015
|
"Audit evidence": "voice.readiness.audit_evidence",
|
|
@@ -30202,7 +30406,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30202
30406
|
profile: options.profile || undefined,
|
|
30203
30407
|
operationsRecords,
|
|
30204
30408
|
proofSources,
|
|
30205
|
-
status:
|
|
30409
|
+
status: rollupStatus4(checks),
|
|
30206
30410
|
summary: {
|
|
30207
30411
|
agentSquadContracts: agentSquadContractSummary,
|
|
30208
30412
|
audit,
|
|
@@ -30259,25 +30463,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30259
30463
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
30260
30464
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
30261
30465
|
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>${
|
|
30466
|
+
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>` : "";
|
|
30467
|
+
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
30468
|
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 ${
|
|
30469
|
+
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("");
|
|
30470
|
+
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>` : "";
|
|
30471
|
+
return `<article class="check ${escapeHtml46(check.status)}">
|
|
30268
30472
|
<div>
|
|
30269
|
-
<span>${
|
|
30270
|
-
<h2>${
|
|
30271
|
-
${check.detail ? `<p>${
|
|
30473
|
+
<span>${escapeHtml46(check.status.toUpperCase())}</span>
|
|
30474
|
+
<h2>${escapeHtml46(check.label)}</h2>
|
|
30475
|
+
${check.detail ? `<p>${escapeHtml46(check.detail)}</p>` : ""}
|
|
30272
30476
|
${explanation}
|
|
30273
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
30477
|
+
${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
30478
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
30275
30479
|
</div>
|
|
30276
|
-
<strong>${
|
|
30277
|
-
${check.href ? `<a href="${
|
|
30480
|
+
<strong>${escapeHtml46(String(check.value ?? check.status))}</strong>
|
|
30481
|
+
${check.href ? `<a href="${escapeHtml46(check.href)}">Open surface</a>` : ""}
|
|
30278
30482
|
</article>`;
|
|
30279
30483
|
}).join("");
|
|
30280
|
-
const snippet =
|
|
30484
|
+
const snippet = escapeHtml46(`createVoiceProductionReadinessRoutes({
|
|
30281
30485
|
htmlPath: '/production-readiness',
|
|
30282
30486
|
path: '/api/production-readiness',
|
|
30283
30487
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -30293,13 +30497,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
30293
30497
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
30294
30498
|
store: traceStore
|
|
30295
30499
|
});`);
|
|
30296
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30500
|
+
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
30501
|
};
|
|
30298
30502
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
30299
30503
|
const path = options.path ?? "/api/production-readiness";
|
|
30300
30504
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
30301
30505
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
30302
|
-
const routes = new
|
|
30506
|
+
const routes = new Elysia49({
|
|
30303
30507
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
30304
30508
|
});
|
|
30305
30509
|
const resolveOptions = async (input) => {
|
|
@@ -30347,10 +30551,10 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30347
30551
|
return routes;
|
|
30348
30552
|
};
|
|
30349
30553
|
// src/voiceMonitoring.ts
|
|
30350
|
-
import { Elysia as
|
|
30351
|
-
var
|
|
30554
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
30555
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30352
30556
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30353
|
-
var
|
|
30557
|
+
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30354
30558
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
30355
30559
|
const issues = new Map(initial.map((issue) => [issue.id, { ...issue }]));
|
|
30356
30560
|
return {
|
|
@@ -30432,7 +30636,7 @@ var buildVoiceMonitorRunReport = async (options) => {
|
|
|
30432
30636
|
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
30433
30637
|
issues,
|
|
30434
30638
|
runs,
|
|
30435
|
-
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 ||
|
|
30639
|
+
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 || rollupStatus5(runs) === "warn" ? "warn" : rollupStatus5(runs),
|
|
30436
30640
|
summary: {
|
|
30437
30641
|
acknowledged: issues.filter((issue) => issue.status === "acknowledged").length,
|
|
30438
30642
|
criticalOpen,
|
|
@@ -30601,14 +30805,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
30601
30805
|
};
|
|
30602
30806
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
30603
30807
|
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 =
|
|
30808
|
+
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("");
|
|
30809
|
+
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("");
|
|
30810
|
+
const snippet = escapeHtml47(`app.use(createVoiceMonitorRoutes({
|
|
30607
30811
|
evidence,
|
|
30608
30812
|
issueStore,
|
|
30609
30813
|
monitors: [defineVoiceMonitor(...)]
|
|
30610
30814
|
}));`);
|
|
30611
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30815
|
+
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
30816
|
};
|
|
30613
30817
|
var actorFromRequest = async (request) => {
|
|
30614
30818
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -30632,7 +30836,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30632
30836
|
monitors: options.monitors,
|
|
30633
30837
|
now: options.now
|
|
30634
30838
|
});
|
|
30635
|
-
const routes = new
|
|
30839
|
+
const routes = new Elysia50({
|
|
30636
30840
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
30637
30841
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
30638
30842
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -30679,7 +30883,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30679
30883
|
};
|
|
30680
30884
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
30681
30885
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
30682
|
-
return new
|
|
30886
|
+
return new Elysia50({
|
|
30683
30887
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
30684
30888
|
}).get(path, () => ({
|
|
30685
30889
|
isRunning: options.runner.isRunning()
|
|
@@ -31055,8 +31259,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
31055
31259
|
};
|
|
31056
31260
|
};
|
|
31057
31261
|
// src/providerStackRecommendations.ts
|
|
31058
|
-
import { Elysia as
|
|
31059
|
-
var
|
|
31262
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
31263
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31060
31264
|
var profileProviderPriorities = {
|
|
31061
31265
|
"meeting-recorder": {
|
|
31062
31266
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31108,7 +31312,7 @@ var profileRequiredCapabilities = {
|
|
|
31108
31312
|
tts: ["streaming speech", "barge-in friendly"]
|
|
31109
31313
|
}
|
|
31110
31314
|
};
|
|
31111
|
-
var
|
|
31315
|
+
var defaultProviderEnv2 = {
|
|
31112
31316
|
anthropic: ["ANTHROPIC_API_KEY"],
|
|
31113
31317
|
assemblyai: ["ASSEMBLYAI_API_KEY"],
|
|
31114
31318
|
deepgram: ["DEEPGRAM_API_KEY"],
|
|
@@ -31168,12 +31372,12 @@ var recommendVoiceProviderStack = (input) => {
|
|
|
31168
31372
|
};
|
|
31169
31373
|
};
|
|
31170
31374
|
var rollupContractStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
31171
|
-
var
|
|
31375
|
+
var statusRank5 = {
|
|
31172
31376
|
pass: 0,
|
|
31173
31377
|
warn: 1,
|
|
31174
31378
|
fail: 2
|
|
31175
31379
|
};
|
|
31176
|
-
var
|
|
31380
|
+
var statusExceeds2 = (actual, max) => statusRank5[actual] > statusRank5[max];
|
|
31177
31381
|
var buildVoiceProviderContractMatrix = (input) => {
|
|
31178
31382
|
const rows = input.contracts.map((contract) => {
|
|
31179
31383
|
const configured = contract.configured !== false;
|
|
@@ -31286,7 +31490,7 @@ var evaluateVoiceProviderContractMatrixEvidence = (report, input = {}) => {
|
|
|
31286
31490
|
const selectedKinds = [
|
|
31287
31491
|
...new Set(report.rows.filter((row) => row.selected).map((row) => row.kind))
|
|
31288
31492
|
].sort();
|
|
31289
|
-
if (
|
|
31493
|
+
if (statusExceeds2(report.status, maxStatus)) {
|
|
31290
31494
|
issues.push(`Expected provider contract matrix status at most ${maxStatus}, found ${report.status}.`);
|
|
31291
31495
|
}
|
|
31292
31496
|
if (report.failed > maxFailed) {
|
|
@@ -31348,11 +31552,11 @@ var createVoiceProviderContractMatrixPreset = (profile, options) => {
|
|
|
31348
31552
|
const contracts = ["llm", "stt", "tts"].flatMap((kind) => {
|
|
31349
31553
|
const providers = options.providers[kind] ?? [];
|
|
31350
31554
|
return providers.map((provider) => {
|
|
31351
|
-
const configured = options.configured?.[provider] ?? (
|
|
31555
|
+
const configured = options.configured?.[provider] ?? (defaultProviderEnv2[provider]?.length ? defaultProviderEnv2[provider].every((name) => options.env?.[name]) : true);
|
|
31352
31556
|
const fallbackProviders = options.fallbackProviders?.[kind] ?? providers.filter((candidate) => candidate !== provider);
|
|
31353
31557
|
const requiredCapabilities = profileRequiredCapabilities[profile][kind];
|
|
31354
31558
|
const capabilities = options.capabilities?.[kind]?.[provider] ?? defaultProviderCapabilities[provider] ?? [];
|
|
31355
|
-
const requiredEnv =
|
|
31559
|
+
const requiredEnv = defaultProviderEnv2[provider] ?? [];
|
|
31356
31560
|
return {
|
|
31357
31561
|
capabilities,
|
|
31358
31562
|
configured,
|
|
@@ -31375,17 +31579,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31375
31579
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31376
31580
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31377
31581
|
const rows = report.rows.map((row) => {
|
|
31378
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31379
|
-
return `<article class="row ${
|
|
31582
|
+
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("");
|
|
31583
|
+
return `<article class="row ${escapeHtml48(row.status)}">
|
|
31380
31584
|
<div>
|
|
31381
|
-
<p class="eyebrow">${
|
|
31382
|
-
<h2>${
|
|
31383
|
-
<p class="status ${
|
|
31585
|
+
<p class="eyebrow">${escapeHtml48(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
31586
|
+
<h2>${escapeHtml48(row.provider)}</h2>
|
|
31587
|
+
<p class="status ${escapeHtml48(row.status)}">${escapeHtml48(row.status.toUpperCase())}</p>
|
|
31384
31588
|
</div>
|
|
31385
31589
|
<ul>${checks}</ul>
|
|
31386
31590
|
</article>`;
|
|
31387
31591
|
}).join("");
|
|
31388
|
-
const snippet =
|
|
31592
|
+
const snippet = escapeHtml48(`const providerContracts = () =>
|
|
31389
31593
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31390
31594
|
env: process.env,
|
|
31391
31595
|
providers: {
|
|
@@ -31406,7 +31610,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31406
31610
|
providerContractMatrix: () =>
|
|
31407
31611
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31408
31612
|
});`);
|
|
31409
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31613
|
+
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
31614
|
};
|
|
31411
31615
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31412
31616
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31421,7 +31625,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31421
31625
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31422
31626
|
const path = options.path ?? "/api/provider-contracts";
|
|
31423
31627
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31424
|
-
const routes = new
|
|
31628
|
+
const routes = new Elysia51({
|
|
31425
31629
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31426
31630
|
});
|
|
31427
31631
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -31488,7 +31692,7 @@ var evaluateVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31488
31692
|
const providers = [
|
|
31489
31693
|
...new Set(report.gaps.map((gap) => gap.provider).filter((provider) => provider !== undefined))
|
|
31490
31694
|
].sort();
|
|
31491
|
-
if (
|
|
31695
|
+
if (statusExceeds2(report.status, maxStatus)) {
|
|
31492
31696
|
issues.push(`Expected provider stack status at most ${maxStatus}, found ${report.status}.`);
|
|
31493
31697
|
}
|
|
31494
31698
|
if (report.missing > maxMissing) {
|
|
@@ -31539,7 +31743,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31539
31743
|
return assertion;
|
|
31540
31744
|
};
|
|
31541
31745
|
// src/opsConsoleRoutes.ts
|
|
31542
|
-
import { Elysia as
|
|
31746
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
31543
31747
|
var DEFAULT_LINKS = [
|
|
31544
31748
|
{
|
|
31545
31749
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -31574,7 +31778,7 @@ var DEFAULT_LINKS = [
|
|
|
31574
31778
|
label: "Handoffs"
|
|
31575
31779
|
}
|
|
31576
31780
|
];
|
|
31577
|
-
var
|
|
31781
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31578
31782
|
var countProviderStatuses = (providers) => {
|
|
31579
31783
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
31580
31784
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -31643,20 +31847,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
31643
31847
|
trace
|
|
31644
31848
|
};
|
|
31645
31849
|
};
|
|
31646
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
31850
|
+
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
31851
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
31648
31852
|
const links = report.links.map((link) => `<article class="surface">
|
|
31649
|
-
<div><h2>${
|
|
31650
|
-
<p><a href="${
|
|
31853
|
+
<div><h2>${escapeHtml49(link.label)}</h2>${link.description ? `<p>${escapeHtml49(link.description)}</p>` : ""}</div>
|
|
31854
|
+
<p><a href="${escapeHtml49(link.href)}">Open ${escapeHtml49(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml49(link.statusHref)}">Status</a>` : ""}</p>
|
|
31651
31855
|
</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>${
|
|
31856
|
+
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>';
|
|
31857
|
+
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
31858
|
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>${
|
|
31859
|
+
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
31860
|
};
|
|
31657
31861
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
31658
31862
|
const path = options.path ?? "/ops-console";
|
|
31659
|
-
const routes = new
|
|
31863
|
+
const routes = new Elysia52({
|
|
31660
31864
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
31661
31865
|
});
|
|
31662
31866
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -31673,7 +31877,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
31673
31877
|
return routes;
|
|
31674
31878
|
};
|
|
31675
31879
|
// src/incidentBundle.ts
|
|
31676
|
-
import { Elysia as
|
|
31880
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31677
31881
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
31678
31882
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
31679
31883
|
return false;
|
|
@@ -31874,7 +32078,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
31874
32078
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
31875
32079
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
31876
32080
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
31877
|
-
const routes = new
|
|
32081
|
+
const routes = new Elysia53({
|
|
31878
32082
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
31879
32083
|
});
|
|
31880
32084
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -32075,19 +32279,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
32075
32279
|
};
|
|
32076
32280
|
};
|
|
32077
32281
|
// src/opsStatusRoutes.ts
|
|
32078
|
-
import { Elysia as
|
|
32079
|
-
var
|
|
32282
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
32283
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32080
32284
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
32081
32285
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
32082
32286
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
32083
32287
|
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 ${
|
|
32288
|
+
return `<article class="surface ${escapeHtml50(surface.status)}"><span>${escapeHtml50(surface.status.toUpperCase())}</span><h2>${escapeHtml50(key)}</h2><strong>${escapeHtml50(value)}</strong></article>`;
|
|
32085
32289
|
}).join("");
|
|
32086
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32290
|
+
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
32291
|
};
|
|
32088
32292
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
32089
32293
|
const path = options.path ?? "/api/voice/ops-status";
|
|
32090
|
-
const routes = new
|
|
32294
|
+
const routes = new Elysia54({
|
|
32091
32295
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
32092
32296
|
});
|
|
32093
32297
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -32520,8 +32724,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
32520
32724
|
};
|
|
32521
32725
|
};
|
|
32522
32726
|
// src/traceDeliveryRoutes.ts
|
|
32523
|
-
import { Elysia as
|
|
32524
|
-
var
|
|
32727
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32728
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32525
32729
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
32526
32730
|
var getNumber12 = (value) => {
|
|
32527
32731
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -32602,14 +32806,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
32602
32806
|
if (entries.length === 0) {
|
|
32603
32807
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
32604
32808
|
}
|
|
32605
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
32809
|
+
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
32810
|
};
|
|
32607
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
32811
|
+
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
32812
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
32609
32813
|
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>${
|
|
32814
|
+
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>`;
|
|
32815
|
+
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("");
|
|
32816
|
+
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
32817
|
};
|
|
32614
32818
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
32615
32819
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32629,7 +32833,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
32629
32833
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
32630
32834
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
32631
32835
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
32632
|
-
const routes = new
|
|
32836
|
+
const routes = new Elysia55({
|
|
32633
32837
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
32634
32838
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
32635
32839
|
if (htmlPath !== false) {
|
|
@@ -32726,7 +32930,7 @@ var createVoiceMemoryStore = () => {
|
|
|
32726
32930
|
return { get, getOrCreate, list, remove, set };
|
|
32727
32931
|
};
|
|
32728
32932
|
// src/opsWebhook.ts
|
|
32729
|
-
import { Elysia as
|
|
32933
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32730
32934
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
32731
32935
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
32732
32936
|
const encoder = new TextEncoder;
|
|
@@ -32856,7 +33060,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
32856
33060
|
};
|
|
32857
33061
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
32858
33062
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
32859
|
-
return new
|
|
33063
|
+
return new Elysia56().post(path, async ({ body, request, set }) => {
|
|
32860
33064
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
32861
33065
|
if (options.signingSecret) {
|
|
32862
33066
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -33311,7 +33515,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
33311
33515
|
};
|
|
33312
33516
|
};
|
|
33313
33517
|
// src/postCallAnalysis.ts
|
|
33314
|
-
import { Elysia as
|
|
33518
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
33315
33519
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
33316
33520
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
33317
33521
|
var getPathValue3 = (source, path) => {
|
|
@@ -33490,7 +33694,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
33490
33694
|
};
|
|
33491
33695
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
33492
33696
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
33493
|
-
const routes = new
|
|
33697
|
+
const routes = new Elysia57({
|
|
33494
33698
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
33495
33699
|
});
|
|
33496
33700
|
routes.get(path, async ({ query }) => {
|
|
@@ -33515,7 +33719,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
33515
33719
|
return routes;
|
|
33516
33720
|
};
|
|
33517
33721
|
// src/guardrails.ts
|
|
33518
|
-
import { Elysia as
|
|
33722
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
33519
33723
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
33520
33724
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
33521
33725
|
var matchesRule = async (rule, input) => {
|
|
@@ -33817,7 +34021,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
33817
34021
|
};
|
|
33818
34022
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
33819
34023
|
const path = options.path ?? "/api/voice/guardrails";
|
|
33820
|
-
const routes = new
|
|
34024
|
+
const routes = new Elysia58({
|
|
33821
34025
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
33822
34026
|
});
|
|
33823
34027
|
routes.all(path, async ({ request }) => {
|
|
@@ -34341,6 +34545,7 @@ export {
|
|
|
34341
34545
|
renderVoiceScenarioEvalHTML,
|
|
34342
34546
|
renderVoiceResilienceHTML,
|
|
34343
34547
|
renderVoiceReconnectContractHTML,
|
|
34548
|
+
renderVoiceRealtimeProviderContractHTML,
|
|
34344
34549
|
renderVoiceRealtimeChannelMarkdown,
|
|
34345
34550
|
renderVoiceRealtimeChannelHTML,
|
|
34346
34551
|
renderVoiceQualityHTML,
|
|
@@ -34438,6 +34643,7 @@ export {
|
|
|
34438
34643
|
evaluateVoiceTelephonyWebhookNormalizationEvidence,
|
|
34439
34644
|
evaluateVoiceTelephonyContract,
|
|
34440
34645
|
evaluateVoiceSimulationSuiteEvidence,
|
|
34646
|
+
evaluateVoiceRealtimeProviderContractEvidence,
|
|
34441
34647
|
evaluateVoiceRealtimeChannelEvidence,
|
|
34442
34648
|
evaluateVoiceQuality,
|
|
34443
34649
|
evaluateVoiceProviderStackGaps,
|
|
@@ -34568,6 +34774,7 @@ export {
|
|
|
34568
34774
|
createVoiceRedisPlivoWebhookNonceStore,
|
|
34569
34775
|
createVoiceRedisIdempotencyStore,
|
|
34570
34776
|
createVoiceReconnectContractRoutes,
|
|
34777
|
+
createVoiceRealtimeProviderContractRoutes,
|
|
34571
34778
|
createVoiceRealtimeChannelRoutes,
|
|
34572
34779
|
createVoiceReadinessProfile,
|
|
34573
34780
|
createVoiceQualityRoutes,
|
|
@@ -34772,6 +34979,7 @@ export {
|
|
|
34772
34979
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
34773
34980
|
buildVoiceSloReadinessThresholdReport,
|
|
34774
34981
|
buildVoiceSloCalibrationReport,
|
|
34982
|
+
buildVoiceRealtimeProviderContractMatrix,
|
|
34775
34983
|
buildVoiceRealtimeChannelRuntimeSamplesFromTrace,
|
|
34776
34984
|
buildVoiceRealtimeChannelReport,
|
|
34777
34985
|
buildVoiceProviderSloReport,
|
|
@@ -34817,6 +35025,7 @@ export {
|
|
|
34817
35025
|
assertVoiceTelephonyWebhookNormalizationEvidence,
|
|
34818
35026
|
assertVoiceSloCalibration,
|
|
34819
35027
|
assertVoiceSimulationSuiteEvidence,
|
|
35028
|
+
assertVoiceRealtimeProviderContractEvidence,
|
|
34820
35029
|
assertVoiceRealtimeChannelEvidence,
|
|
34821
35030
|
assertVoiceProviderStackEvidence,
|
|
34822
35031
|
assertVoiceProviderSloEvidence,
|