@absolutejs/voice 0.0.22-beta.302 → 0.0.22-beta.304
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -1
- package/dist/index.js +733 -435
- package/dist/realtimeChannel.d.ts +9 -0
- package/dist/realtimeProviderContracts.d.ts +115 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10954,6 +10954,77 @@ var validateFormat = (label, actual, expected, issues) => {
|
|
|
10954
10954
|
});
|
|
10955
10955
|
}
|
|
10956
10956
|
};
|
|
10957
|
+
var readString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
10958
|
+
var readNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
10959
|
+
var eventHasRealtimeAssistantProof = (event) => event.type === "turn.assistant" && (event.payload.realtimeConfigured === true || event.payload.mode === "realtime" || event.metadata?.realtime === true);
|
|
10960
|
+
var buildVoiceRealtimeChannelRuntimeSamplesFromTrace = (events, options = {}) => {
|
|
10961
|
+
const format = options.format ?? DEFAULT_REALTIME_FORMAT2;
|
|
10962
|
+
const source = options.source ?? "trace-store";
|
|
10963
|
+
const samples = [];
|
|
10964
|
+
const stagesByTurn = new Map;
|
|
10965
|
+
for (const event of events) {
|
|
10966
|
+
if (event.type !== "turn_latency.stage" || !event.turnId) {
|
|
10967
|
+
continue;
|
|
10968
|
+
}
|
|
10969
|
+
const stage = readString(event.payload.stage);
|
|
10970
|
+
if (!stage) {
|
|
10971
|
+
continue;
|
|
10972
|
+
}
|
|
10973
|
+
const stages = stagesByTurn.get(event.turnId) ?? new Map;
|
|
10974
|
+
stages.set(stage, event.at);
|
|
10975
|
+
stagesByTurn.set(event.turnId, stages);
|
|
10976
|
+
}
|
|
10977
|
+
for (const event of [...events].sort((left, right) => left.at - right.at)) {
|
|
10978
|
+
if (event.type === "turn.committed") {
|
|
10979
|
+
samples.push({
|
|
10980
|
+
format,
|
|
10981
|
+
kind: "input-audio",
|
|
10982
|
+
observedAt: event.at,
|
|
10983
|
+
ok: true,
|
|
10984
|
+
sessionId: event.sessionId,
|
|
10985
|
+
source,
|
|
10986
|
+
turnId: event.turnId
|
|
10987
|
+
});
|
|
10988
|
+
samples.push({
|
|
10989
|
+
kind: "turn-commit",
|
|
10990
|
+
observedAt: event.at,
|
|
10991
|
+
ok: true,
|
|
10992
|
+
sessionId: event.sessionId,
|
|
10993
|
+
source,
|
|
10994
|
+
turnId: event.turnId
|
|
10995
|
+
});
|
|
10996
|
+
continue;
|
|
10997
|
+
}
|
|
10998
|
+
if (eventHasRealtimeAssistantProof(event)) {
|
|
10999
|
+
const stages = event.turnId ? stagesByTurn.get(event.turnId) : undefined;
|
|
11000
|
+
const committedAt = stages?.get("turn_committed");
|
|
11001
|
+
const audioAt = stages?.get("assistant_audio_received") ?? stages?.get("tts_send_completed") ?? stages?.get("assistant_text_started") ?? event.at;
|
|
11002
|
+
const latencyMs = committedAt !== undefined ? Math.max(0, audioAt - committedAt) : readNumber(event.payload.elapsedMs);
|
|
11003
|
+
samples.push({
|
|
11004
|
+
format,
|
|
11005
|
+
kind: "assistant-audio",
|
|
11006
|
+
latencyMs,
|
|
11007
|
+
observedAt: event.at,
|
|
11008
|
+
ok: event.payload.status !== "realtime-send-failed",
|
|
11009
|
+
sessionId: event.sessionId,
|
|
11010
|
+
source,
|
|
11011
|
+
turnId: event.turnId
|
|
11012
|
+
});
|
|
11013
|
+
continue;
|
|
11014
|
+
}
|
|
11015
|
+
if (event.type === "client.reconnect") {
|
|
11016
|
+
samples.push({
|
|
11017
|
+
kind: "reconnect",
|
|
11018
|
+
observedAt: event.at,
|
|
11019
|
+
ok: event.payload.status !== "failed",
|
|
11020
|
+
sessionId: event.sessionId,
|
|
11021
|
+
source,
|
|
11022
|
+
turnId: event.turnId
|
|
11023
|
+
});
|
|
11024
|
+
}
|
|
11025
|
+
}
|
|
11026
|
+
return samples;
|
|
11027
|
+
};
|
|
10957
11028
|
var buildVoiceRealtimeChannelReport = (options) => {
|
|
10958
11029
|
const expectedInputFormat = options.expectedInputFormat ?? DEFAULT_REALTIME_FORMAT2;
|
|
10959
11030
|
const expectedOutputFormat = options.expectedOutputFormat ?? expectedInputFormat;
|
|
@@ -11121,8 +11192,26 @@ var createVoiceRealtimeChannelRoutes = (options) => {
|
|
|
11121
11192
|
const markdownPath = options.markdownPath ?? "/voice/realtime-channel.md";
|
|
11122
11193
|
const headers = options.headers ?? {};
|
|
11123
11194
|
const title = options.title ?? "Voice Realtime Channel Proof";
|
|
11124
|
-
const
|
|
11125
|
-
|
|
11195
|
+
const resolveOptions = async () => {
|
|
11196
|
+
const source = typeof options.source === "function" ? await options.source() : options.source ?? options;
|
|
11197
|
+
const {
|
|
11198
|
+
headers: _headers,
|
|
11199
|
+
htmlPath: _htmlPath,
|
|
11200
|
+
markdownPath: _markdownPath,
|
|
11201
|
+
name: _name,
|
|
11202
|
+
path: _path,
|
|
11203
|
+
render: _render,
|
|
11204
|
+
source: _source,
|
|
11205
|
+
title: _title,
|
|
11206
|
+
...reportOptions
|
|
11207
|
+
} = {
|
|
11208
|
+
...options,
|
|
11209
|
+
...source
|
|
11210
|
+
};
|
|
11211
|
+
return reportOptions;
|
|
11212
|
+
};
|
|
11213
|
+
const report = async () => buildVoiceRealtimeChannelReport(await resolveOptions());
|
|
11214
|
+
const app = new Elysia9({ name: options.name ?? "voice-realtime-channel" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
11126
11215
|
headers: {
|
|
11127
11216
|
"content-type": "application/json; charset=utf-8",
|
|
11128
11217
|
...headers
|
|
@@ -11130,7 +11219,7 @@ var createVoiceRealtimeChannelRoutes = (options) => {
|
|
|
11130
11219
|
}));
|
|
11131
11220
|
if (htmlPath !== false) {
|
|
11132
11221
|
app.get(htmlPath, async () => {
|
|
11133
|
-
const current = report();
|
|
11222
|
+
const current = await report();
|
|
11134
11223
|
const body = options.render ? await options.render(current) : renderVoiceRealtimeChannelHTML(current, title);
|
|
11135
11224
|
return new Response(body, {
|
|
11136
11225
|
headers: {
|
|
@@ -11141,7 +11230,7 @@ var createVoiceRealtimeChannelRoutes = (options) => {
|
|
|
11141
11230
|
});
|
|
11142
11231
|
}
|
|
11143
11232
|
if (markdownPath !== false) {
|
|
11144
|
-
app.get(markdownPath, () => new Response(renderVoiceRealtimeChannelMarkdown(report()), {
|
|
11233
|
+
app.get(markdownPath, async () => new Response(renderVoiceRealtimeChannelMarkdown(await report()), {
|
|
11145
11234
|
headers: {
|
|
11146
11235
|
"content-type": "text/markdown; charset=utf-8",
|
|
11147
11236
|
...headers
|
|
@@ -11150,9 +11239,212 @@ var createVoiceRealtimeChannelRoutes = (options) => {
|
|
|
11150
11239
|
}
|
|
11151
11240
|
return app;
|
|
11152
11241
|
};
|
|
11153
|
-
// src/
|
|
11242
|
+
// src/realtimeProviderContracts.ts
|
|
11154
11243
|
import { Elysia as Elysia10 } from "elysia";
|
|
11155
|
-
var
|
|
11244
|
+
var defaultRequiredCapabilities = [
|
|
11245
|
+
"browser-format-negotiation",
|
|
11246
|
+
"raw-pcm",
|
|
11247
|
+
"duplex-audio",
|
|
11248
|
+
"turn-commit",
|
|
11249
|
+
"first-audio-latency",
|
|
11250
|
+
"trace-evidence",
|
|
11251
|
+
"reconnect",
|
|
11252
|
+
"barge-in"
|
|
11253
|
+
];
|
|
11254
|
+
var defaultProviderEnv = {
|
|
11255
|
+
"gemini-live": ["GEMINI_API_KEY"],
|
|
11256
|
+
"openai-realtime": ["OPENAI_API_KEY"],
|
|
11257
|
+
"pipecat-bridge": []
|
|
11258
|
+
};
|
|
11259
|
+
var statusRank = {
|
|
11260
|
+
pass: 0,
|
|
11261
|
+
warn: 1,
|
|
11262
|
+
fail: 2
|
|
11263
|
+
};
|
|
11264
|
+
var statusExceeds = (actual, max) => statusRank[actual] > statusRank[max];
|
|
11265
|
+
var rollupStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
11266
|
+
var escapeHtml13 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11267
|
+
var buildVoiceRealtimeProviderContractMatrix = (input) => {
|
|
11268
|
+
const rows = input.contracts.map((contract) => {
|
|
11269
|
+
const configured = contract.configured !== false;
|
|
11270
|
+
const requiredEnv = contract.requiredEnv ?? defaultProviderEnv[contract.provider] ?? [];
|
|
11271
|
+
const missingEnv = requiredEnv.filter((name) => !contract.env?.[name]);
|
|
11272
|
+
const requiredCapabilities = contract.requiredCapabilities ?? defaultRequiredCapabilities;
|
|
11273
|
+
const presentCapabilities = new Set(contract.capabilities ?? []);
|
|
11274
|
+
const missingCapabilities = requiredCapabilities.filter((capability) => !presentCapabilities.has(capability));
|
|
11275
|
+
const realtimeChannel = contract.realtimeChannel;
|
|
11276
|
+
const checks = [
|
|
11277
|
+
{
|
|
11278
|
+
detail: configured ? "Provider is configured for this deployment." : "Provider is declared but not configured.",
|
|
11279
|
+
key: "configured",
|
|
11280
|
+
label: "Configured",
|
|
11281
|
+
status: configured ? "pass" : "fail"
|
|
11282
|
+
},
|
|
11283
|
+
{
|
|
11284
|
+
detail: missingEnv.length === 0 ? "Required environment is present." : `Missing env: ${missingEnv.join(", ")}.`,
|
|
11285
|
+
key: "env",
|
|
11286
|
+
label: "Required env",
|
|
11287
|
+
status: missingEnv.length === 0 ? "pass" : "fail"
|
|
11288
|
+
},
|
|
11289
|
+
{
|
|
11290
|
+
detail: missingCapabilities.length === 0 ? "Required realtime capabilities are declared." : `Missing capabilities: ${missingCapabilities.join(", ")}.`,
|
|
11291
|
+
key: "capabilities",
|
|
11292
|
+
label: "Realtime capabilities",
|
|
11293
|
+
status: missingCapabilities.length === 0 ? "pass" : "warn"
|
|
11294
|
+
},
|
|
11295
|
+
{
|
|
11296
|
+
detail: realtimeChannel ? `Realtime channel proof is ${realtimeChannel.status}.` : "No realtime channel proof linked.",
|
|
11297
|
+
key: "realtimeChannel",
|
|
11298
|
+
label: "Realtime channel proof",
|
|
11299
|
+
status: realtimeChannel?.status === "pass" ? "pass" : realtimeChannel ? "warn" : "fail"
|
|
11300
|
+
},
|
|
11301
|
+
{
|
|
11302
|
+
detail: contract.latencyBudgetMs !== undefined ? `First audio latency budget is ${String(contract.latencyBudgetMs)}ms.` : "No first-audio latency budget declared.",
|
|
11303
|
+
key: "latencyBudget",
|
|
11304
|
+
label: "Latency budget",
|
|
11305
|
+
status: contract.latencyBudgetMs !== undefined ? "pass" : "warn"
|
|
11306
|
+
},
|
|
11307
|
+
{
|
|
11308
|
+
detail: (contract.fallbackProviders ?? []).length > 0 ? `Fallback providers: ${contract.fallbackProviders?.join(", ")}.` : "No realtime fallback provider declared.",
|
|
11309
|
+
key: "fallback",
|
|
11310
|
+
label: "Fallback",
|
|
11311
|
+
status: (contract.fallbackProviders ?? []).length > 0 ? "pass" : "warn"
|
|
11312
|
+
},
|
|
11313
|
+
{
|
|
11314
|
+
detail: contract.traceHref ? `Trace evidence: ${contract.traceHref}.` : "Trace evidence link is missing.",
|
|
11315
|
+
key: "traceEvidence",
|
|
11316
|
+
label: "Trace evidence",
|
|
11317
|
+
status: contract.traceHref ? "pass" : "warn"
|
|
11318
|
+
},
|
|
11319
|
+
{
|
|
11320
|
+
detail: contract.readinessHref ? `Readiness gate: ${contract.readinessHref}.` : "Readiness gate link is missing.",
|
|
11321
|
+
key: "readiness",
|
|
11322
|
+
label: "Readiness gate",
|
|
11323
|
+
status: contract.readinessHref ? "pass" : "warn"
|
|
11324
|
+
}
|
|
11325
|
+
];
|
|
11326
|
+
return {
|
|
11327
|
+
checks,
|
|
11328
|
+
configured,
|
|
11329
|
+
provider: contract.provider,
|
|
11330
|
+
selected: contract.selected === true,
|
|
11331
|
+
status: rollupStatus(checks)
|
|
11332
|
+
};
|
|
11333
|
+
});
|
|
11334
|
+
const failed = rows.filter((row) => row.status === "fail").length;
|
|
11335
|
+
const warned = rows.filter((row) => row.status === "warn").length;
|
|
11336
|
+
return {
|
|
11337
|
+
failed,
|
|
11338
|
+
passed: rows.filter((row) => row.status === "pass").length,
|
|
11339
|
+
rows,
|
|
11340
|
+
status: failed > 0 ? "fail" : warned > 0 ? "warn" : "pass",
|
|
11341
|
+
total: rows.length,
|
|
11342
|
+
warned
|
|
11343
|
+
};
|
|
11344
|
+
};
|
|
11345
|
+
var evaluateVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
11346
|
+
const issues = [];
|
|
11347
|
+
const maxStatus = input.maxStatus ?? "pass";
|
|
11348
|
+
const maxFailed = input.maxFailed ?? 0;
|
|
11349
|
+
const maxWarned = input.maxWarned ?? 0;
|
|
11350
|
+
const minRows = input.minRows ?? 1;
|
|
11351
|
+
const providers = [...new Set(report.rows.map((row) => row.provider))].sort();
|
|
11352
|
+
const selectedProviders = [
|
|
11353
|
+
...new Set(report.rows.filter((row) => row.selected).map((row) => row.provider))
|
|
11354
|
+
].sort();
|
|
11355
|
+
if (statusExceeds(report.status, maxStatus)) {
|
|
11356
|
+
issues.push(`Expected realtime provider contract status at most ${maxStatus}, found ${report.status}.`);
|
|
11357
|
+
}
|
|
11358
|
+
if (report.failed > maxFailed) {
|
|
11359
|
+
issues.push(`Expected at most ${String(maxFailed)} failing realtime provider row(s), found ${String(report.failed)}.`);
|
|
11360
|
+
}
|
|
11361
|
+
if (report.warned > maxWarned) {
|
|
11362
|
+
issues.push(`Expected at most ${String(maxWarned)} warning realtime provider row(s), found ${String(report.warned)}.`);
|
|
11363
|
+
}
|
|
11364
|
+
if (report.total < minRows) {
|
|
11365
|
+
issues.push(`Expected at least ${String(minRows)} realtime provider row(s), found ${String(report.total)}.`);
|
|
11366
|
+
}
|
|
11367
|
+
for (const provider of input.requiredProviders ?? []) {
|
|
11368
|
+
if (!providers.includes(provider)) {
|
|
11369
|
+
issues.push(`Missing realtime provider contract provider: ${provider}.`);
|
|
11370
|
+
}
|
|
11371
|
+
}
|
|
11372
|
+
for (const key of input.requiredCheckKeys ?? []) {
|
|
11373
|
+
const missingRows = report.rows.filter((row) => !row.checks.some((check) => check.key === key)).length;
|
|
11374
|
+
if (missingRows > 0) {
|
|
11375
|
+
issues.push(`Realtime provider contract check ${key} is missing from ${String(missingRows)} row(s).`);
|
|
11376
|
+
}
|
|
11377
|
+
}
|
|
11378
|
+
for (const capability of input.requiredCapabilities ?? []) {
|
|
11379
|
+
const missingRows = report.rows.filter((row) => {
|
|
11380
|
+
const capabilityCheck = row.checks.find((check) => check.key === "capabilities");
|
|
11381
|
+
return capabilityCheck?.detail?.includes(capability) === true;
|
|
11382
|
+
}).length;
|
|
11383
|
+
if (missingRows > 0) {
|
|
11384
|
+
issues.push(`Realtime provider capability ${capability} is missing from ${String(missingRows)} row(s).`);
|
|
11385
|
+
}
|
|
11386
|
+
}
|
|
11387
|
+
if ((input.requireSelected ?? true) && selectedProviders.length === 0) {
|
|
11388
|
+
issues.push("Missing selected realtime provider contract row.");
|
|
11389
|
+
}
|
|
11390
|
+
return {
|
|
11391
|
+
failed: report.failed,
|
|
11392
|
+
issues,
|
|
11393
|
+
ok: issues.length === 0,
|
|
11394
|
+
providers,
|
|
11395
|
+
selectedProviders,
|
|
11396
|
+
status: report.status,
|
|
11397
|
+
total: report.total,
|
|
11398
|
+
warned: report.warned
|
|
11399
|
+
};
|
|
11400
|
+
};
|
|
11401
|
+
var assertVoiceRealtimeProviderContractEvidence = (report, input = {}) => {
|
|
11402
|
+
const assertion = evaluateVoiceRealtimeProviderContractEvidence(report, input);
|
|
11403
|
+
if (!assertion.ok) {
|
|
11404
|
+
throw new Error(`Voice realtime provider contract assertion failed: ${assertion.issues.join(" ")}`);
|
|
11405
|
+
}
|
|
11406
|
+
return assertion;
|
|
11407
|
+
};
|
|
11408
|
+
var resolveMatrix = async (matrix) => typeof matrix === "function" ? await matrix() : matrix;
|
|
11409
|
+
var renderVoiceRealtimeProviderContractHTML = (report, title = "Voice Realtime Provider Contracts") => {
|
|
11410
|
+
const rows = report.rows.map((row) => {
|
|
11411
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml13(check.status)}"><strong>${escapeHtml13(check.label)}</strong><span>${escapeHtml13(check.detail ?? check.status)}</span></li>`).join("");
|
|
11412
|
+
return `<article class="row ${escapeHtml13(row.status)}"><div><p class="eyebrow">${row.selected ? "selected" : "available"}</p><h2>${escapeHtml13(row.provider)}</h2><p class="status ${escapeHtml13(row.status)}">${escapeHtml13(row.status)}</p></div><ul>${checks}</ul></article>`;
|
|
11413
|
+
}).join("");
|
|
11414
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml13(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.row{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.1))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.row{display:grid;gap:18px;grid-template-columns:minmax(190px,.4fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#101814;border:1px solid #2e3d36;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.pass{color:#86efac}.warn{color:#fde68a}.fail{color:#fecaca}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime provider contracts</p><h1>${escapeHtml13(title)}</h1><p>Provider-level proof for duplex audio, browser format negotiation, turn commit, latency, reconnect, barge-in, trace evidence, fallback, and readiness gates.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section>${rows || '<article class="row"><p>No realtime provider contracts configured.</p></article>'}</main></body></html>`;
|
|
11415
|
+
};
|
|
11416
|
+
var createVoiceRealtimeProviderContractRoutes = (options) => {
|
|
11417
|
+
const path = options.path ?? "/api/voice/realtime-provider-contracts";
|
|
11418
|
+
const htmlPath = options.htmlPath ?? "/voice/realtime-provider-contracts";
|
|
11419
|
+
const title = options.title ?? "Voice Realtime Provider Contracts";
|
|
11420
|
+
const report = async () => buildVoiceRealtimeProviderContractMatrix(await resolveMatrix(options.matrix));
|
|
11421
|
+
const routes = new Elysia10({
|
|
11422
|
+
name: options.name ?? "voice-realtime-provider-contracts"
|
|
11423
|
+
}).get(path, async () => {
|
|
11424
|
+
return new Response(JSON.stringify(await report(), null, 2), {
|
|
11425
|
+
headers: {
|
|
11426
|
+
"content-type": "application/json; charset=utf-8",
|
|
11427
|
+
...options.headers
|
|
11428
|
+
}
|
|
11429
|
+
});
|
|
11430
|
+
});
|
|
11431
|
+
if (htmlPath !== false) {
|
|
11432
|
+
routes.get(htmlPath, async () => {
|
|
11433
|
+
const current = await report();
|
|
11434
|
+
const body = options.render ? await options.render(current) : renderVoiceRealtimeProviderContractHTML(current, title);
|
|
11435
|
+
return new Response(body, {
|
|
11436
|
+
headers: {
|
|
11437
|
+
"content-type": "text/html; charset=utf-8",
|
|
11438
|
+
...options.headers
|
|
11439
|
+
}
|
|
11440
|
+
});
|
|
11441
|
+
});
|
|
11442
|
+
}
|
|
11443
|
+
return routes;
|
|
11444
|
+
};
|
|
11445
|
+
// src/diagnosticsRoutes.ts
|
|
11446
|
+
import { Elysia as Elysia11 } from "elysia";
|
|
11447
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11156
11448
|
var getString6 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
11157
11449
|
var getNumber4 = (value) => {
|
|
11158
11450
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
|
|
@@ -11218,9 +11510,9 @@ var renderDiagnosticsIndex = (input) => {
|
|
|
11218
11510
|
const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
|
|
11219
11511
|
const summary = summarizeVoiceTrace(events);
|
|
11220
11512
|
const encoded = encodeURIComponent(sessionId);
|
|
11221
|
-
return `<tr><td>${
|
|
11513
|
+
return `<tr><td>${escapeHtml14(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
|
|
11222
11514
|
}).join("");
|
|
11223
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11515
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml14(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml14(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
11224
11516
|
};
|
|
11225
11517
|
var withRedaction = (events, query, defaultRedact) => {
|
|
11226
11518
|
const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
|
|
@@ -11229,7 +11521,7 @@ var withRedaction = (events, query, defaultRedact) => {
|
|
|
11229
11521
|
var createVoiceDiagnosticsRoutes = (options) => {
|
|
11230
11522
|
const path = options.path ?? "/diagnostics";
|
|
11231
11523
|
const title = options.title ?? "AbsoluteJS Voice Diagnostics";
|
|
11232
|
-
const routes = new
|
|
11524
|
+
const routes = new Elysia11({
|
|
11233
11525
|
name: options.name ?? "absolutejs-voice-diagnostics"
|
|
11234
11526
|
});
|
|
11235
11527
|
routes.get(path, async () => {
|
|
@@ -11286,9 +11578,9 @@ var createVoiceDiagnosticsRoutes = (options) => {
|
|
|
11286
11578
|
return routes;
|
|
11287
11579
|
};
|
|
11288
11580
|
// src/demoReadyRoutes.ts
|
|
11289
|
-
import { Elysia as
|
|
11290
|
-
var
|
|
11291
|
-
var
|
|
11581
|
+
import { Elysia as Elysia12 } from "elysia";
|
|
11582
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11583
|
+
var rollupStatus2 = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
11292
11584
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
11293
11585
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
11294
11586
|
const query = input.query ?? {};
|
|
@@ -11344,7 +11636,7 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11344
11636
|
return {
|
|
11345
11637
|
checkedAt: Date.now(),
|
|
11346
11638
|
sections,
|
|
11347
|
-
status: sections.length === 0 ? "warn" :
|
|
11639
|
+
status: sections.length === 0 ? "warn" : rollupStatus2(sections),
|
|
11348
11640
|
summary: {
|
|
11349
11641
|
opsStatus: opsStatus ? {
|
|
11350
11642
|
failed: opsStatus.failed,
|
|
@@ -11371,17 +11663,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11371
11663
|
};
|
|
11372
11664
|
};
|
|
11373
11665
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
11374
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
11375
|
-
<div><span>${
|
|
11376
|
-
<strong>${
|
|
11377
|
-
${section.href ? `<a href="${
|
|
11666
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml15(section.status)}">
|
|
11667
|
+
<div><span>${escapeHtml15(section.status.toUpperCase())}</span><h2>${escapeHtml15(section.label)}</h2>${section.description ? `<p>${escapeHtml15(section.description)}</p>` : ""}</div>
|
|
11668
|
+
<strong>${escapeHtml15(String(section.value ?? section.status))}</strong>
|
|
11669
|
+
${section.href ? `<a href="${escapeHtml15(section.href)}">Open</a>` : ""}
|
|
11378
11670
|
</article>`).join("");
|
|
11379
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11671
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(report.title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.sections{display:grid;gap:14px}.section{align-items:center;background:#151d26;border:1px solid #283544;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.section span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.section h2{margin:.2rem 0}.section p{color:#b9c0c8;margin:.2rem 0 0}.section strong{font-size:1.4rem}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.65)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}@media(max-width:760px){main{padding:20px}.section{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Demo readiness</p><h1>${escapeHtml15(report.title)}</h1><p>One customer-facing checklist for the self-hosted voice proof surfaces: ops status, production readiness, phone setup, and phone smoke traces.</p><p class="status ${escapeHtml15(report.status)}">Overall: ${escapeHtml15(report.status.toUpperCase())}</p><p>Checked ${escapeHtml15(new Date(report.checkedAt).toLocaleString())}</p></section><section class="sections">${sections || '<article class="section warn"><div><span>WARN</span><h2>No checks configured</h2><p>Add ops status, production readiness, phone setup, or phone smoke loaders.</p></div><strong>warn</strong></article>'}</section></main></body></html>`;
|
|
11380
11672
|
};
|
|
11381
11673
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
11382
11674
|
const path = options.path ?? "/api/demo-ready";
|
|
11383
11675
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
11384
|
-
const routes = new
|
|
11676
|
+
const routes = new Elysia12({
|
|
11385
11677
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
11386
11678
|
});
|
|
11387
11679
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -11400,7 +11692,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
11400
11692
|
return routes;
|
|
11401
11693
|
};
|
|
11402
11694
|
// src/deliverySinkRoutes.ts
|
|
11403
|
-
import { Elysia as
|
|
11695
|
+
import { Elysia as Elysia13 } from "elysia";
|
|
11404
11696
|
|
|
11405
11697
|
// src/queue.ts
|
|
11406
11698
|
var releaseLeaseScript = `
|
|
@@ -12343,7 +12635,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
12343
12635
|
};
|
|
12344
12636
|
|
|
12345
12637
|
// src/deliverySinkRoutes.ts
|
|
12346
|
-
var
|
|
12638
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12347
12639
|
var deliveryStatus = (summary) => {
|
|
12348
12640
|
if (!summary) {
|
|
12349
12641
|
return "warn";
|
|
@@ -12442,13 +12734,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
12442
12734
|
return "";
|
|
12443
12735
|
}
|
|
12444
12736
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
12445
|
-
const body = `<span>${
|
|
12446
|
-
return `<article>${surface.href ? `<a href="${
|
|
12737
|
+
const body = `<span>${escapeHtml16(surface.label)}</span><strong>${escapeHtml16(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
12738
|
+
return `<article>${surface.href ? `<a href="${escapeHtml16(surface.href)}">${body}</a>` : body}</article>`;
|
|
12447
12739
|
};
|
|
12448
12740
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
12449
12741
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
12450
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
12451
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12742
|
+
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${escapeHtml16(sink.kind)}</span><strong style="font-size:1.5rem">${escapeHtml16(sink.label)}</strong>${sink.description ? `<p class="muted">${escapeHtml16(sink.description)}</p>` : ""}${sink.mode ? `<p class="muted">Mode: ${escapeHtml16(sink.mode)}</p>` : ""}${sink.target ? `<p class="muted">Target: <code>${escapeHtml16(sink.target)}</code></p>` : ""}${sink.href ? `<p><a href="${escapeHtml16(sink.href)}">Open sink</a></p>` : ""}</article>`).join("") : '<article><span>Sink</span><strong style="font-size:1.5rem">Not described</strong><p class="muted">Pass sink descriptors to document your file, webhook, S3, SQLite, or Postgres targets.</p></article>';
|
|
12743
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{background:#11120d;color:#fbf7e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{max-width:1120px;margin:auto;padding:32px}a{color:#fde68a;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(253,230,138,.2),rgba(34,197,94,.14));border:1px solid #3a3420;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fde68a;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.65)}.status.fail{border-color:rgba(239,68,68,.75)}.muted{color:#b8b093}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#191a13;border:1px solid #33311f;border-radius:22px;padding:18px}article span{color:#b8b093;display:block;font-weight:800}article strong{display:block;font-size:2.4rem;margin-top:8px}pre{background:#0c0d09;border:1px solid #33311f;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}code{color:#fef3c7}</style></head><body><main><p><a href="/production-readiness">Production readiness</a></p><section class="hero"><p class="eyebrow">Composable sink primitive</p><h1>${escapeHtml16(title)}</h1><p class="muted">Delivery queues prove audit and trace exports without owning your infrastructure. Swap file, webhook, S3, SQLite, or Postgres sinks behind the same readiness surface.</p><p class="status ${escapeHtml16(report.status)}">Overall: ${escapeHtml16(report.status.toUpperCase())}</p><p class="muted">Checked ${escapeHtml16(new Date(report.checkedAt).toLocaleString())}</p></section><section class="grid">${renderSurfaceCard(report.auditDeliveries)}${renderSurfaceCard(report.traceDeliveries)}${sinks}</section><section class="card"><h2>Primitive shape</h2><p class="muted">Mount delivery sink routes beside audit and trace delivery queues. Production readiness can consume the same stores for pass/fail evidence.</p><pre>createVoiceDeliverySinkRoutes({
|
|
12452
12744
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
12453
12745
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
12454
12746
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -12460,7 +12752,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
12460
12752
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
12461
12753
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
12462
12754
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
12463
|
-
const routes = new
|
|
12755
|
+
const routes = new Elysia13({
|
|
12464
12756
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
12465
12757
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
12466
12758
|
if (htmlPath !== false) {
|
|
@@ -12478,7 +12770,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
12478
12770
|
return routes;
|
|
12479
12771
|
};
|
|
12480
12772
|
// src/opsActionAuditRoutes.ts
|
|
12481
|
-
import { Elysia as
|
|
12773
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12482
12774
|
var readRecordBody = (body) => {
|
|
12483
12775
|
if (!body || typeof body !== "object") {
|
|
12484
12776
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -12553,7 +12845,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
12553
12845
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
12554
12846
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
12555
12847
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
12556
|
-
const routes = new
|
|
12848
|
+
const routes = new Elysia14({
|
|
12557
12849
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
12558
12850
|
}).post(path, async ({ body, request, set }) => {
|
|
12559
12851
|
try {
|
|
@@ -12603,13 +12895,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
12603
12895
|
total: entries.length
|
|
12604
12896
|
};
|
|
12605
12897
|
};
|
|
12606
|
-
var
|
|
12898
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12607
12899
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
12608
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
12900
|
+
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml17(entry.ok ? "success" : "error")}</span><strong>${escapeHtml17(entry.actionId)}</strong><p>${escapeHtml17(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml17(entry.error)}</p>` : ""}</article>`).join("");
|
|
12609
12901
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Ops Action History</title><style>body{background:#11140f;color:#f7f1df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,article{background:#181d15;border:1px solid #2c3327;border-radius:24px;padding:20px}.hero{margin-bottom:16px}h1{font-size:clamp(2rem,6vw,4rem);line-height:.95}section{display:grid;gap:12px}article.ok{border-color:rgba(34,197,94,.55)}article.fail{border-color:rgba(239,68,68,.75)}span{color:#facc15;font-weight:900;text-transform:uppercase}p{color:#c8ccb8}</style></head><body><main><section class="hero"><span>Operator proof</span><h1>Voice Ops Action History</h1><p>${String(report.total)} action(s), ${String(report.failed)} failed.</p></section><section>${rows || "<p>No operator actions have been recorded.</p>"}</section></main></body></html>`;
|
|
12610
12902
|
};
|
|
12611
12903
|
// src/platformCoverage.ts
|
|
12612
|
-
import { Elysia as
|
|
12904
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12613
12905
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
12614
12906
|
const coverage = input.coverage ?? [];
|
|
12615
12907
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -12670,7 +12962,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
12670
12962
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
12671
12963
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
12672
12964
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
12673
|
-
const routes = new
|
|
12965
|
+
const routes = new Elysia15({
|
|
12674
12966
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
12675
12967
|
});
|
|
12676
12968
|
routes.get(path, async () => {
|
|
@@ -12682,8 +12974,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
12682
12974
|
return routes;
|
|
12683
12975
|
};
|
|
12684
12976
|
// src/competitiveCoverage.ts
|
|
12685
|
-
import { Elysia as
|
|
12686
|
-
var
|
|
12977
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12978
|
+
var escapeHtml18 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12687
12979
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
12688
12980
|
var resolveSurfaceStatus = (surface) => {
|
|
12689
12981
|
if (surface.status)
|
|
@@ -12851,24 +13143,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
12851
13143
|
`);
|
|
12852
13144
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
12853
13145
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
12854
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
12855
|
-
return `<article class="surface ${
|
|
12856
|
-
<header><div><p class="eyebrow">${
|
|
12857
|
-
<p>${
|
|
13146
|
+
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${escapeHtml18(item.name)}</strong>${item.kind ? ` <span>${escapeHtml18(item.kind)}</span>` : ""}${item.status ? ` <em>${escapeHtml18(item.status)}</em>` : ""}${item.href ? ` <a href="${escapeHtml18(item.href)}">open</a>` : ""}</li>`).join("");
|
|
13147
|
+
return `<article class="surface ${escapeHtml18(surface.status)} ${escapeHtml18(surface.depth)}">
|
|
13148
|
+
<header><div><p class="eyebrow">${escapeHtml18(surface.coverage)} \xB7 ${escapeHtml18(surface.depth)}</p><h2>${escapeHtml18(surface.surface)}</h2></div><strong>${escapeHtml18(surface.status)}</strong></header>
|
|
13149
|
+
<p>${escapeHtml18(surface.why)}</p>
|
|
12858
13150
|
<dl>
|
|
12859
|
-
<div><dt>Competitors</dt><dd>${
|
|
12860
|
-
<div><dt>Operations record</dt><dd>${
|
|
12861
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
12862
|
-
<div><dt>Frameworks</dt><dd>${
|
|
13151
|
+
<div><dt>Competitors</dt><dd>${escapeHtml18((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
13152
|
+
<div><dt>Operations record</dt><dd>${escapeHtml18(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
13153
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml18(surface.readinessGate ?? "unknown")}</dd></div>
|
|
13154
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml18((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
12863
13155
|
</dl>
|
|
12864
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
12865
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
13156
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml18(surface.remainingGap)}</p>` : ""}
|
|
13157
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml18(surface.nextMove)}</p>` : ""}
|
|
12866
13158
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
12867
13159
|
</article>`;
|
|
12868
13160
|
}).join(`
|
|
12869
13161
|
`);
|
|
12870
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
12871
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13162
|
+
const issueList = report.issues.map((issue) => `<li class="${escapeHtml18(issue.severity)}"><strong>${escapeHtml18(issue.code)}</strong>${issue.surface ? ` ${escapeHtml18(issue.surface)}` : ""}: ${escapeHtml18(issue.message)}</li>`).join("");
|
|
13163
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(title)}</title><style>body{background:#0e1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.surface,.issues{background:#17201c;border:1px solid #2e3c35;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.16),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.surfaces{display:grid;gap:14px}.surface header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.surface.pass{border-color:rgba(34,197,94,.55)}.surface.warn{border-color:rgba(245,158,11,.72)}.surface.fail{border-color:rgba(239,68,68,.75)}.surface.advantage h2{color:#bbf7d0}.surface.intentional-gap h2{color:#cbd5e1}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}dt{color:#9fb0a8;font-size:.8rem;font-weight:800}dd{margin:0;overflow-wrap:anywhere}.gap{color:#fde68a}.next{color:#bfdbfe}.muted{color:#a8b5ad}a{color:#5eead4}.issues li{margin:.4rem 0}.issues .error{color:#fecaca}.issues .warning{color:#fde68a}@media(max-width:760px){main{padding:18px}.surface header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted market proof</p><h1>${escapeHtml18(title)}</h1><p>Generated ${escapeHtml18(report.generatedAt)}. This report scores whether AbsoluteJS Voice merely covers a hosted-platform buyer surface or beats it for a code-owned/self-hosted buyer.</p><div class="summary"><span class="pill">Status ${escapeHtml18(report.status)}</span><span class="pill">Vapi-style ${escapeHtml18(report.vapiCoverageEstimate)}</span><span class="pill">Market ${escapeHtml18(report.marketCoverageEstimate)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.advantage)} advantage</span><span class="pill">${String(report.summary.intentionalGaps)} intentional gaps</span></div></section><section class="issues"><h2>Issues</h2><ul>${issueList || "<li>No issues.</li>"}</ul></section><section class="surfaces">${surfaceCards || '<article class="surface"><p>No competitive surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
12872
13164
|
};
|
|
12873
13165
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
12874
13166
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -12881,7 +13173,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12881
13173
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
12882
13174
|
return normalizeCompetitiveCoverageReport(value);
|
|
12883
13175
|
};
|
|
12884
|
-
const app = new
|
|
13176
|
+
const app = new Elysia16({
|
|
12885
13177
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
12886
13178
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
12887
13179
|
headers: {
|
|
@@ -12912,7 +13204,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12912
13204
|
return app;
|
|
12913
13205
|
};
|
|
12914
13206
|
// src/proofTrends.ts
|
|
12915
|
-
import { Elysia as
|
|
13207
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
12916
13208
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
12917
13209
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
12918
13210
|
var toTimeMs = (value) => {
|
|
@@ -13063,7 +13355,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
13063
13355
|
};
|
|
13064
13356
|
var createVoiceProofTrendRoutes = (options) => {
|
|
13065
13357
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
13066
|
-
const routes = new
|
|
13358
|
+
const routes = new Elysia17({
|
|
13067
13359
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
13068
13360
|
});
|
|
13069
13361
|
routes.get(path, async () => {
|
|
@@ -13096,11 +13388,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
13096
13388
|
return `${days}d ${hours % 24}h`;
|
|
13097
13389
|
};
|
|
13098
13390
|
// src/providerDecisionTraces.ts
|
|
13099
|
-
import { Elysia as
|
|
13391
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13100
13392
|
|
|
13101
13393
|
// src/resilienceRoutes.ts
|
|
13102
|
-
import { Elysia as
|
|
13103
|
-
var
|
|
13394
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
13395
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13104
13396
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
13105
13397
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13106
13398
|
var getBoolean2 = (value) => value === true;
|
|
@@ -13248,13 +13540,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
13248
13540
|
};
|
|
13249
13541
|
var renderProviderCards = (title, providers) => {
|
|
13250
13542
|
if (providers.length === 0) {
|
|
13251
|
-
return `<p class="muted">No ${
|
|
13543
|
+
return `<p class="muted">No ${escapeHtml19(title)} provider health yet.</p>`;
|
|
13252
13544
|
}
|
|
13253
13545
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
13254
|
-
<article class="card provider ${
|
|
13546
|
+
<article class="card provider ${escapeHtml19(provider.status)}">
|
|
13255
13547
|
<div class="card-header">
|
|
13256
|
-
<strong>${
|
|
13257
|
-
<span>${
|
|
13548
|
+
<strong>${escapeHtml19(provider.provider)}</strong>
|
|
13549
|
+
<span>${escapeHtml19(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
13258
13550
|
</div>
|
|
13259
13551
|
<dl>
|
|
13260
13552
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -13263,7 +13555,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
13263
13555
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
13264
13556
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
13265
13557
|
</dl>
|
|
13266
|
-
${provider.lastError ? `<p class="muted">${
|
|
13558
|
+
${provider.lastError ? `<p class="muted">${escapeHtml19(provider.lastError)}</p>` : ""}
|
|
13267
13559
|
</article>
|
|
13268
13560
|
`).join("")}</div>`;
|
|
13269
13561
|
};
|
|
@@ -13272,24 +13564,24 @@ var renderTimeline2 = (events) => {
|
|
|
13272
13564
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
13273
13565
|
}
|
|
13274
13566
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
13275
|
-
<article class="card event ${
|
|
13567
|
+
<article class="card event ${escapeHtml19(event.status ?? "unknown")}">
|
|
13276
13568
|
<div class="card-header">
|
|
13277
|
-
<strong>${
|
|
13569
|
+
<strong>${escapeHtml19(event.kind.toUpperCase())} ${escapeHtml19(event.operation ?? "generate")}</strong>
|
|
13278
13570
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
13279
13571
|
</div>
|
|
13280
13572
|
<p>
|
|
13281
|
-
<span class="pill">${
|
|
13282
|
-
<span class="pill">provider: ${
|
|
13283
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
13573
|
+
<span class="pill">${escapeHtml19(event.status ?? "unknown")}</span>
|
|
13574
|
+
<span class="pill">provider: ${escapeHtml19(event.provider ?? "unknown")}</span>
|
|
13575
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml19(event.fallbackProvider)}</span>` : ""}
|
|
13284
13576
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
13285
13577
|
</p>
|
|
13286
13578
|
<dl>
|
|
13287
13579
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
13288
13580
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
13289
13581
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
13290
|
-
<div><dt>Session</dt><dd>${
|
|
13582
|
+
<div><dt>Session</dt><dd>${escapeHtml19(event.sessionId)}</dd></div>
|
|
13291
13583
|
</dl>
|
|
13292
|
-
${event.error ? `<p class="muted">${
|
|
13584
|
+
${event.error ? `<p class="muted">${escapeHtml19(event.error)}</p>` : ""}
|
|
13293
13585
|
</article>
|
|
13294
13586
|
`).join("")}</div>`;
|
|
13295
13587
|
};
|
|
@@ -13299,9 +13591,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
13299
13591
|
const status = latest?.status ?? "idle";
|
|
13300
13592
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
13301
13593
|
return `<div>
|
|
13302
|
-
<dt>${
|
|
13303
|
-
<dd>${
|
|
13304
|
-
<small>${
|
|
13594
|
+
<dt>${escapeHtml19(kind.toUpperCase())}</dt>
|
|
13595
|
+
<dd>${escapeHtml19(provider)}${escapeHtml19(fallback)}</dd>
|
|
13596
|
+
<small>${escapeHtml19(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
|
|
13305
13597
|
</div>`;
|
|
13306
13598
|
};
|
|
13307
13599
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -13309,10 +13601,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
13309
13601
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
13310
13602
|
}
|
|
13311
13603
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
13312
|
-
<article class="card session ${
|
|
13604
|
+
<article class="card session ${escapeHtml19(session.status)}">
|
|
13313
13605
|
<div class="card-header">
|
|
13314
|
-
<strong>${
|
|
13315
|
-
<span>${
|
|
13606
|
+
<strong>${escapeHtml19(session.sessionId)}</strong>
|
|
13607
|
+
<span>${escapeHtml19(session.status)}</span>
|
|
13316
13608
|
</div>
|
|
13317
13609
|
<p>
|
|
13318
13610
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -13339,21 +13631,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
13339
13631
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
13340
13632
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
13341
13633
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
13342
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
13343
|
-
<p class="muted">${
|
|
13634
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml19(pathPrefix)}">
|
|
13635
|
+
<p class="muted">${escapeHtml19(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
13344
13636
|
<div class="simulate-actions">
|
|
13345
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
13346
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
13637
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml19(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml19(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
13638
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml19(provider.provider)}">Mark ${escapeHtml19(provider.provider)} recovered</button>`).join("")}
|
|
13347
13639
|
</div>
|
|
13348
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
13640
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml19(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
13349
13641
|
<pre class="simulate-output" hidden></pre>
|
|
13350
13642
|
</div>`;
|
|
13351
13643
|
};
|
|
13352
13644
|
var renderVoiceResilienceHTML = (input) => {
|
|
13353
13645
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
13354
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
13355
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
13356
|
-
const snippet =
|
|
13646
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml19(kind)}: ${String(count)}</span>`).join("");
|
|
13647
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join(" \xB7 ") : "";
|
|
13648
|
+
const snippet = escapeHtml19(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
13357
13649
|
kind: 'stt',
|
|
13358
13650
|
providers: ['deepgram', 'assemblyai'],
|
|
13359
13651
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -13391,7 +13683,7 @@ app.use(
|
|
|
13391
13683
|
<head>
|
|
13392
13684
|
<meta charset="utf-8" />
|
|
13393
13685
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13394
|
-
<title>${
|
|
13686
|
+
<title>${escapeHtml19(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
13395
13687
|
<style>
|
|
13396
13688
|
:root { color-scheme: dark; }
|
|
13397
13689
|
body { background: radial-gradient(circle at top left, #172554, #09090b 36%, #050505); color: #f4f4f5; font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; }
|
|
@@ -13543,7 +13835,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
13543
13835
|
};
|
|
13544
13836
|
var createVoiceResilienceRoutes = (options) => {
|
|
13545
13837
|
const path = options.path ?? "/resilience";
|
|
13546
|
-
const routes = new
|
|
13838
|
+
const routes = new Elysia18({
|
|
13547
13839
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
13548
13840
|
}).get(path, async () => {
|
|
13549
13841
|
const events = await options.store.list();
|
|
@@ -13584,7 +13876,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
13584
13876
|
};
|
|
13585
13877
|
|
|
13586
13878
|
// src/providerDecisionTraces.ts
|
|
13587
|
-
var
|
|
13879
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13588
13880
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
13589
13881
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13590
13882
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -13599,8 +13891,8 @@ var surfaceForKind = (kind) => {
|
|
|
13599
13891
|
return "live-call";
|
|
13600
13892
|
}
|
|
13601
13893
|
};
|
|
13602
|
-
var
|
|
13603
|
-
var reportStatus = (issues) => issues.reduce((status, issue) =>
|
|
13894
|
+
var statusRank2 = { fail: 2, pass: 0, warn: 1 };
|
|
13895
|
+
var reportStatus = (issues) => issues.reduce((status, issue) => statusRank2[issue.status] > statusRank2[status] ? issue.status : status, "pass");
|
|
13604
13896
|
var uniqueSorted = (values) => [
|
|
13605
13897
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
13606
13898
|
].sort();
|
|
@@ -13825,7 +14117,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
13825
14117
|
<head>
|
|
13826
14118
|
<meta charset="utf-8" />
|
|
13827
14119
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13828
|
-
<title>${
|
|
14120
|
+
<title>${escapeHtml20(title)}</title>
|
|
13829
14121
|
<style>
|
|
13830
14122
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
13831
14123
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -13839,8 +14131,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13839
14131
|
</head>
|
|
13840
14132
|
<body>
|
|
13841
14133
|
<main>
|
|
13842
|
-
<p class="status ${report.status}">${
|
|
13843
|
-
<h1>${
|
|
14134
|
+
<p class="status ${report.status}">${escapeHtml20(report.status)}</p>
|
|
14135
|
+
<h1>${escapeHtml20(title)}</h1>
|
|
13844
14136
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
13845
14137
|
<section class="grid">
|
|
13846
14138
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -13851,10 +14143,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13851
14143
|
</section>
|
|
13852
14144
|
<section class="surfaces">
|
|
13853
14145
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
13854
|
-
<header><strong>${
|
|
14146
|
+
<header><strong>${escapeHtml20(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml20(surface.status)}</span></header>
|
|
13855
14147
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
13856
|
-
<p class="muted">Providers: ${
|
|
13857
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
14148
|
+
<p class="muted">Providers: ${escapeHtml20(surface.providers.join(", ") || "none")}</p>
|
|
14149
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml20(reason)}</code>`).join(" ")}</p>
|
|
13858
14150
|
</article>`).join(`
|
|
13859
14151
|
`)}
|
|
13860
14152
|
</section>
|
|
@@ -13868,7 +14160,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13868
14160
|
const headers = options.headers ?? {};
|
|
13869
14161
|
const title = options.title ?? "Provider Decision Traces";
|
|
13870
14162
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
13871
|
-
const app = new
|
|
14163
|
+
const app = new Elysia19({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13872
14164
|
headers: {
|
|
13873
14165
|
"content-type": "application/json; charset=utf-8",
|
|
13874
14166
|
...headers
|
|
@@ -13896,7 +14188,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13896
14188
|
return app;
|
|
13897
14189
|
};
|
|
13898
14190
|
// src/sloCalibration.ts
|
|
13899
|
-
import { Elysia as
|
|
14191
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
13900
14192
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
13901
14193
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
13902
14194
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -14076,7 +14368,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
14076
14368
|
};
|
|
14077
14369
|
};
|
|
14078
14370
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
14079
|
-
var
|
|
14371
|
+
var escapeHtml21 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14080
14372
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
14081
14373
|
var readinessThresholdRows = (report) => [
|
|
14082
14374
|
{
|
|
@@ -14167,15 +14459,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
14167
14459
|
};
|
|
14168
14460
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
14169
14461
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
14170
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
14171
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
14172
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
14173
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
14462
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml21(row.control)}</td><td>${escapeHtml21(formatMs(row.value))}</td><td>${escapeHtml21(row.usedBy)}</td></tr>`).join("");
|
|
14463
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml21(issue)}</li>`).join("");
|
|
14464
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml21(source)}</code></li>`).join("");
|
|
14465
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml21(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1040px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}.status{font-size:1.6rem;font-weight:800;text-transform:uppercase}</style></head><body><main><h1>${escapeHtml21(title)}</h1><p>This page shows the calibrated thresholds currently driving production readiness gates.</p><section class="summary"><div class="card"><strong>Status</strong><br><span class="status">${escapeHtml21(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml21(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml21(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml21(formatMs(report.bargeIn.thresholdMs))}</div></section><h2>Active Readiness Thresholds</h2><table><thead><tr><th>Threshold</th><th>Active value</th><th>Used by</th></tr></thead><tbody>${rows}</tbody></table><h2>Sources</h2><ul>${sources}</ul><h2>Issues</h2><ul>${issues}</ul></main></body></html>`;
|
|
14174
14466
|
};
|
|
14175
14467
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
14176
14468
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
14177
14469
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
14178
|
-
const routes = new
|
|
14470
|
+
const routes = new Elysia20({
|
|
14179
14471
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
14180
14472
|
});
|
|
14181
14473
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14199,7 +14491,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14199
14491
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
14200
14492
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
14201
14493
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
14202
|
-
const routes = new
|
|
14494
|
+
const routes = new Elysia20({
|
|
14203
14495
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
14204
14496
|
});
|
|
14205
14497
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14233,7 +14525,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14233
14525
|
return routes;
|
|
14234
14526
|
};
|
|
14235
14527
|
// src/liveOps.ts
|
|
14236
|
-
import { Elysia as
|
|
14528
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14237
14529
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
14238
14530
|
"assign",
|
|
14239
14531
|
"create-task",
|
|
@@ -14543,7 +14835,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14543
14835
|
const controller = createVoiceLiveOpsController(options);
|
|
14544
14836
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
14545
14837
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
14546
|
-
return new
|
|
14838
|
+
return new Elysia21({
|
|
14547
14839
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
14548
14840
|
}).post(path, async ({ request, set }) => {
|
|
14549
14841
|
try {
|
|
@@ -14565,15 +14857,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14565
14857
|
});
|
|
14566
14858
|
};
|
|
14567
14859
|
// src/deliveryRuntime.ts
|
|
14568
|
-
import { Elysia as
|
|
14860
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14569
14861
|
import { mkdir } from "fs/promises";
|
|
14570
14862
|
import { dirname, join } from "path";
|
|
14571
|
-
var
|
|
14863
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14572
14864
|
var renderSummaryCard = (label, summary) => {
|
|
14573
14865
|
if (!summary) {
|
|
14574
|
-
return `<article><span>${
|
|
14866
|
+
return `<article><span>${escapeHtml22(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
14575
14867
|
}
|
|
14576
|
-
return `<article><span>${
|
|
14868
|
+
return `<article><span>${escapeHtml22(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending · ${String(summary.failed)} failed · ${String(summary.deadLettered)} dead-lettered</p></article>`;
|
|
14577
14869
|
};
|
|
14578
14870
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
14579
14871
|
audit: leases,
|
|
@@ -14784,9 +15076,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
14784
15076
|
});
|
|
14785
15077
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
14786
15078
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
14787
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
14788
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
14789
|
-
const snippet =
|
|
15079
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml22(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
15080
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml22(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
15081
|
+
const snippet = escapeHtml22(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
14790
15082
|
createVoiceDeliveryRuntimePresetConfig({
|
|
14791
15083
|
audit: {
|
|
14792
15084
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -14812,14 +15104,14 @@ app.use(
|
|
|
14812
15104
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
14813
15105
|
})
|
|
14814
15106
|
);`);
|
|
14815
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15107
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}.primitive{background:#111a15;border-color:#41604a}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}.primitive p{color:#c8d8ca;line-height:1.55}.primitive code{color:#bbf7d0}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml22(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml22(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceDeliveryRuntimeRoutes(...)</code> builds this control plane</h2><p>Own the audit and trace delivery queues in your app, mount one runtime route group, and pass the same runtime into production readiness so failed or dead-lettered exports block deploys.</p><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
14816
15108
|
};
|
|
14817
15109
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
14818
15110
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
14819
15111
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
14820
15112
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
14821
15113
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
14822
|
-
const routes = new
|
|
15114
|
+
const routes = new Elysia22({
|
|
14823
15115
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
14824
15116
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
14825
15117
|
if (tickPath !== false) {
|
|
@@ -14855,7 +15147,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
14855
15147
|
return routes;
|
|
14856
15148
|
};
|
|
14857
15149
|
// src/dataControl.ts
|
|
14858
|
-
import { Elysia as
|
|
15150
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
14859
15151
|
var voiceComplianceRedactionDefaults = {
|
|
14860
15152
|
keys: [
|
|
14861
15153
|
"apiKey",
|
|
@@ -15094,7 +15386,7 @@ var parseRetentionScopes = (value) => {
|
|
|
15094
15386
|
const allowed = new Set(allRetentionScopes);
|
|
15095
15387
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
15096
15388
|
};
|
|
15097
|
-
var
|
|
15389
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15098
15390
|
var buildStorageSurfaces = (options) => [
|
|
15099
15391
|
{
|
|
15100
15392
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -15331,12 +15623,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
15331
15623
|
zeroRetentionAvailable: true
|
|
15332
15624
|
};
|
|
15333
15625
|
};
|
|
15334
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
15626
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml23(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml23(scope.skippedReason ?? "")}</td><td><code>${escapeHtml23(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
15335
15627
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
15336
15628
|
const title = options.title ?? "Voice Data Control";
|
|
15337
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
15338
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
15339
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
15629
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml23(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml23(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
15630
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml23(key.name)}</td><td><code>${escapeHtml23(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml23(key.recommendation)}</td></tr>`).join("");
|
|
15631
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml23(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1120px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml23(title)}</h1><p>Self-hosted data-control proof for retention, redaction, audit export, deletion planning, customer-owned storage, and provider key handling.</p><section class="summary"><div class="card"><strong>Redaction</strong><br>${report.redaction.enabled ? "enabled" : "disabled"}</div><div class="card"><strong>Retention dry-run deletes</strong><br>${report.retentionPlan.deletedCount}</div><div class="card"><strong>Audit export events</strong><br>${report.auditExport?.events.length ?? 0}</div><div class="card"><strong>Zero retention recipe</strong><br>${report.zeroRetentionAvailable ? "available" : "missing"}</div></section><h2>Customer-Owned Storage</h2><table><thead><tr><th>Surface</th><th>Status</th><th>Control</th><th>Self-hosted</th></tr></thead><tbody>${storageRows}</tbody></table><h2>Retention Plan</h2><table><thead><tr><th>Scope</th><th>Scanned</th><th>Would delete</th><th>Skipped</th><th>Ids</th></tr></thead><tbody>${renderDataRetentionReportRows(report.retentionPlan)}</tbody></table><h2>Provider Keys</h2><table><thead><tr><th>Provider</th><th>Env</th><th>Required</th><th>Recommendation</th></tr></thead><tbody>${keyRows}</tbody></table><p><a href="./data-control/audit.md">Redacted audit Markdown</a> \xB7 <a href="./data-control/audit.html">Redacted audit HTML</a></p></main></body></html>`;
|
|
15340
15632
|
};
|
|
15341
15633
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
15342
15634
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -15394,7 +15686,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
15394
15686
|
var createVoiceDataControlRoutes = (options) => {
|
|
15395
15687
|
const path = options.path ?? "/data-control";
|
|
15396
15688
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
15397
|
-
const routes = new
|
|
15689
|
+
const routes = new Elysia23({
|
|
15398
15690
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
15399
15691
|
});
|
|
15400
15692
|
routes.get(path, async ({ query }) => {
|
|
@@ -15470,16 +15762,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
15470
15762
|
return routes;
|
|
15471
15763
|
};
|
|
15472
15764
|
// src/evalRoutes.ts
|
|
15473
|
-
import { Elysia as
|
|
15765
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
15474
15766
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
15475
15767
|
import { dirname as dirname2 } from "path";
|
|
15476
15768
|
|
|
15477
15769
|
// src/qualityRoutes.ts
|
|
15478
|
-
import { Elysia as
|
|
15770
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15479
15771
|
|
|
15480
15772
|
// src/handoffHealth.ts
|
|
15481
|
-
import { Elysia as
|
|
15482
|
-
var
|
|
15773
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15774
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15483
15775
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15484
15776
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
15485
15777
|
var increment3 = (record, key) => {
|
|
@@ -15597,10 +15889,10 @@ var renderActionSummary = (summary) => {
|
|
|
15597
15889
|
return [
|
|
15598
15890
|
'<section class="voice-handoff-health-columns">',
|
|
15599
15891
|
"<article><h3>Actions</h3>",
|
|
15600
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
15892
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml24(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
15601
15893
|
"</article>",
|
|
15602
15894
|
"<article><h3>Adapters</h3>",
|
|
15603
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
15895
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml24(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
15604
15896
|
"</article>",
|
|
15605
15897
|
"</section>"
|
|
15606
15898
|
].join("");
|
|
@@ -15614,22 +15906,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
15614
15906
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
15615
15907
|
'<div class="voice-handoff-health-events">',
|
|
15616
15908
|
...summary.events.map((event) => [
|
|
15617
|
-
`<article class="${
|
|
15909
|
+
`<article class="${escapeHtml24(event.status)}">`,
|
|
15618
15910
|
'<div class="voice-handoff-health-event-header">',
|
|
15619
|
-
`<strong>${
|
|
15620
|
-
`<span>${
|
|
15911
|
+
`<strong>${escapeHtml24(event.action ?? "handoff")}</strong>`,
|
|
15912
|
+
`<span>${escapeHtml24(event.status)}</span>`,
|
|
15621
15913
|
"</div>",
|
|
15622
|
-
`<p><small>${
|
|
15623
|
-
event.target ? `<p>Target: ${
|
|
15624
|
-
event.reason ? `<p>Reason: ${
|
|
15914
|
+
`<p><small>${escapeHtml24(event.sessionId)}</small></p>`,
|
|
15915
|
+
event.target ? `<p>Target: ${escapeHtml24(event.target)}</p>` : "",
|
|
15916
|
+
event.reason ? `<p>Reason: ${escapeHtml24(event.reason)}</p>` : "",
|
|
15625
15917
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
15626
15918
|
"<li>",
|
|
15627
|
-
`${
|
|
15628
|
-
delivery.deliveredTo ? ` to ${
|
|
15629
|
-
delivery.error ? ` (${
|
|
15919
|
+
`${escapeHtml24(delivery.adapterId)}: ${escapeHtml24(delivery.status)}`,
|
|
15920
|
+
delivery.deliveredTo ? ` to ${escapeHtml24(delivery.deliveredTo)}` : "",
|
|
15921
|
+
delivery.error ? ` (${escapeHtml24(delivery.error)})` : "",
|
|
15630
15922
|
"</li>"
|
|
15631
15923
|
].join("")).join("")}</ul>` : "",
|
|
15632
|
-
event.replayHref ? `<p><a href="${
|
|
15924
|
+
event.replayHref ? `<p><a href="${escapeHtml24(event.replayHref)}">Open replay</a></p>` : "",
|
|
15633
15925
|
"</article>"
|
|
15634
15926
|
].join("")),
|
|
15635
15927
|
"</div>"
|
|
@@ -15661,7 +15953,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
15661
15953
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
15662
15954
|
const path = options.path ?? "/api/voice-handoffs";
|
|
15663
15955
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
15664
|
-
const routes = new
|
|
15956
|
+
const routes = new Elysia24({
|
|
15665
15957
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
15666
15958
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
15667
15959
|
if (htmlPath) {
|
|
@@ -15782,17 +16074,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
15782
16074
|
thresholds
|
|
15783
16075
|
};
|
|
15784
16076
|
};
|
|
15785
|
-
var
|
|
16077
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15786
16078
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
15787
16079
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
15788
16080
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
15789
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
15790
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16081
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml25(metric.label)}</td><td>${escapeHtml25(formatMetricValue(metric))}</td><td>${escapeHtml25(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml25(key)}</code></td></tr>`).join("");
|
|
16082
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15791
16083
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>AbsoluteJS Voice Quality</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}nav{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 1.25rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;padding:.35rem .75rem;font-weight:800}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}table{border-collapse:collapse;width:100%;background:white;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}.pass td{border-left:4px solid #16a34a}.fail td{border-left:4px solid #dc2626}code{background:#f3f4f6;padding:.15rem .3rem;border-radius:.3rem}</style></head><body><main>${links}<h1>Voice quality gates</h1><p class="status ${report.status}">${report.status}</p><p>${report.eventCount} event(s) checked.</p><table><thead><tr><th>Metric</th><th>Actual</th><th>Threshold</th><th>Status</th><th>Key</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
15792
16084
|
};
|
|
15793
16085
|
var createVoiceQualityRoutes = (options) => {
|
|
15794
16086
|
const path = options.path ?? "/quality";
|
|
15795
|
-
const routes = new
|
|
16087
|
+
const routes = new Elysia25({
|
|
15796
16088
|
name: options.name ?? "absolutejs-voice-quality"
|
|
15797
16089
|
});
|
|
15798
16090
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -15821,7 +16113,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
15821
16113
|
};
|
|
15822
16114
|
|
|
15823
16115
|
// src/evalRoutes.ts
|
|
15824
|
-
var
|
|
16116
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15825
16117
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
15826
16118
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
15827
16119
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -16143,7 +16435,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
16143
16435
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
16144
16436
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
16145
16437
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
16146
|
-
const snippet =
|
|
16438
|
+
const snippet = escapeHtml26(`app.use(
|
|
16147
16439
|
createVoiceEvalRoutes({
|
|
16148
16440
|
path: '/evals',
|
|
16149
16441
|
store: traceStore,
|
|
@@ -16164,48 +16456,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
16164
16456
|
};
|
|
16165
16457
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
16166
16458
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
16167
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16168
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
16459
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16460
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml26(bucket.key)}</td><td>${bucket.total}</td><td>${bucket.passed}</td><td>${bucket.failed}</td></tr>`).join("") : '<tr><td colspan="4">No eval buckets yet.</td></tr>';
|
|
16169
16461
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
16170
16462
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
16171
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16172
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16463
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml26(session.operationsRecordHref)}">${escapeHtml26(session.sessionId)}</a>` : escapeHtml26(session.sessionId);
|
|
16464
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml26(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml26(formatTime(session.endedAt))}</td><td>${escapeHtml26(failedMetrics || "none")}</td></tr>`;
|
|
16173
16465
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
16174
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16466
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,.primitive{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3;margin:1rem 0}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}<h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
16175
16467
|
};
|
|
16176
16468
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
16177
16469
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
16178
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16179
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
16180
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
16181
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
16182
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16470
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16471
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml26(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
16472
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml26(id)}</li>`).join("") : "<li>none</li>";
|
|
16473
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml26(id)}</li>`).join("") : "<li>none</li>";
|
|
16474
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1000px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{background:#dcfce7;color:#166534}.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{background:white;border:1px solid #e7e5e4;border-radius:1rem;margin:1rem 0;padding:1rem}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml26(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml26(formatPercent(comparison.current.passRate))}</strong></article><article class="card"><span>Failed delta</span><strong>${comparison.deltas.failed}</strong></article><article class="card"><span>Pass rate delta</span><strong>${escapeHtml26(formatPercent(comparison.deltas.passRate))}</strong></article></div><section><h2>Regression Reasons</h2><ul>${reasons}</ul></section><section><h2>New Failed Sessions</h2><ul>${newFailures}</ul></section><section><h2>Recovered Sessions</h2><ul>${recovered}</ul></section></main></body></html>`;
|
|
16183
16475
|
};
|
|
16184
16476
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
16185
16477
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
16186
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16478
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16187
16479
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
16188
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
16480
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml26(issue)}</li>`).join("")}</ul>` : "";
|
|
16189
16481
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
16190
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16191
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16482
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml26(session.operationsRecordHref)}">${escapeHtml26(session.sessionId)}</a>` : escapeHtml26(session.sessionId);
|
|
16483
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml26(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml26(session.issues.join(", ") || "none")}</td></tr>`;
|
|
16192
16484
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
16193
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
16485
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml26(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml26(scenario.description)}</p>` : ""}<p class="status ${scenario.status}">${scenario.status}</p><p>${scenario.passed} passed, ${scenario.failed} failed, ${scenario.matchedSessions} matched.</p>${scenarioIssues}<table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Issues</th></tr></thead><tbody>${sessions}</tbody></table></section>`;
|
|
16194
16486
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
16195
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16487
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${scenarios}</main></body></html>`;
|
|
16196
16488
|
};
|
|
16197
16489
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
16198
16490
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
16199
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16491
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml26(link.href)}">${escapeHtml26(link.label)}</a>`).join("")}</nav>` : "";
|
|
16200
16492
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
16201
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
16202
|
-
return `<section class="${fixture.status}"><h2>${
|
|
16493
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml26(scenario.label)}</td><td>${escapeHtml26(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml26([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
16494
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml26(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml26(fixture.description)}</p>` : ""}<p class="status ${fixture.status}">${fixture.status}</p><table><thead><tr><th>Scenario</th><th>Status</th><th>Sessions</th><th>Issues</th></tr></thead><tbody>${scenarios}</tbody></table></section>`;
|
|
16203
16495
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
16204
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16496
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml26(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${fixtures}</main></body></html>`;
|
|
16205
16497
|
};
|
|
16206
16498
|
var createVoiceEvalRoutes = (options) => {
|
|
16207
16499
|
const path = options.path ?? "/evals";
|
|
16208
|
-
const routes = new
|
|
16500
|
+
const routes = new Elysia26({
|
|
16209
16501
|
name: options.name ?? "absolutejs-voice-evals"
|
|
16210
16502
|
});
|
|
16211
16503
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -16342,11 +16634,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
16342
16634
|
return routes;
|
|
16343
16635
|
};
|
|
16344
16636
|
// src/simulationSuite.ts
|
|
16345
|
-
import { Elysia as
|
|
16637
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
16346
16638
|
|
|
16347
16639
|
// src/outcomeContract.ts
|
|
16348
|
-
import { Elysia as
|
|
16349
|
-
var
|
|
16640
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16641
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16350
16642
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
16351
16643
|
if (value === false) {
|
|
16352
16644
|
return;
|
|
@@ -16557,13 +16849,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
16557
16849
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
16558
16850
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
16559
16851
|
const contracts = report.contracts.map((contract) => {
|
|
16560
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
16852
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml27(href)}">${escapeHtml27(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
16561
16853
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16562
16854
|
<div class="contract-header">
|
|
16563
16855
|
<div>
|
|
16564
|
-
<p class="eyebrow">${
|
|
16565
|
-
<h2>${
|
|
16566
|
-
${contract.description ? `<p>${
|
|
16856
|
+
<p class="eyebrow">${escapeHtml27(contract.contractId)}</p>
|
|
16857
|
+
<h2>${escapeHtml27(contract.label ?? contract.contractId)}</h2>
|
|
16858
|
+
${contract.description ? `<p>${escapeHtml27(contract.description)}</p>` : ""}
|
|
16567
16859
|
${sessionLinks}
|
|
16568
16860
|
</div>
|
|
16569
16861
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -16575,10 +16867,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
16575
16867
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
16576
16868
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
16577
16869
|
</div>
|
|
16578
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
16870
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml27(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
16579
16871
|
</section>`;
|
|
16580
16872
|
}).join("");
|
|
16581
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16873
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml27(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(14,165,233,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary,.grid{display:flex;flex-wrap:wrap;gap:10px}.pill,.grid span{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}li{margin:8px 0}@media(max-width:800px){main{padding:18px}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Business Outcome Verification</p><h1>${escapeHtml27(title)}</h1><div class="summary"><span class="pill ${report.status}">${report.status}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No outcome contracts configured.</p></section>'}</main></body></html>`;
|
|
16582
16874
|
};
|
|
16583
16875
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
16584
16876
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -16594,7 +16886,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
16594
16886
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
16595
16887
|
const path = options.path ?? "/api/outcome-contracts";
|
|
16596
16888
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16597
|
-
const routes = new
|
|
16889
|
+
const routes = new Elysia27({
|
|
16598
16890
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
16599
16891
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
16600
16892
|
if (htmlPath) {
|
|
@@ -16604,7 +16896,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
16604
16896
|
};
|
|
16605
16897
|
|
|
16606
16898
|
// src/toolContract.ts
|
|
16607
|
-
import { Elysia as
|
|
16899
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16608
16900
|
|
|
16609
16901
|
// src/toolRuntime.ts
|
|
16610
16902
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -16813,7 +17105,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
16813
17105
|
});
|
|
16814
17106
|
var defaultApi = {};
|
|
16815
17107
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
16816
|
-
var
|
|
17108
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16817
17109
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
16818
17110
|
if (value === false) {
|
|
16819
17111
|
return;
|
|
@@ -17062,7 +17354,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
17062
17354
|
};
|
|
17063
17355
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
17064
17356
|
const title = options.title ?? "Voice Tool Contracts";
|
|
17065
|
-
const snippet =
|
|
17357
|
+
const snippet = escapeHtml28(`app.use(
|
|
17066
17358
|
createVoiceToolContractRoutes({
|
|
17067
17359
|
htmlPath: '/tool-contracts',
|
|
17068
17360
|
path: '/api/tool-contracts',
|
|
@@ -17088,20 +17380,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17088
17380
|
);`);
|
|
17089
17381
|
const contracts = report.contracts.map((contract) => {
|
|
17090
17382
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
17091
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
17383
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml28(testCase.operationsRecordHref)}">${escapeHtml28(testCase.label ?? testCase.caseId)}</a>` : escapeHtml28(testCase.label ?? testCase.caseId)}</td>
|
|
17092
17384
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
17093
|
-
<td>${
|
|
17094
|
-
<td>${
|
|
17385
|
+
<td>${escapeHtml28(testCase.status)}</td>
|
|
17386
|
+
<td>${escapeHtml28(testCase.sessionId)}</td>
|
|
17095
17387
|
<td>${String(testCase.attempts)}</td>
|
|
17096
17388
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
17097
17389
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
17098
|
-
<td>${
|
|
17390
|
+
<td>${escapeHtml28(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
17099
17391
|
</tr>`).join("");
|
|
17100
17392
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17101
17393
|
<div class="contract-header">
|
|
17102
17394
|
<div>
|
|
17103
|
-
<p class="eyebrow">${
|
|
17104
|
-
<h2>${
|
|
17395
|
+
<p class="eyebrow">${escapeHtml28(contract.toolName)}</p>
|
|
17396
|
+
<h2>${escapeHtml28(contract.label ?? contract.contractId)}</h2>
|
|
17105
17397
|
</div>
|
|
17106
17398
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
17107
17399
|
</div>
|
|
@@ -17111,7 +17403,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17111
17403
|
</table>
|
|
17112
17404
|
</section>`;
|
|
17113
17405
|
}).join("");
|
|
17114
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17406
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.primitive{background:#151b20;border-color:#5a4421}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}.primitive p{color:#d8dee6;line-height:1.55}.primitive pre{background:#0f1217;border:1px solid #2a323a;border-radius:16px;color:#fef3c7;overflow:auto;padding:14px}.primitive code{color:#fef3c7}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml28(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml28(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceToolContractRoutes(...)</code> certifies tool behavior</h2><p>Define deterministic tool cases for retries, idempotency, timeouts, result shape, and error handling so assistant tools fail in pre-production instead of live calls.</p><pre><code>${snippet}</code></pre></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
|
|
17115
17407
|
};
|
|
17116
17408
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
17117
17409
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -17128,7 +17420,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
17128
17420
|
var createVoiceToolContractRoutes = (options) => {
|
|
17129
17421
|
const path = options.path ?? "/api/tool-contracts";
|
|
17130
17422
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17131
|
-
const routes = new
|
|
17423
|
+
const routes = new Elysia28({
|
|
17132
17424
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
17133
17425
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
17134
17426
|
if (htmlPath) {
|
|
@@ -17138,7 +17430,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
17138
17430
|
};
|
|
17139
17431
|
|
|
17140
17432
|
// src/simulationSuite.ts
|
|
17141
|
-
var
|
|
17433
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17142
17434
|
var summarizeSection = (report) => ({
|
|
17143
17435
|
failed: report.failed,
|
|
17144
17436
|
passed: report.passed,
|
|
@@ -17334,15 +17626,15 @@ var renderSection = (label, summary) => {
|
|
|
17334
17626
|
if (!summary) {
|
|
17335
17627
|
return "";
|
|
17336
17628
|
}
|
|
17337
|
-
return `<article class="${
|
|
17629
|
+
return `<article class="${escapeHtml29(summary.status)}"><span>${escapeHtml29(label)}</span><strong>${escapeHtml29(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
17338
17630
|
};
|
|
17339
17631
|
var renderAction = (action) => {
|
|
17340
|
-
const content = `<strong>${
|
|
17341
|
-
return action.href ? `<a class="action" href="${
|
|
17632
|
+
const content = `<strong>${escapeHtml29(action.label)}</strong><p>${escapeHtml29(action.description)}</p><span>${escapeHtml29(action.section)} / ${escapeHtml29(action.severity)}</span>`;
|
|
17633
|
+
return action.href ? `<a class="action" href="${escapeHtml29(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
17342
17634
|
};
|
|
17343
17635
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
17344
17636
|
const title = options.title ?? "Voice Simulation Suite";
|
|
17345
|
-
const snippet =
|
|
17637
|
+
const snippet = escapeHtml29(`app.use(
|
|
17346
17638
|
createVoiceSimulationSuiteRoutes({
|
|
17347
17639
|
htmlPath: '/voice/simulations',
|
|
17348
17640
|
path: '/api/voice/simulations',
|
|
@@ -17375,12 +17667,12 @@ app.use(
|
|
|
17375
17667
|
store: traceStore
|
|
17376
17668
|
})
|
|
17377
17669
|
);`);
|
|
17378
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17670
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml29(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#355078}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p,.primitive p{color:#d8dee6;line-height:1.55;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}.primitive pre{background:#0b1118;color:#dbeafe}.primitive code{color:#bfdbfe}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml29(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml29(report.status)}">Status: ${escapeHtml29(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceSimulationSuiteRoutes(...)</code> builds this pre-production proof surface</h2><p>Run session quality checks, scenario evals, fixture-backed simulations, tool contracts, and outcome contracts from one route group before live traffic sees a regression.</p><pre><code>${snippet}</code></pre></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml29(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
17379
17671
|
};
|
|
17380
17672
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
17381
17673
|
const path = options.path ?? "/api/voice/simulations";
|
|
17382
17674
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
17383
|
-
const app = new
|
|
17675
|
+
const app = new Elysia29({
|
|
17384
17676
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
17385
17677
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
17386
17678
|
if (htmlPath) {
|
|
@@ -17692,9 +17984,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
17692
17984
|
};
|
|
17693
17985
|
};
|
|
17694
17986
|
// src/sessionReplay.ts
|
|
17695
|
-
import { Elysia as
|
|
17987
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
17696
17988
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
17697
|
-
var
|
|
17989
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17698
17990
|
var increment4 = (record, key) => {
|
|
17699
17991
|
record[key] = (record[key] ?? 0) + 1;
|
|
17700
17992
|
};
|
|
@@ -17888,10 +18180,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
17888
18180
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
17889
18181
|
'<div class="voice-sessions-list">',
|
|
17890
18182
|
...sessions.map((session) => [
|
|
17891
|
-
`<article class="voice-session-card ${
|
|
18183
|
+
`<article class="voice-session-card ${escapeHtml30(session.status)}">`,
|
|
17892
18184
|
'<div class="voice-session-card-header">',
|
|
17893
|
-
`<strong>${
|
|
17894
|
-
`<span>${
|
|
18185
|
+
`<strong>${escapeHtml30(session.sessionId)}</strong>`,
|
|
18186
|
+
`<span>${escapeHtml30(session.status)}</span>`,
|
|
17895
18187
|
"</div>",
|
|
17896
18188
|
"<dl>",
|
|
17897
18189
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -17899,9 +18191,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
17899
18191
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
17900
18192
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
17901
18193
|
"</dl>",
|
|
17902
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
17903
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
17904
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
18194
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml30(session.latestOutcome)}</p>` : "",
|
|
18195
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml30).join(", ")}</p>` : "",
|
|
18196
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml30(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml30(session.replayHref)}">Open replay</a></p>` : "",
|
|
17905
18197
|
"</article>"
|
|
17906
18198
|
].join("")),
|
|
17907
18199
|
"</div>"
|
|
@@ -17932,7 +18224,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
17932
18224
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
17933
18225
|
const path = options.path ?? "/api/voice-sessions";
|
|
17934
18226
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17935
|
-
const routes = new
|
|
18227
|
+
const routes = new Elysia30({
|
|
17936
18228
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
17937
18229
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
17938
18230
|
if (htmlPath) {
|
|
@@ -17960,7 +18252,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
17960
18252
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
17961
18253
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
17962
18254
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17963
|
-
const routes = new
|
|
18255
|
+
const routes = new Elysia30({
|
|
17964
18256
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
17965
18257
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
17966
18258
|
if (htmlPath) {
|
|
@@ -18274,10 +18566,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
18274
18566
|
return report;
|
|
18275
18567
|
};
|
|
18276
18568
|
// src/turnLatency.ts
|
|
18277
|
-
import { Elysia as
|
|
18569
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
18278
18570
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
18279
18571
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
18280
|
-
var
|
|
18572
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18281
18573
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18282
18574
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
18283
18575
|
var createTraceStageIndex = (events) => {
|
|
@@ -18409,11 +18701,11 @@ await traceStore.append({
|
|
|
18409
18701
|
turnId,
|
|
18410
18702
|
type: 'turn_latency.stage'
|
|
18411
18703
|
});`;
|
|
18412
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18413
|
-
<header><div><p class="eyebrow">${
|
|
18414
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
18704
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml31(turn.status)}">
|
|
18705
|
+
<header><div><p class="eyebrow">${escapeHtml31(turn.sessionId)} \xB7 ${escapeHtml31(turn.turnId)}</p><h2>${escapeHtml31(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml31(turn.status)}</strong></header>
|
|
18706
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml31(stage.label)}</dt><dd>${escapeHtml31(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
18415
18707
|
</article>`).join("");
|
|
18416
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18708
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn,.primitive{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml31(title)}</h1><div class="summary"><span class="pill ${escapeHtml31(report.status)}">${escapeHtml31(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml31(formatMs2(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml31(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
18417
18709
|
};
|
|
18418
18710
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
18419
18711
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -18430,7 +18722,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
18430
18722
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
18431
18723
|
const path = options.path ?? "/api/turn-latency";
|
|
18432
18724
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18433
|
-
const routes = new
|
|
18725
|
+
const routes = new Elysia31({
|
|
18434
18726
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
18435
18727
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
18436
18728
|
if (htmlPath) {
|
|
@@ -18439,8 +18731,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
18439
18731
|
return routes;
|
|
18440
18732
|
};
|
|
18441
18733
|
// src/liveLatency.ts
|
|
18442
|
-
import { Elysia as
|
|
18443
|
-
var
|
|
18734
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
18735
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18444
18736
|
var percentile3 = (values, percentileValue) => {
|
|
18445
18737
|
if (values.length === 0) {
|
|
18446
18738
|
return;
|
|
@@ -18507,13 +18799,13 @@ await traceStore.append({
|
|
|
18507
18799
|
sessionId,
|
|
18508
18800
|
type: 'client.live_latency'
|
|
18509
18801
|
});`;
|
|
18510
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
18511
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18802
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml32(sample.sessionId)}</td><td>${escapeHtml32(formatMs3(sample.latencyMs))}</td><td>${escapeHtml32(sample.status ?? "unknown")}</td><td>${escapeHtml32(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
18803
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml32(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml32(report.status)}">Status: ${escapeHtml32(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml32(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml32(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml32(formatMs3(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml32(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
18512
18804
|
};
|
|
18513
18805
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
18514
18806
|
const path = options.path ?? "/api/live-latency";
|
|
18515
18807
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
18516
|
-
const routes = new
|
|
18808
|
+
const routes = new Elysia32({
|
|
18517
18809
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
18518
18810
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
18519
18811
|
if (htmlPath) {
|
|
@@ -18832,9 +19124,9 @@ None.
|
|
|
18832
19124
|
`}`;
|
|
18833
19125
|
};
|
|
18834
19126
|
// src/turnQuality.ts
|
|
18835
|
-
import { Elysia as
|
|
19127
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18836
19128
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
18837
|
-
var
|
|
19129
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18838
19130
|
var getTurnLatencyMs = (turn) => {
|
|
18839
19131
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18840
19132
|
if (firstTranscriptAt === undefined) {
|
|
@@ -18905,24 +19197,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
18905
19197
|
};
|
|
18906
19198
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
18907
19199
|
const title = options.title ?? "Voice Turn Quality";
|
|
18908
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19200
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml33(turn.status)}">
|
|
18909
19201
|
<div class="turn-header">
|
|
18910
19202
|
<div>
|
|
18911
|
-
<p class="eyebrow">${
|
|
18912
|
-
<h2>${
|
|
19203
|
+
<p class="eyebrow">${escapeHtml33(turn.sessionId)} \xB7 ${escapeHtml33(turn.turnId)}</p>
|
|
19204
|
+
<h2>${escapeHtml33(turn.text || "Empty turn")}</h2>
|
|
18913
19205
|
</div>
|
|
18914
|
-
<strong>${
|
|
19206
|
+
<strong>${escapeHtml33(turn.status)}</strong>
|
|
18915
19207
|
</div>
|
|
18916
19208
|
<dl>
|
|
18917
|
-
<div><dt>Source</dt><dd>${
|
|
19209
|
+
<div><dt>Source</dt><dd>${escapeHtml33(turn.source ?? "unknown")}</dd></div>
|
|
18918
19210
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
18919
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
18920
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
19211
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml33(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
19212
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml33(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
18921
19213
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
18922
19214
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
18923
19215
|
</dl>
|
|
18924
19216
|
</article>`).join("");
|
|
18925
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19217
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.unknown{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml33(title)}</h1><div class="summary"><span class="pill ${escapeHtml33(report.status)}">${escapeHtml33(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
18926
19218
|
};
|
|
18927
19219
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
18928
19220
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -18939,7 +19231,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
18939
19231
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
18940
19232
|
const path = options.path ?? "/api/turn-quality";
|
|
18941
19233
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18942
|
-
const routes = new
|
|
19234
|
+
const routes = new Elysia33({
|
|
18943
19235
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
18944
19236
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
18945
19237
|
if (htmlPath) {
|
|
@@ -18948,7 +19240,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
18948
19240
|
return routes;
|
|
18949
19241
|
};
|
|
18950
19242
|
// src/telephonyOutcome.ts
|
|
18951
|
-
import { Elysia as
|
|
19243
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
18952
19244
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
18953
19245
|
"answered",
|
|
18954
19246
|
"completed",
|
|
@@ -19709,7 +20001,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
19709
20001
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
19710
20002
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
19711
20003
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
19712
|
-
return new
|
|
20004
|
+
return new Elysia34({
|
|
19713
20005
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
19714
20006
|
}).post(path, async ({ query, request }) => {
|
|
19715
20007
|
try {
|
|
@@ -19730,12 +20022,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
19730
20022
|
});
|
|
19731
20023
|
};
|
|
19732
20024
|
// src/phoneAgent.ts
|
|
19733
|
-
import { Elysia as
|
|
20025
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
19734
20026
|
|
|
19735
20027
|
// src/telephony/plivo.ts
|
|
19736
20028
|
import { Buffer as Buffer5 } from "buffer";
|
|
19737
20029
|
import { Database } from "bun:sqlite";
|
|
19738
|
-
import { Elysia as
|
|
20030
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
19739
20031
|
|
|
19740
20032
|
// src/telephony/contract.ts
|
|
19741
20033
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -19819,7 +20111,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
19819
20111
|
|
|
19820
20112
|
// src/telephony/twilio.ts
|
|
19821
20113
|
import { Buffer as Buffer4 } from "buffer";
|
|
19822
|
-
import { Elysia as
|
|
20114
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19823
20115
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
19824
20116
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
19825
20117
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -19849,7 +20141,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
19849
20141
|
return parameters;
|
|
19850
20142
|
};
|
|
19851
20143
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19852
|
-
var
|
|
20144
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19853
20145
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
19854
20146
|
if (!webhook?.verificationUrl) {
|
|
19855
20147
|
return;
|
|
@@ -19892,23 +20184,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
19892
20184
|
};
|
|
19893
20185
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19894
20186
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
19895
|
-
<h1>${
|
|
20187
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
19896
20188
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
19897
20189
|
<section>
|
|
19898
20190
|
<h2>URLs</h2>
|
|
19899
20191
|
<ul>
|
|
19900
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19901
|
-
<li><strong>Media stream:</strong> <code>${
|
|
19902
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
20192
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml34(status.urls.twiml)}</code></li>
|
|
20193
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml34(status.urls.stream)}</code></li>
|
|
20194
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml34(status.urls.webhook)}</code></li>
|
|
19903
20195
|
</ul>
|
|
19904
20196
|
</section>
|
|
19905
20197
|
<section>
|
|
19906
20198
|
<h2>Signing</h2>
|
|
19907
20199
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
19908
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
20200
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml34(status.signing.verificationUrl)}</code></p>` : ""}
|
|
19909
20201
|
</section>
|
|
19910
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
19911
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
20202
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml34(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
20203
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml34(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
19912
20204
|
</main>`;
|
|
19913
20205
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
19914
20206
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -19919,20 +20211,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
19919
20211
|
});
|
|
19920
20212
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19921
20213
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
19922
|
-
<h1>${
|
|
20214
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
19923
20215
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
19924
20216
|
<section>
|
|
19925
20217
|
<h2>Checks</h2>
|
|
19926
20218
|
<ul>
|
|
19927
|
-
${report.checks.map((check) => `<li><strong>${
|
|
20219
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml34(check.name)}</strong>: ${escapeHtml34(check.status)}${check.message ? ` - ${escapeHtml34(check.message)}` : ""}</li>`).join("")}
|
|
19928
20220
|
</ul>
|
|
19929
20221
|
</section>
|
|
19930
20222
|
<section>
|
|
19931
20223
|
<h2>Observed URLs</h2>
|
|
19932
20224
|
<ul>
|
|
19933
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19934
|
-
<li><strong>Stream:</strong> <code>${
|
|
19935
|
-
<li><strong>Webhook:</strong> <code>${
|
|
20225
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml34(report.setup.urls.twiml)}</code></li>
|
|
20226
|
+
<li><strong>Stream:</strong> <code>${escapeHtml34(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
20227
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml34(report.setup.urls.webhook)}</code></li>
|
|
19936
20228
|
</ul>
|
|
19937
20229
|
</section>
|
|
19938
20230
|
</main>`;
|
|
@@ -20392,7 +20684,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20392
20684
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
20393
20685
|
const bridges = new WeakMap;
|
|
20394
20686
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
20395
|
-
const app = new
|
|
20687
|
+
const app = new Elysia35({
|
|
20396
20688
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
20397
20689
|
}).get(twimlPath, async ({ query, request }) => {
|
|
20398
20690
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -20529,7 +20821,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20529
20821
|
|
|
20530
20822
|
// src/telephony/plivo.ts
|
|
20531
20823
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20532
|
-
var
|
|
20824
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20533
20825
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20534
20826
|
var resolveRequestOrigin2 = (request) => {
|
|
20535
20827
|
const url = new URL(request.url);
|
|
@@ -20959,21 +21251,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
20959
21251
|
};
|
|
20960
21252
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20961
21253
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
20962
|
-
<h1>${
|
|
21254
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
20963
21255
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20964
21256
|
<ul>
|
|
20965
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
20966
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
20967
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21257
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml35(status.urls.answer)}</code></li>
|
|
21258
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml35(status.urls.stream)}</code></li>
|
|
21259
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml35(status.urls.webhook)}</code></li>
|
|
20968
21260
|
</ul>
|
|
20969
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20970
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21261
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml35(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21262
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml35(warning)}</li>`).join("")}</ul>` : ""}
|
|
20971
21263
|
</main>`;
|
|
20972
21264
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20973
21265
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
20974
|
-
<h1>${
|
|
21266
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
20975
21267
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20976
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21268
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml35(check.name)}</strong>: ${escapeHtml35(check.status)}${check.message ? ` - ${escapeHtml35(check.message)}` : ""}</li>`).join("")}</ul>
|
|
20977
21269
|
</main>`;
|
|
20978
21270
|
var runPlivoSmokeTest = async (input) => {
|
|
20979
21271
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -21063,7 +21355,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21063
21355
|
nonceStore: options.webhook.nonceStore,
|
|
21064
21356
|
verificationUrl: options.webhook.verificationUrl
|
|
21065
21357
|
}) : undefined);
|
|
21066
|
-
const app = new
|
|
21358
|
+
const app = new Elysia36({
|
|
21067
21359
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
21068
21360
|
}).get(answerPath, async ({ query, request }) => {
|
|
21069
21361
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -21175,9 +21467,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21175
21467
|
// src/telephony/telnyx.ts
|
|
21176
21468
|
import { Buffer as Buffer6 } from "buffer";
|
|
21177
21469
|
import { Database as Database2 } from "bun:sqlite";
|
|
21178
|
-
import { Elysia as
|
|
21470
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
21179
21471
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21180
|
-
var
|
|
21472
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21181
21473
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21182
21474
|
var resolveRequestOrigin3 = (request) => {
|
|
21183
21475
|
const url = new URL(request.url);
|
|
@@ -21570,21 +21862,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
21570
21862
|
};
|
|
21571
21863
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21572
21864
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
21573
|
-
<h1>${
|
|
21865
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
21574
21866
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21575
21867
|
<ul>
|
|
21576
|
-
<li><strong>TeXML:</strong> <code>${
|
|
21577
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21578
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21868
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml36(status.urls.texml)}</code></li>
|
|
21869
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml36(status.urls.stream)}</code></li>
|
|
21870
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml36(status.urls.webhook)}</code></li>
|
|
21579
21871
|
</ul>
|
|
21580
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21581
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21872
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml36(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21873
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml36(warning)}</li>`).join("")}</ul>` : ""}
|
|
21582
21874
|
</main>`;
|
|
21583
21875
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21584
21876
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
21585
|
-
<h1>${
|
|
21877
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
21586
21878
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21587
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21879
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml36(check.name)}</strong>: ${escapeHtml36(check.status)}${check.message ? ` - ${escapeHtml36(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21588
21880
|
</main>`;
|
|
21589
21881
|
var runTelnyxSmokeTest = async (input) => {
|
|
21590
21882
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -21677,7 +21969,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21677
21969
|
publicKey: options.webhook.publicKey,
|
|
21678
21970
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
21679
21971
|
}) : undefined);
|
|
21680
|
-
const app = new
|
|
21972
|
+
const app = new Elysia37({
|
|
21681
21973
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
21682
21974
|
}).get(texmlPath, async ({ query, request }) => {
|
|
21683
21975
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -21787,8 +22079,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21787
22079
|
};
|
|
21788
22080
|
|
|
21789
22081
|
// src/telephony/matrix.ts
|
|
21790
|
-
import { Elysia as
|
|
21791
|
-
var
|
|
22082
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
22083
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21792
22084
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
21793
22085
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
21794
22086
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -21849,13 +22141,13 @@ var badgeStyles = {
|
|
|
21849
22141
|
};
|
|
21850
22142
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
21851
22143
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
21852
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
22144
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml37(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
21853
22145
|
<p style="color:#52606d; margin: 0 0 24px;">${matrix.summary.ready}/${matrix.summary.providers} ready, ${matrix.summary.contractsPassing}/${matrix.summary.providers} contract passing, ${matrix.summary.smokePassing}/${matrix.summary.providers} smoke passing.</p>
|
|
21854
22146
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
21855
22147
|
${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; border-radius:18px; padding:18px; background:#fff; box-shadow:0 18px 48px rgba(15,23,42,.08);">
|
|
21856
22148
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
21857
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
21858
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
22149
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml37(entry.name)}</h2>
|
|
22150
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml37(entry.status.toUpperCase())}</span>
|
|
21859
22151
|
</div>
|
|
21860
22152
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
21861
22153
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -21863,15 +22155,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
21863
22155
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
21864
22156
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
21865
22157
|
</dl>
|
|
21866
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
21867
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
21868
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
22158
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml37(entry.setup.urls.stream || "missing")}</code></p>
|
|
22159
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml37(entry.setup.urls.webhook || "missing")}</code></p>
|
|
22160
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml37(issue.severity)}: ${escapeHtml37(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
21869
22161
|
</article>`).join("")}
|
|
21870
22162
|
</section>
|
|
21871
22163
|
</main>`;
|
|
21872
22164
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
21873
22165
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
21874
|
-
return new
|
|
22166
|
+
return new Elysia38({
|
|
21875
22167
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
21876
22168
|
}).get(path, async ({ query, request }) => {
|
|
21877
22169
|
const providers = await options.load({ query, request });
|
|
@@ -21893,7 +22185,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
21893
22185
|
};
|
|
21894
22186
|
|
|
21895
22187
|
// src/phoneAgentProductionSmoke.ts
|
|
21896
|
-
import { Elysia as
|
|
22188
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
21897
22189
|
var defaultRequirements = [
|
|
21898
22190
|
"media-started",
|
|
21899
22191
|
"transcript",
|
|
@@ -21901,7 +22193,7 @@ var defaultRequirements = [
|
|
|
21901
22193
|
"lifecycle-outcome",
|
|
21902
22194
|
"no-session-error"
|
|
21903
22195
|
];
|
|
21904
|
-
var
|
|
22196
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21905
22197
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
21906
22198
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
21907
22199
|
const value = event.payload[key];
|
|
@@ -22010,10 +22302,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
22010
22302
|
});
|
|
22011
22303
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
22012
22304
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
22013
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
22014
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
22015
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
22016
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22305
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml38(issue.requirement)}</strong>: ${escapeHtml38(issue.message)}</li>`).join("");
|
|
22306
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml38(outcome)}</span>`).join("");
|
|
22307
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml38(requirement)}</span>`).join("");
|
|
22308
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(title)}</title><style>body{background:#0e141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1050px;padding:32px}.hero,.panel{background:#151d26;border:1px solid #283544;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.metric{background:#0f151d;border:1px solid #283544;border-radius:16px;padding:14px}.metric strong{display:block;font-size:1.8rem}.pill{background:#0f151d;border:1px solid #3f3f46;border-radius:999px;display:inline-flex;margin:4px;padding:7px 10px}.issues{color:#fca5a5}code{color:#fde68a}@media(max-width:720px){main{padding:18px}}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent production smoke</p><h1>${escapeHtml38(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml38(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml38(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml38(report.sessionId)}</code>` : ""}.</p></section><section class="panel"><h2>Observed Trace Evidence</h2><div class="grid"><div class="metric"><span>Media starts</span><strong>${String(report.observed.mediaStarts)}</strong></div><div class="metric"><span>Transcripts</span><strong>${String(report.observed.transcripts)}</strong></div><div class="metric"><span>Assistant responses</span><strong>${String(report.observed.assistantResponses)}</strong></div><div class="metric"><span>Session errors</span><strong>${String(report.observed.sessionErrors)}</strong></div></div><p>${outcomes || '<span class="pill">No lifecycle outcome</span>'}</p></section><section class="panel"><h2>Requirements</h2><p>${requirements}</p>${issues ? `<ul class="issues">${issues}</ul>` : '<p class="pass">All required phone-agent smoke evidence is present.</p>'}</section></main></body></html>`;
|
|
22017
22309
|
};
|
|
22018
22310
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
22019
22311
|
query,
|
|
@@ -22036,7 +22328,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
22036
22328
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
22037
22329
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
22038
22330
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
22039
|
-
const routes = new
|
|
22331
|
+
const routes = new Elysia39({
|
|
22040
22332
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
22041
22333
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
22042
22334
|
if (htmlPath) {
|
|
@@ -22079,7 +22371,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
22079
22371
|
"completed",
|
|
22080
22372
|
"failed"
|
|
22081
22373
|
];
|
|
22082
|
-
var
|
|
22374
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22083
22375
|
var loadRouteJson = async (input) => {
|
|
22084
22376
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
22085
22377
|
headers: {
|
|
@@ -22317,10 +22609,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
22317
22609
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
22318
22610
|
const urls = entry?.setup.urls;
|
|
22319
22611
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
22320
|
-
return `<tr><td>${
|
|
22612
|
+
return `<tr><td>${escapeHtml39(carrier.name ?? carrier.provider)}</td><td>${escapeHtml39(carrier.provider)}</td><td><code>${escapeHtml39(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml39(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml39(entry.status)}">${escapeHtml39(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml39(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml39(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml39(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
22321
22613
|
}).join("");
|
|
22322
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
22323
|
-
const snippet =
|
|
22614
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml39(stage)}</code></li>`).join("");
|
|
22615
|
+
const snippet = escapeHtml39(`const phoneAgent = createVoicePhoneAgent({
|
|
22324
22616
|
carriers: [
|
|
22325
22617
|
{
|
|
22326
22618
|
provider: 'twilio',
|
|
@@ -22354,11 +22646,11 @@ app.use(
|
|
|
22354
22646
|
);`);
|
|
22355
22647
|
const checklist = report.carriers.map((carrier) => {
|
|
22356
22648
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
22357
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
22358
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
22359
|
-
return `<article><h3>${
|
|
22649
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml39(issue)}</li>`).join("") ?? "";
|
|
22650
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml39(step)}</li>`).join("") ?? "";
|
|
22651
|
+
return `<article><h3>${escapeHtml39(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
22360
22652
|
}).join("");
|
|
22361
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22653
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#365a60}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.primitive p{color:#cbd5de;line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #283544;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml39(report.title)}</h1><p>One self-hosted entrypoint for carrier routes, setup reports, smoke checks, and normalized call lifecycle stages.</p><p class="badge ${report.ready ? "pass" : "fail"}">Ready: ${String(report.ready)}</p>${report.matrixPath ? `<p><a href="${escapeHtml39(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoicePhoneAgent(...)</code> builds this carrier control plane</h2><p>Mount carrier routes once, expose setup and smoke proof, then feed the same carrier matrix and phone-agent smoke reports into production readiness so carrier regressions block deploys.</p><pre><code>${snippet}</code></pre></section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
|
|
22362
22654
|
};
|
|
22363
22655
|
var createVoicePhoneAgent = (options) => {
|
|
22364
22656
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -22367,7 +22659,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
22367
22659
|
setupPath: resolveSetupPath(carrier),
|
|
22368
22660
|
smokePath: resolveSmokePath(carrier)
|
|
22369
22661
|
}));
|
|
22370
|
-
const app = new
|
|
22662
|
+
const app = new Elysia40({
|
|
22371
22663
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
22372
22664
|
});
|
|
22373
22665
|
for (const carrier of options.carriers) {
|
|
@@ -24501,8 +24793,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24501
24793
|
};
|
|
24502
24794
|
};
|
|
24503
24795
|
// src/providerCapabilities.ts
|
|
24504
|
-
import { Elysia as
|
|
24505
|
-
var
|
|
24796
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
24797
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24506
24798
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
24507
24799
|
configured: true,
|
|
24508
24800
|
features: options.features?.[provider],
|
|
@@ -24565,27 +24857,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
24565
24857
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
24566
24858
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
24567
24859
|
const cards = report.capabilities.map((capability) => {
|
|
24568
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
24569
|
-
return `<article class="card ${
|
|
24860
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml40(feature)}</span>`).join("");
|
|
24861
|
+
return `<article class="card ${escapeHtml40(capability.status)}">
|
|
24570
24862
|
<div class="card-header">
|
|
24571
24863
|
<div>
|
|
24572
|
-
<p class="eyebrow">${
|
|
24573
|
-
<h2>${
|
|
24864
|
+
<p class="eyebrow">${escapeHtml40(capability.kind)}</p>
|
|
24865
|
+
<h2>${escapeHtml40(capability.label ?? capability.provider)}</h2>
|
|
24574
24866
|
</div>
|
|
24575
|
-
<strong>${
|
|
24867
|
+
<strong>${escapeHtml40(capability.status)}</strong>
|
|
24576
24868
|
</div>
|
|
24577
|
-
${capability.description ? `<p>${
|
|
24869
|
+
${capability.description ? `<p>${escapeHtml40(capability.description)}</p>` : ""}
|
|
24578
24870
|
<dl>
|
|
24579
24871
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
24580
24872
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
24581
|
-
<div><dt>Model</dt><dd>${
|
|
24873
|
+
<div><dt>Model</dt><dd>${escapeHtml40(capability.model ?? "default")}</dd></div>
|
|
24582
24874
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
24583
24875
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
24584
24876
|
</dl>
|
|
24585
24877
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
24586
24878
|
</article>`;
|
|
24587
24879
|
}).join("");
|
|
24588
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24880
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.16),rgba(34,197,94,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary,.features{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.selected,.healthy{color:#86efac}.unconfigured,.degraded,.rate-limited,.suppressed{color:#fca5a5}.idle,.recoverable{color:#fde68a}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Discovery</p><h1>${escapeHtml40(title)}</h1><div class="summary"><span class="pill">${String(report.configured)} configured</span><span class="pill">${String(report.selected)} selected</span><span class="pill">${String(report.unconfigured)} missing</span><span class="pill">${String(report.total)} total</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider capabilities configured.</p></article>'}</section></main></body></html>`;
|
|
24589
24881
|
};
|
|
24590
24882
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
24591
24883
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -24602,7 +24894,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
24602
24894
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
24603
24895
|
const path = options.path ?? "/api/provider-capabilities";
|
|
24604
24896
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
24605
|
-
const routes = new
|
|
24897
|
+
const routes = new Elysia41({
|
|
24606
24898
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
24607
24899
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
24608
24900
|
if (htmlPath) {
|
|
@@ -24611,7 +24903,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
24611
24903
|
return routes;
|
|
24612
24904
|
};
|
|
24613
24905
|
// src/providerOrchestration.ts
|
|
24614
|
-
import { Elysia as
|
|
24906
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
24615
24907
|
var defaultRequirement = {
|
|
24616
24908
|
minProviders: 1,
|
|
24617
24909
|
requireBudgetPolicy: false,
|
|
@@ -24619,12 +24911,12 @@ var defaultRequirement = {
|
|
|
24619
24911
|
requireFallback: false,
|
|
24620
24912
|
requireTimeoutBudget: false
|
|
24621
24913
|
};
|
|
24622
|
-
var
|
|
24914
|
+
var statusRank3 = {
|
|
24623
24915
|
pass: 0,
|
|
24624
24916
|
warn: 1,
|
|
24625
24917
|
fail: 2
|
|
24626
24918
|
};
|
|
24627
|
-
var
|
|
24919
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24628
24920
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24629
24921
|
var uniqueSorted6 = (values) => [
|
|
24630
24922
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -24635,7 +24927,7 @@ var surfaceProviderNames = (surface) => uniqueSorted6([
|
|
|
24635
24927
|
...isProviderList(surface.fallback) ? surface.fallback : [],
|
|
24636
24928
|
...isProviderList(surface.allowProviders) ? surface.allowProviders : []
|
|
24637
24929
|
]);
|
|
24638
|
-
var surfaceStatus = (issues) => issues.reduce((status, issue) =>
|
|
24930
|
+
var surfaceStatus = (issues) => issues.reduce((status, issue) => statusRank3[issue.status] > statusRank3[status] ? issue.status : status, "pass");
|
|
24639
24931
|
var resolvedRequirement = (surface, options) => ({
|
|
24640
24932
|
...defaultRequirement,
|
|
24641
24933
|
...options.defaultRequirement ?? {},
|
|
@@ -24767,27 +25059,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
24767
25059
|
};
|
|
24768
25060
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
24769
25061
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
24770
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
24771
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
25062
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml41(surface.status)}">
|
|
25063
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml41(surface.surface)}</p><h2>${escapeHtml41(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml41(surface.status)}</strong></div>
|
|
24772
25064
|
<dl>
|
|
24773
|
-
<div><dt>Providers</dt><dd>${
|
|
24774
|
-
<div><dt>Fallback</dt><dd>${
|
|
25065
|
+
<div><dt>Providers</dt><dd>${escapeHtml41(surface.providers.join(", ") || "none")}</dd></div>
|
|
25066
|
+
<div><dt>Fallback</dt><dd>${escapeHtml41(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
24775
25067
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
24776
25068
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
24777
25069
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
24778
25070
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
24779
25071
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
24780
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
25072
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml41(surface.fallbackMode || "default")}</dd></div>
|
|
24781
25073
|
</dl>
|
|
24782
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
25074
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml41(issue.status)}</strong> ${escapeHtml41(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
24783
25075
|
</article>`).join("");
|
|
24784
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25076
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#172033;border:1px solid #2d3b55;border-radius:22px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(59,130,246,.18),rgba(20,184,166,.12))}.eyebrow{color:#93c5fd;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f172a;border:1px solid #334155;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass strong{color:#86efac}.warn strong{color:#fde68a}.fail strong{color:#fca5a5}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0;overflow-wrap:anywhere}li{margin:.35rem 0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Policy Proof</p><h1>${escapeHtml41(title)}</h1><div class="summary"><span class="pill">${escapeHtml41(report.profileId)}</span><span class="pill">${escapeHtml41(report.status)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.providers)} providers</span><span class="pill">${String(report.issues.length)} issues</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider orchestration surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
24785
25077
|
};
|
|
24786
25078
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
24787
25079
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
24788
25080
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
24789
25081
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
24790
|
-
const routes = new
|
|
25082
|
+
const routes = new Elysia42({
|
|
24791
25083
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
24792
25084
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
24793
25085
|
if (htmlPath) {
|
|
@@ -24958,7 +25250,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
24958
25250
|
return report;
|
|
24959
25251
|
};
|
|
24960
25252
|
// src/providerSlo.ts
|
|
24961
|
-
import { Elysia as
|
|
25253
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
24962
25254
|
var defaultThresholds = {
|
|
24963
25255
|
llm: {
|
|
24964
25256
|
maxAverageElapsedMs: 2500,
|
|
@@ -24986,12 +25278,12 @@ var defaultThresholds = {
|
|
|
24986
25278
|
}
|
|
24987
25279
|
};
|
|
24988
25280
|
var providerKinds = ["llm", "stt", "tts"];
|
|
24989
|
-
var
|
|
25281
|
+
var statusRank4 = {
|
|
24990
25282
|
pass: 0,
|
|
24991
25283
|
warn: 1,
|
|
24992
25284
|
fail: 2
|
|
24993
25285
|
};
|
|
24994
|
-
var
|
|
25286
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24995
25287
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
24996
25288
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
24997
25289
|
var uniqueSorted7 = (values) => [
|
|
@@ -25183,7 +25475,7 @@ var evaluateVoiceProviderSloEvidence = (report, input = {}) => {
|
|
|
25183
25475
|
const timeouts = kindReports.reduce((total, kind) => total + kind.timeouts, 0);
|
|
25184
25476
|
const unresolvedErrors = kindReports.reduce((total, kind) => total + kind.unresolvedErrors, 0);
|
|
25185
25477
|
const maxStatus = input.maxStatus ?? "pass";
|
|
25186
|
-
if (
|
|
25478
|
+
if (statusRank4[report.status] > statusRank4[maxStatus]) {
|
|
25187
25479
|
issues.push(`Expected provider SLO status at most ${maxStatus}, found ${report.status}.`);
|
|
25188
25480
|
}
|
|
25189
25481
|
if (input.minEvents !== undefined && report.events < input.minEvents) {
|
|
@@ -25287,11 +25579,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25287
25579
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25288
25580
|
const kindCards = providerKinds.map((kind) => {
|
|
25289
25581
|
const kindReport = report.kinds[kind];
|
|
25290
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
25582
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml42(metric.label)}</dt><dd>${escapeHtml42(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml42(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
25291
25583
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25292
|
-
return `<article class="${
|
|
25584
|
+
return `<article class="${escapeHtml42(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml42(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml42(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
25293
25585
|
}).join("");
|
|
25294
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
25586
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml42(issue.status)}"><strong>${escapeHtml42(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml42(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
25295
25587
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25296
25588
|
store: runtimeStorage.traces,
|
|
25297
25589
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25301,7 +25593,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25301
25593
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25302
25594
|
}
|
|
25303
25595
|
})`;
|
|
25304
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25596
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#101318;color:#f8f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,article,.primitive{background:#171b22;border:1px solid #2c3340;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.2),rgba(245,158,11,.12))}.eyebrow{color:#7dd3fc;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.9rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status,article h2 span{border:1px solid #475569;border-radius:999px;display:inline-flex;font-size:.85rem;padding:6px 10px}.pass{border-color:rgba(34,197,94,.65)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}dt{color:#cbd5e1;font-size:.78rem;text-transform:uppercase}dd{font-size:1.7rem;font-weight:900;margin:0}small{color:#a8b3c2}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#101318;border:1px solid #2c3340;border-radius:16px;padding:12px}li span{color:#cbd5e1;display:block;margin-top:4px}.primitive{background:#11161d}.primitive code{color:#bae6fd}.primitive pre{background:#070b10;border:1px solid #243041;border-radius:16px;color:#e0f2fe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Provider latency and fallback proof</p><h1>${escapeHtml42(title)}</h1><p class="status ${escapeHtml42(report.status)}">${escapeHtml42(report.status)}</p><p>${report.events} provider routing event(s), ${report.eventsWithLatency} latency sample(s).</p></section><section class="grid">${kindCards}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderSloRoutes(...)</code> turns provider speed into release evidence</h2><p>Pair this report with production readiness so LLM/STT/TTS latency, timeout, fallback, and unresolved error regressions block deploys.</p><pre><code>${escapeHtml42(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
25305
25597
|
};
|
|
25306
25598
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25307
25599
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25312,7 +25604,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25312
25604
|
...options.headers ?? {}
|
|
25313
25605
|
};
|
|
25314
25606
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25315
|
-
const app = new
|
|
25607
|
+
const app = new Elysia43({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25316
25608
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25317
25609
|
if (markdownPath !== false) {
|
|
25318
25610
|
app.get(markdownPath, async () => {
|
|
@@ -25342,10 +25634,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25342
25634
|
return app;
|
|
25343
25635
|
};
|
|
25344
25636
|
// src/productionReadiness.ts
|
|
25345
|
-
import { Elysia as
|
|
25637
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
25346
25638
|
|
|
25347
25639
|
// src/telephony/security.ts
|
|
25348
|
-
import { Elysia as
|
|
25640
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25349
25641
|
|
|
25350
25642
|
// src/postgresStore.ts
|
|
25351
25643
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -26083,7 +26375,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
26083
26375
|
};
|
|
26084
26376
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
26085
26377
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
26086
|
-
return new
|
|
26378
|
+
return new Elysia44({
|
|
26087
26379
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
26088
26380
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
26089
26381
|
};
|
|
@@ -26140,8 +26432,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
26140
26432
|
};
|
|
26141
26433
|
|
|
26142
26434
|
// src/opsRecovery.ts
|
|
26143
|
-
import { Elysia as
|
|
26144
|
-
var
|
|
26435
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
26436
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26145
26437
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26146
26438
|
var hrefForSession = (value, sessionId) => {
|
|
26147
26439
|
if (typeof value === "function") {
|
|
@@ -26157,7 +26449,7 @@ var hrefForSession = (value, sessionId) => {
|
|
|
26157
26449
|
return value;
|
|
26158
26450
|
};
|
|
26159
26451
|
var operationsRecordHrefForSession = (links, sessionId) => hrefForSession(links?.operationsRecords, sessionId);
|
|
26160
|
-
var
|
|
26452
|
+
var rollupStatus3 = (issues) => issues.some((issue) => issue.severity === "fail") ? "fail" : issues.some((issue) => issue.severity === "warn") ? "warn" : "pass";
|
|
26161
26453
|
var providerUnresolved = (provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed";
|
|
26162
26454
|
var collectFailedSessions = (events, limit, links) => events.filter((event) => {
|
|
26163
26455
|
if (event.type !== "session.error") {
|
|
@@ -26305,7 +26597,7 @@ var buildVoiceOpsRecoveryReport = async (options = {}) => {
|
|
|
26305
26597
|
recoveredFallbacks: providers.reduce((total, provider) => total + provider.fallbackCount, 0),
|
|
26306
26598
|
unresolvedFailures: unresolvedProviders.length
|
|
26307
26599
|
},
|
|
26308
|
-
status:
|
|
26600
|
+
status: rollupStatus3(issues),
|
|
26309
26601
|
traceDeliveries
|
|
26310
26602
|
};
|
|
26311
26603
|
};
|
|
@@ -26355,19 +26647,19 @@ ${failedSessions || "None."}
|
|
|
26355
26647
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26356
26648
|
`;
|
|
26357
26649
|
};
|
|
26358
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
26650
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml43(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml43(label)}</span><strong>not configured</strong></article>`;
|
|
26359
26651
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26360
26652
|
const title = options.title ?? "Voice Ops Recovery";
|
|
26361
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
26362
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
26363
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
26364
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26653
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml43(issue.severity)}</td><td><code>${escapeHtml43(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml43(issue.href)}">${escapeHtml43(issue.label)}</a>` : escapeHtml43(issue.label)}</td><td>${escapeHtml43(String(issue.value ?? ""))}</td><td>${escapeHtml43(issue.detail ?? "")}</td></tr>`).join("");
|
|
26654
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml43(provider.provider)}</td><td>${escapeHtml43(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml43(provider.lastError ?? "")}</td></tr>`).join("");
|
|
26655
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml43(session.operationsRecordHref)}">${escapeHtml43(session.sessionId)}</a>` : escapeHtml43(session.sessionId)}${session.provider ? ` via ${escapeHtml43(session.provider)}` : ""}${session.error ? `: ${escapeHtml43(session.error)}` : ""}</li>`).join("");
|
|
26656
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml43(title)}</h1><p><span class="status">${escapeHtml43(report.status)}</span> Checked ${escapeHtml43(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml43(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
26365
26657
|
};
|
|
26366
26658
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26367
26659
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26368
26660
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26369
26661
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26370
|
-
const routes = new
|
|
26662
|
+
const routes = new Elysia45({
|
|
26371
26663
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26372
26664
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26373
26665
|
if (htmlPath) {
|
|
@@ -26397,18 +26689,18 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26397
26689
|
};
|
|
26398
26690
|
|
|
26399
26691
|
// src/observabilityExport.ts
|
|
26400
|
-
import { Elysia as
|
|
26692
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
26401
26693
|
import { Database as Database4 } from "bun:sqlite";
|
|
26402
26694
|
import { createHash } from "crypto";
|
|
26403
26695
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26404
26696
|
import { join as join3 } from "path";
|
|
26405
26697
|
|
|
26406
26698
|
// src/operationsRecord.ts
|
|
26407
|
-
import { Elysia as
|
|
26699
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
26408
26700
|
|
|
26409
26701
|
// src/traceTimeline.ts
|
|
26410
|
-
import { Elysia as
|
|
26411
|
-
var
|
|
26702
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26703
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26412
26704
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26413
26705
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26414
26706
|
var firstString3 = (payload, keys) => {
|
|
@@ -26591,17 +26883,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
26591
26883
|
};
|
|
26592
26884
|
};
|
|
26593
26885
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26594
|
-
var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${
|
|
26886
|
+
var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml44(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs4(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs4(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
|
|
26595
26887
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
26596
|
-
const events = session.events.map((event) => `<tr class="${
|
|
26597
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
26598
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
26599
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26888
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml44(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml44(event.type)}</td><td>${escapeHtml44(event.label)}</td><td>${escapeHtml44(event.provider ?? "")}</td><td>${escapeHtml44(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
26889
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml44(issue.severity)}">${escapeHtml44(issue.code)}: ${escapeHtml44(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
26890
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml44(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
26891
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml44(session.sessionId)}</h1><p class="status ${escapeHtml44(session.status)}">${escapeHtml44(session.status)}</p>${supportLinks}</header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs4(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
|
|
26600
26892
|
};
|
|
26601
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
26893
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml44(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml44(session.operationsRecordHref)}">${escapeHtml44(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml44(session.sessionId)}</a>`}</td><td>${escapeHtml44(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs4(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml44(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
26602
26894
|
var timelineCSS = "body{background:#0f1318;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}a{color:#fbbf24}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.metrics,.providers{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.providers article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span,dt,.muted{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:12px 0 0}dd{font-weight:800;margin:4px 0 0}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}section{margin-top:28px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}";
|
|
26603
26895
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
26604
|
-
const snippet =
|
|
26896
|
+
const snippet = escapeHtml44(`const traceStore = createVoiceTraceSinkStore({
|
|
26605
26897
|
store: runtimeStorage.traces,
|
|
26606
26898
|
sinks: [
|
|
26607
26899
|
createVoiceTraceHTTPSink({
|
|
@@ -26627,13 +26919,13 @@ app.use(
|
|
|
26627
26919
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
26628
26920
|
})
|
|
26629
26921
|
);`);
|
|
26630
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26922
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml44(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
|
|
26631
26923
|
};
|
|
26632
26924
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
26633
26925
|
const path = options.path ?? "/api/voice-traces";
|
|
26634
26926
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
26635
26927
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
26636
|
-
const routes = new
|
|
26928
|
+
const routes = new Elysia46({
|
|
26637
26929
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
26638
26930
|
});
|
|
26639
26931
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -27062,7 +27354,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
27062
27354
|
}
|
|
27063
27355
|
return report;
|
|
27064
27356
|
};
|
|
27065
|
-
var
|
|
27357
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27066
27358
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27067
27359
|
var outcomeLabels = (outcome) => [
|
|
27068
27360
|
outcome.complete ? "complete" : undefined,
|
|
@@ -27142,20 +27434,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
27142
27434
|
`);
|
|
27143
27435
|
};
|
|
27144
27436
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
27145
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
27146
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
27147
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
27437
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml45(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs5(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
27438
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml45(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml45(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml45(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml45(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
27439
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml45(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml45(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml45(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml45(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml45(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml45(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml45(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml45(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
27148
27440
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
27149
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
27150
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
27151
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
27152
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
27153
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
27441
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml45(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml45(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml45(handoff.status ?? "")}</span><p>${escapeHtml45(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
27442
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml45(tool.toolName ?? "tool")}</strong> <span>${escapeHtml45(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml45(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
27443
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml45(review.title)}</strong> <span>${escapeHtml45(review.summary.outcome ?? "")}</span><p>${escapeHtml45(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
27444
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml45(task.title)}</strong> <span>${escapeHtml45(task.status)}</span><p>${escapeHtml45(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
27445
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml45(event.type)}</strong> <span>${escapeHtml45(event.deliveryStatus ?? "local")}</span><p>${escapeHtml45(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
27154
27446
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
27155
27447
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
27156
|
-
return `<li><strong>assistant.guardrail ${
|
|
27448
|
+
return `<li><strong>assistant.guardrail ${escapeHtml45(decision.stage ?? "unknown")}</strong> <span>${escapeHtml45(decision.status ?? "")}</span><p>Allowed: ${escapeHtml45(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml45(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml45(decision.turnId)}` : ""}</p><p>${escapeHtml45(findings)}</p></li>`;
|
|
27157
27449
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
27158
|
-
const snippet =
|
|
27450
|
+
const snippet = escapeHtml45(`app.use(
|
|
27159
27451
|
createVoiceOperationsRecordRoutes({
|
|
27160
27452
|
audit: auditStore,
|
|
27161
27453
|
integrationEvents: opsEvents,
|
|
@@ -27169,16 +27461,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
27169
27461
|
tasks: opsTasks
|
|
27170
27462
|
})
|
|
27171
27463
|
);`);
|
|
27172
|
-
const incidentMarkdown =
|
|
27173
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
27174
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27464
|
+
const incidentMarkdown = escapeHtml45(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
27465
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml45(options.incidentHref)}">Download incident.md</a>` : "";
|
|
27466
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml45(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml45(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml45(record.status)}">${escapeHtml45(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs5(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml45(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
|
|
27175
27467
|
};
|
|
27176
27468
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
27177
27469
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
27178
27470
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
27179
27471
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
27180
27472
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
27181
|
-
const routes = new
|
|
27473
|
+
const routes = new Elysia47({
|
|
27182
27474
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
27183
27475
|
});
|
|
27184
27476
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -27829,7 +28121,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
27829
28121
|
...options.headers ?? {}
|
|
27830
28122
|
};
|
|
27831
28123
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
27832
|
-
const app = new
|
|
28124
|
+
const app = new Elysia48({
|
|
27833
28125
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
27834
28126
|
});
|
|
27835
28127
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28638,7 +28930,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28638
28930
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
28639
28931
|
}
|
|
28640
28932
|
});
|
|
28641
|
-
const app = new
|
|
28933
|
+
const app = new Elysia48({
|
|
28642
28934
|
name: options.name ?? "absolute-voice-observability-export"
|
|
28643
28935
|
});
|
|
28644
28936
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28715,8 +29007,8 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28715
29007
|
};
|
|
28716
29008
|
|
|
28717
29009
|
// src/productionReadiness.ts
|
|
28718
|
-
var
|
|
28719
|
-
var
|
|
29010
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29011
|
+
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
28720
29012
|
var readinessGateCodes = {
|
|
28721
29013
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
28722
29014
|
"Audit evidence": "voice.readiness.audit_evidence",
|
|
@@ -30113,7 +30405,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30113
30405
|
profile: options.profile || undefined,
|
|
30114
30406
|
operationsRecords,
|
|
30115
30407
|
proofSources,
|
|
30116
|
-
status:
|
|
30408
|
+
status: rollupStatus4(checks),
|
|
30117
30409
|
summary: {
|
|
30118
30410
|
agentSquadContracts: agentSquadContractSummary,
|
|
30119
30411
|
audit,
|
|
@@ -30170,25 +30462,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30170
30462
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
30171
30463
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
30172
30464
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
30173
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
30174
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
30465
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml46(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
30466
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml46(report.profile.name)}</h2><p>${escapeHtml46(report.profile.description)}</p><p>${escapeHtml46(report.profile.purpose)}</p><div class="profile-surfaces">${report.profile.surfaces.map((surface) => `<article class="${surface.configured ? "pass" : "warn"}"><span>${surface.configured ? "CONFIGURED" : "EXPECTED"}</span><strong>${surface.href ? `<a href="${escapeHtml46(surface.href)}">${escapeHtml46(surface.label)}</a>` : escapeHtml46(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
30175
30467
|
const checks = report.checks.map((check, index) => {
|
|
30176
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
30177
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
30178
|
-
return `<article class="check ${
|
|
30468
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml46(action.href)}">${escapeHtml46(action.label)}</button>` : `<a href="${escapeHtml46(action.href)}">${escapeHtml46(action.label)}</a>`).join("");
|
|
30469
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml46(check.status)}: observed ${escapeHtml46(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml46(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml46(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml46(check.gateExplanation.unit)}` : ""}. ${escapeHtml46(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml46(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
30470
|
+
return `<article class="check ${escapeHtml46(check.status)}">
|
|
30179
30471
|
<div>
|
|
30180
|
-
<span>${
|
|
30181
|
-
<h2>${
|
|
30182
|
-
${check.detail ? `<p>${
|
|
30472
|
+
<span>${escapeHtml46(check.status.toUpperCase())}</span>
|
|
30473
|
+
<h2>${escapeHtml46(check.label)}</h2>
|
|
30474
|
+
${check.detail ? `<p>${escapeHtml46(check.detail)}</p>` : ""}
|
|
30183
30475
|
${explanation}
|
|
30184
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
30476
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml46(check.proofSource.href)}">${escapeHtml46(check.proofSource.sourceLabel)}</a>` : escapeHtml46(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml46(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
30185
30477
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
30186
30478
|
</div>
|
|
30187
|
-
<strong>${
|
|
30188
|
-
${check.href ? `<a href="${
|
|
30479
|
+
<strong>${escapeHtml46(String(check.value ?? check.status))}</strong>
|
|
30480
|
+
${check.href ? `<a href="${escapeHtml46(check.href)}">Open surface</a>` : ""}
|
|
30189
30481
|
</article>`;
|
|
30190
30482
|
}).join("");
|
|
30191
|
-
const snippet =
|
|
30483
|
+
const snippet = escapeHtml46(`createVoiceProductionReadinessRoutes({
|
|
30192
30484
|
htmlPath: '/production-readiness',
|
|
30193
30485
|
path: '/api/production-readiness',
|
|
30194
30486
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -30204,13 +30496,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
30204
30496
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
30205
30497
|
store: traceStore
|
|
30206
30498
|
});`);
|
|
30207
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30499
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero,.primitive,.profile{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.primitive,.profile{background:#111722}.primitive{border-color:#3a3f2d}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.primitive code{color:#fde68a}.primitive p{color:#c8ccd3;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#0b0f16;border:1px solid #2c3440;border-radius:18px;color:#fef3c7;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.check.pass,.profile-surfaces .pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn,.profile-surfaces .warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span,.profile-surfaces span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p,.profile p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check .gate-explanation{background:#0b0f16;border:1px solid #2c3440;border-radius:14px;color:#fef3c7;margin-top:10px;padding:10px}.check strong{font-size:1.5rem}.profile-surfaces{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}.profile-surfaces article{background:#141922;border:1px solid #26313d;border-radius:16px;padding:14px}.profile-surfaces strong{display:block;margin-top:6px}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml46(title)}</h1><p>One deployable pass/fail report for quality gates, provider failover, session health, handoffs, routing evidence, and optional carrier readiness.</p><p class="status ${escapeHtml46(report.status)}">Overall: ${escapeHtml46(report.status.toUpperCase())}</p><p>Checked ${escapeHtml46(new Date(report.checkedAt).toLocaleString())}</p>${thresholdLink}</section>${profile}<section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProductionReadinessRoutes(...)</code> builds this deploy gate</h2><p>Mount one package primitive to expose JSON readiness, HTML readiness, and a machine-readable gate route. Feed it the proof stores and contract reports your app already owns.</p><pre><code>${snippet}</code></pre></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
|
|
30208
30500
|
};
|
|
30209
30501
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
30210
30502
|
const path = options.path ?? "/api/production-readiness";
|
|
30211
30503
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
30212
30504
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
30213
|
-
const routes = new
|
|
30505
|
+
const routes = new Elysia49({
|
|
30214
30506
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
30215
30507
|
});
|
|
30216
30508
|
const resolveOptions = async (input) => {
|
|
@@ -30258,10 +30550,10 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30258
30550
|
return routes;
|
|
30259
30551
|
};
|
|
30260
30552
|
// src/voiceMonitoring.ts
|
|
30261
|
-
import { Elysia as
|
|
30262
|
-
var
|
|
30553
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
30554
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30263
30555
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30264
|
-
var
|
|
30556
|
+
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30265
30557
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
30266
30558
|
const issues = new Map(initial.map((issue) => [issue.id, { ...issue }]));
|
|
30267
30559
|
return {
|
|
@@ -30343,7 +30635,7 @@ var buildVoiceMonitorRunReport = async (options) => {
|
|
|
30343
30635
|
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
30344
30636
|
issues,
|
|
30345
30637
|
runs,
|
|
30346
|
-
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 ||
|
|
30638
|
+
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 || rollupStatus5(runs) === "warn" ? "warn" : rollupStatus5(runs),
|
|
30347
30639
|
summary: {
|
|
30348
30640
|
acknowledged: issues.filter((issue) => issue.status === "acknowledged").length,
|
|
30349
30641
|
criticalOpen,
|
|
@@ -30512,14 +30804,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
30512
30804
|
};
|
|
30513
30805
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
30514
30806
|
const title = options.title ?? "Voice Monitors";
|
|
30515
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
30516
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
30517
|
-
const snippet =
|
|
30807
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml47(run.label)}</td><td class="${escapeHtml47(run.status)}">${escapeHtml47(run.status)}</td><td>${escapeHtml47(run.severity)}</td><td>${escapeHtml47(String(run.value ?? ""))}</td><td>${escapeHtml47(String(run.threshold ?? ""))}</td><td>${escapeHtml47(run.detail ?? "")}</td></tr>`).join("");
|
|
30808
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml47(issue.label)}</strong> <span class="${escapeHtml47(issue.status)}">${escapeHtml47(issue.status)}</span> ${escapeHtml47(issue.detail ?? "")}</li>`).join("");
|
|
30809
|
+
const snippet = escapeHtml47(`app.use(createVoiceMonitorRoutes({
|
|
30518
30810
|
evidence,
|
|
30519
30811
|
issueStore,
|
|
30520
30812
|
monitors: [defineVoiceMonitor(...)]
|
|
30521
30813
|
}));`);
|
|
30522
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30814
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml47(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml47(title)}</h1><p class="pill ${escapeHtml47(report.status)}">Status: ${escapeHtml47(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
30523
30815
|
};
|
|
30524
30816
|
var actorFromRequest = async (request) => {
|
|
30525
30817
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -30543,7 +30835,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30543
30835
|
monitors: options.monitors,
|
|
30544
30836
|
now: options.now
|
|
30545
30837
|
});
|
|
30546
|
-
const routes = new
|
|
30838
|
+
const routes = new Elysia50({
|
|
30547
30839
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
30548
30840
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
30549
30841
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -30590,7 +30882,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30590
30882
|
};
|
|
30591
30883
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
30592
30884
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
30593
|
-
return new
|
|
30885
|
+
return new Elysia50({
|
|
30594
30886
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
30595
30887
|
}).get(path, () => ({
|
|
30596
30888
|
isRunning: options.runner.isRunning()
|
|
@@ -30966,8 +31258,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
30966
31258
|
};
|
|
30967
31259
|
};
|
|
30968
31260
|
// src/providerStackRecommendations.ts
|
|
30969
|
-
import { Elysia as
|
|
30970
|
-
var
|
|
31261
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
31262
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30971
31263
|
var profileProviderPriorities = {
|
|
30972
31264
|
"meeting-recorder": {
|
|
30973
31265
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31019,7 +31311,7 @@ var profileRequiredCapabilities = {
|
|
|
31019
31311
|
tts: ["streaming speech", "barge-in friendly"]
|
|
31020
31312
|
}
|
|
31021
31313
|
};
|
|
31022
|
-
var
|
|
31314
|
+
var defaultProviderEnv2 = {
|
|
31023
31315
|
anthropic: ["ANTHROPIC_API_KEY"],
|
|
31024
31316
|
assemblyai: ["ASSEMBLYAI_API_KEY"],
|
|
31025
31317
|
deepgram: ["DEEPGRAM_API_KEY"],
|
|
@@ -31079,12 +31371,12 @@ var recommendVoiceProviderStack = (input) => {
|
|
|
31079
31371
|
};
|
|
31080
31372
|
};
|
|
31081
31373
|
var rollupContractStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
31082
|
-
var
|
|
31374
|
+
var statusRank5 = {
|
|
31083
31375
|
pass: 0,
|
|
31084
31376
|
warn: 1,
|
|
31085
31377
|
fail: 2
|
|
31086
31378
|
};
|
|
31087
|
-
var
|
|
31379
|
+
var statusExceeds2 = (actual, max) => statusRank5[actual] > statusRank5[max];
|
|
31088
31380
|
var buildVoiceProviderContractMatrix = (input) => {
|
|
31089
31381
|
const rows = input.contracts.map((contract) => {
|
|
31090
31382
|
const configured = contract.configured !== false;
|
|
@@ -31197,7 +31489,7 @@ var evaluateVoiceProviderContractMatrixEvidence = (report, input = {}) => {
|
|
|
31197
31489
|
const selectedKinds = [
|
|
31198
31490
|
...new Set(report.rows.filter((row) => row.selected).map((row) => row.kind))
|
|
31199
31491
|
].sort();
|
|
31200
|
-
if (
|
|
31492
|
+
if (statusExceeds2(report.status, maxStatus)) {
|
|
31201
31493
|
issues.push(`Expected provider contract matrix status at most ${maxStatus}, found ${report.status}.`);
|
|
31202
31494
|
}
|
|
31203
31495
|
if (report.failed > maxFailed) {
|
|
@@ -31259,11 +31551,11 @@ var createVoiceProviderContractMatrixPreset = (profile, options) => {
|
|
|
31259
31551
|
const contracts = ["llm", "stt", "tts"].flatMap((kind) => {
|
|
31260
31552
|
const providers = options.providers[kind] ?? [];
|
|
31261
31553
|
return providers.map((provider) => {
|
|
31262
|
-
const configured = options.configured?.[provider] ?? (
|
|
31554
|
+
const configured = options.configured?.[provider] ?? (defaultProviderEnv2[provider]?.length ? defaultProviderEnv2[provider].every((name) => options.env?.[name]) : true);
|
|
31263
31555
|
const fallbackProviders = options.fallbackProviders?.[kind] ?? providers.filter((candidate) => candidate !== provider);
|
|
31264
31556
|
const requiredCapabilities = profileRequiredCapabilities[profile][kind];
|
|
31265
31557
|
const capabilities = options.capabilities?.[kind]?.[provider] ?? defaultProviderCapabilities[provider] ?? [];
|
|
31266
|
-
const requiredEnv =
|
|
31558
|
+
const requiredEnv = defaultProviderEnv2[provider] ?? [];
|
|
31267
31559
|
return {
|
|
31268
31560
|
capabilities,
|
|
31269
31561
|
configured,
|
|
@@ -31286,17 +31578,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31286
31578
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31287
31579
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31288
31580
|
const rows = report.rows.map((row) => {
|
|
31289
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31290
|
-
return `<article class="row ${
|
|
31581
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml48(check.status)}"><strong>${escapeHtml48(check.label)}</strong><span>${escapeHtml48(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml48(check.remediation.href)}">${escapeHtml48(check.remediation.label)}</a>` : escapeHtml48(check.remediation.label)}: ${escapeHtml48(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
31582
|
+
return `<article class="row ${escapeHtml48(row.status)}">
|
|
31291
31583
|
<div>
|
|
31292
|
-
<p class="eyebrow">${
|
|
31293
|
-
<h2>${
|
|
31294
|
-
<p class="status ${
|
|
31584
|
+
<p class="eyebrow">${escapeHtml48(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
31585
|
+
<h2>${escapeHtml48(row.provider)}</h2>
|
|
31586
|
+
<p class="status ${escapeHtml48(row.status)}">${escapeHtml48(row.status.toUpperCase())}</p>
|
|
31295
31587
|
</div>
|
|
31296
31588
|
<ul>${checks}</ul>
|
|
31297
31589
|
</article>`;
|
|
31298
31590
|
}).join("");
|
|
31299
|
-
const snippet =
|
|
31591
|
+
const snippet = escapeHtml48(`const providerContracts = () =>
|
|
31300
31592
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31301
31593
|
env: process.env,
|
|
31302
31594
|
providers: {
|
|
@@ -31317,7 +31609,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31317
31609
|
providerContractMatrix: () =>
|
|
31318
31610
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31319
31611
|
});`);
|
|
31320
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31612
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml48(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
31321
31613
|
};
|
|
31322
31614
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31323
31615
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31332,7 +31624,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31332
31624
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31333
31625
|
const path = options.path ?? "/api/provider-contracts";
|
|
31334
31626
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31335
|
-
const routes = new
|
|
31627
|
+
const routes = new Elysia51({
|
|
31336
31628
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31337
31629
|
});
|
|
31338
31630
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -31399,7 +31691,7 @@ var evaluateVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31399
31691
|
const providers = [
|
|
31400
31692
|
...new Set(report.gaps.map((gap) => gap.provider).filter((provider) => provider !== undefined))
|
|
31401
31693
|
].sort();
|
|
31402
|
-
if (
|
|
31694
|
+
if (statusExceeds2(report.status, maxStatus)) {
|
|
31403
31695
|
issues.push(`Expected provider stack status at most ${maxStatus}, found ${report.status}.`);
|
|
31404
31696
|
}
|
|
31405
31697
|
if (report.missing > maxMissing) {
|
|
@@ -31450,7 +31742,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31450
31742
|
return assertion;
|
|
31451
31743
|
};
|
|
31452
31744
|
// src/opsConsoleRoutes.ts
|
|
31453
|
-
import { Elysia as
|
|
31745
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
31454
31746
|
var DEFAULT_LINKS = [
|
|
31455
31747
|
{
|
|
31456
31748
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -31485,7 +31777,7 @@ var DEFAULT_LINKS = [
|
|
|
31485
31777
|
label: "Handoffs"
|
|
31486
31778
|
}
|
|
31487
31779
|
];
|
|
31488
|
-
var
|
|
31780
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31489
31781
|
var countProviderStatuses = (providers) => {
|
|
31490
31782
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
31491
31783
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -31554,20 +31846,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
31554
31846
|
trace
|
|
31555
31847
|
};
|
|
31556
31848
|
};
|
|
31557
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
31849
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml49(input.label)}</span><strong>${escapeHtml49(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml49(input.status)}">${escapeHtml49(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml49(input.href)}">Open</a>` : ""}</article>`;
|
|
31558
31850
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
31559
31851
|
const links = report.links.map((link) => `<article class="surface">
|
|
31560
|
-
<div><h2>${
|
|
31561
|
-
<p><a href="${
|
|
31852
|
+
<div><h2>${escapeHtml49(link.label)}</h2>${link.description ? `<p>${escapeHtml49(link.description)}</p>` : ""}</div>
|
|
31853
|
+
<p><a href="${escapeHtml49(link.href)}">Open ${escapeHtml49(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml49(link.statusHref)}">Status</a>` : ""}</p>
|
|
31562
31854
|
</article>`).join("");
|
|
31563
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
31564
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
31855
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml49(session.sessionId)}</td><td>${escapeHtml49(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml49(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
31856
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml49(event.kind)}</td><td>${escapeHtml49(event.provider ?? "unknown")}</td><td>${escapeHtml49(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml49(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
31565
31857
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
31566
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31858
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml49(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml49(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml49(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
|
|
31567
31859
|
};
|
|
31568
31860
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
31569
31861
|
const path = options.path ?? "/ops-console";
|
|
31570
|
-
const routes = new
|
|
31862
|
+
const routes = new Elysia52({
|
|
31571
31863
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
31572
31864
|
});
|
|
31573
31865
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -31584,7 +31876,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
31584
31876
|
return routes;
|
|
31585
31877
|
};
|
|
31586
31878
|
// src/incidentBundle.ts
|
|
31587
|
-
import { Elysia as
|
|
31879
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31588
31880
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
31589
31881
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
31590
31882
|
return false;
|
|
@@ -31785,7 +32077,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
31785
32077
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
31786
32078
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
31787
32079
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
31788
|
-
const routes = new
|
|
32080
|
+
const routes = new Elysia53({
|
|
31789
32081
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
31790
32082
|
});
|
|
31791
32083
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -31986,19 +32278,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
31986
32278
|
};
|
|
31987
32279
|
};
|
|
31988
32280
|
// src/opsStatusRoutes.ts
|
|
31989
|
-
import { Elysia as
|
|
31990
|
-
var
|
|
32281
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
32282
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31991
32283
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
31992
32284
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
31993
32285
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
31994
32286
|
const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
|
|
31995
|
-
return `<article class="surface ${
|
|
32287
|
+
return `<article class="surface ${escapeHtml50(surface.status)}"><span>${escapeHtml50(surface.status.toUpperCase())}</span><h2>${escapeHtml50(key)}</h2><strong>${escapeHtml50(value)}</strong></article>`;
|
|
31996
32288
|
}).join("");
|
|
31997
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32289
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml50(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml50(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml50(report.status)}">Overall: ${escapeHtml50(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
|
|
31998
32290
|
};
|
|
31999
32291
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
32000
32292
|
const path = options.path ?? "/api/voice/ops-status";
|
|
32001
|
-
const routes = new
|
|
32293
|
+
const routes = new Elysia54({
|
|
32002
32294
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
32003
32295
|
});
|
|
32004
32296
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -32431,8 +32723,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
32431
32723
|
};
|
|
32432
32724
|
};
|
|
32433
32725
|
// src/traceDeliveryRoutes.ts
|
|
32434
|
-
import { Elysia as
|
|
32435
|
-
var
|
|
32726
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32727
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32436
32728
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
32437
32729
|
var getNumber12 = (value) => {
|
|
32438
32730
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -32513,14 +32805,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
32513
32805
|
if (entries.length === 0) {
|
|
32514
32806
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
32515
32807
|
}
|
|
32516
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
32808
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml51(sinkId)}</strong>: ${escapeHtml51(result.status)}${result.deliveredTo ? ` to ${escapeHtml51(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml51(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
32517
32809
|
};
|
|
32518
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
32810
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml51(event.type)} <small>${escapeHtml51(event.id)}</small>${event.sessionId ? ` session=${escapeHtml51(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
32519
32811
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
32520
32812
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
32521
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
32522
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
32523
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32813
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml51(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
32814
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml51(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml51(delivery.deliveryStatus)}</span><h2>${escapeHtml51(delivery.id)}</h2><p>${escapeHtml51(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml51(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml51(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
32815
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml51(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml51(title)}</h1><p>Checked ${escapeHtml51(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
|
|
32524
32816
|
};
|
|
32525
32817
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
32526
32818
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32540,7 +32832,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
32540
32832
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
32541
32833
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
32542
32834
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
32543
|
-
const routes = new
|
|
32835
|
+
const routes = new Elysia55({
|
|
32544
32836
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
32545
32837
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
32546
32838
|
if (htmlPath !== false) {
|
|
@@ -32637,7 +32929,7 @@ var createVoiceMemoryStore = () => {
|
|
|
32637
32929
|
return { get, getOrCreate, list, remove, set };
|
|
32638
32930
|
};
|
|
32639
32931
|
// src/opsWebhook.ts
|
|
32640
|
-
import { Elysia as
|
|
32932
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32641
32933
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
32642
32934
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
32643
32935
|
const encoder = new TextEncoder;
|
|
@@ -32767,7 +33059,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
32767
33059
|
};
|
|
32768
33060
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
32769
33061
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
32770
|
-
return new
|
|
33062
|
+
return new Elysia56().post(path, async ({ body, request, set }) => {
|
|
32771
33063
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
32772
33064
|
if (options.signingSecret) {
|
|
32773
33065
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -33222,7 +33514,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
33222
33514
|
};
|
|
33223
33515
|
};
|
|
33224
33516
|
// src/postCallAnalysis.ts
|
|
33225
|
-
import { Elysia as
|
|
33517
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
33226
33518
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
33227
33519
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
33228
33520
|
var getPathValue3 = (source, path) => {
|
|
@@ -33401,7 +33693,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
33401
33693
|
};
|
|
33402
33694
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
33403
33695
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
33404
|
-
const routes = new
|
|
33696
|
+
const routes = new Elysia57({
|
|
33405
33697
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
33406
33698
|
});
|
|
33407
33699
|
routes.get(path, async ({ query }) => {
|
|
@@ -33426,7 +33718,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
33426
33718
|
return routes;
|
|
33427
33719
|
};
|
|
33428
33720
|
// src/guardrails.ts
|
|
33429
|
-
import { Elysia as
|
|
33721
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
33430
33722
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
33431
33723
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
33432
33724
|
var matchesRule = async (rule, input) => {
|
|
@@ -33728,7 +34020,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
33728
34020
|
};
|
|
33729
34021
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
33730
34022
|
const path = options.path ?? "/api/voice/guardrails";
|
|
33731
|
-
const routes = new
|
|
34023
|
+
const routes = new Elysia58({
|
|
33732
34024
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
33733
34025
|
});
|
|
33734
34026
|
routes.all(path, async ({ request }) => {
|
|
@@ -34252,6 +34544,7 @@ export {
|
|
|
34252
34544
|
renderVoiceScenarioEvalHTML,
|
|
34253
34545
|
renderVoiceResilienceHTML,
|
|
34254
34546
|
renderVoiceReconnectContractHTML,
|
|
34547
|
+
renderVoiceRealtimeProviderContractHTML,
|
|
34255
34548
|
renderVoiceRealtimeChannelMarkdown,
|
|
34256
34549
|
renderVoiceRealtimeChannelHTML,
|
|
34257
34550
|
renderVoiceQualityHTML,
|
|
@@ -34349,6 +34642,7 @@ export {
|
|
|
34349
34642
|
evaluateVoiceTelephonyWebhookNormalizationEvidence,
|
|
34350
34643
|
evaluateVoiceTelephonyContract,
|
|
34351
34644
|
evaluateVoiceSimulationSuiteEvidence,
|
|
34645
|
+
evaluateVoiceRealtimeProviderContractEvidence,
|
|
34352
34646
|
evaluateVoiceRealtimeChannelEvidence,
|
|
34353
34647
|
evaluateVoiceQuality,
|
|
34354
34648
|
evaluateVoiceProviderStackGaps,
|
|
@@ -34479,6 +34773,7 @@ export {
|
|
|
34479
34773
|
createVoiceRedisPlivoWebhookNonceStore,
|
|
34480
34774
|
createVoiceRedisIdempotencyStore,
|
|
34481
34775
|
createVoiceReconnectContractRoutes,
|
|
34776
|
+
createVoiceRealtimeProviderContractRoutes,
|
|
34482
34777
|
createVoiceRealtimeChannelRoutes,
|
|
34483
34778
|
createVoiceReadinessProfile,
|
|
34484
34779
|
createVoiceQualityRoutes,
|
|
@@ -34683,6 +34978,8 @@ export {
|
|
|
34683
34978
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
34684
34979
|
buildVoiceSloReadinessThresholdReport,
|
|
34685
34980
|
buildVoiceSloCalibrationReport,
|
|
34981
|
+
buildVoiceRealtimeProviderContractMatrix,
|
|
34982
|
+
buildVoiceRealtimeChannelRuntimeSamplesFromTrace,
|
|
34686
34983
|
buildVoiceRealtimeChannelReport,
|
|
34687
34984
|
buildVoiceProviderSloReport,
|
|
34688
34985
|
buildVoiceProviderOrchestrationReport,
|
|
@@ -34727,6 +35024,7 @@ export {
|
|
|
34727
35024
|
assertVoiceTelephonyWebhookNormalizationEvidence,
|
|
34728
35025
|
assertVoiceSloCalibration,
|
|
34729
35026
|
assertVoiceSimulationSuiteEvidence,
|
|
35027
|
+
assertVoiceRealtimeProviderContractEvidence,
|
|
34730
35028
|
assertVoiceRealtimeChannelEvidence,
|
|
34731
35029
|
assertVoiceProviderStackEvidence,
|
|
34732
35030
|
assertVoiceProviderSloEvidence,
|