@absolutejs/voice 0.0.22-beta.301 → 0.0.22-beta.302
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +646 -410
- package/dist/realtimeChannel.d.ts +127 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10920,9 +10920,239 @@ var createVoiceReconnectContractRoutes = (options) => {
|
|
|
10920
10920
|
}
|
|
10921
10921
|
return app;
|
|
10922
10922
|
};
|
|
10923
|
-
// src/
|
|
10923
|
+
// src/realtimeChannel.ts
|
|
10924
10924
|
import { Elysia as Elysia9 } from "elysia";
|
|
10925
|
-
var
|
|
10925
|
+
var DEFAULT_REALTIME_FORMAT2 = {
|
|
10926
|
+
channels: 1,
|
|
10927
|
+
container: "raw",
|
|
10928
|
+
encoding: "pcm_s16le",
|
|
10929
|
+
sampleRateHz: 24000
|
|
10930
|
+
};
|
|
10931
|
+
var escapeHtml12 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10932
|
+
var formatLabel = (format) => `${format.container}/${format.encoding}/${String(format.sampleRateHz)}hz/${String(format.channels)}ch`;
|
|
10933
|
+
var formatMatches = (actual, expected) => actual.container === expected.container && actual.encoding === expected.encoding && actual.sampleRateHz === expected.sampleRateHz && actual.channels === expected.channels;
|
|
10934
|
+
var validateFormat = (label, actual, expected, issues) => {
|
|
10935
|
+
if (!formatMatches(actual, expected)) {
|
|
10936
|
+
issues.push({
|
|
10937
|
+
code: `${label}-format-mismatch`,
|
|
10938
|
+
message: `${label} format ${formatLabel(actual)} does not match expected ${formatLabel(expected)}.`,
|
|
10939
|
+
severity: "error"
|
|
10940
|
+
});
|
|
10941
|
+
}
|
|
10942
|
+
if (actual.container !== "raw" || actual.encoding !== "pcm_s16le") {
|
|
10943
|
+
issues.push({
|
|
10944
|
+
code: `${label}-unsupported-encoding`,
|
|
10945
|
+
message: `${label} must use raw pcm_s16le audio for realtime proof.`,
|
|
10946
|
+
severity: "error"
|
|
10947
|
+
});
|
|
10948
|
+
}
|
|
10949
|
+
if (actual.channels !== 1) {
|
|
10950
|
+
issues.push({
|
|
10951
|
+
code: `${label}-not-mono`,
|
|
10952
|
+
message: `${label} should be mono for realtime provider input/output.`,
|
|
10953
|
+
severity: "error"
|
|
10954
|
+
});
|
|
10955
|
+
}
|
|
10956
|
+
};
|
|
10957
|
+
var buildVoiceRealtimeChannelReport = (options) => {
|
|
10958
|
+
const expectedInputFormat = options.expectedInputFormat ?? DEFAULT_REALTIME_FORMAT2;
|
|
10959
|
+
const expectedOutputFormat = options.expectedOutputFormat ?? expectedInputFormat;
|
|
10960
|
+
const inputFormat = options.inputFormat ?? expectedInputFormat;
|
|
10961
|
+
const outputFormat = options.outputFormat ?? expectedOutputFormat;
|
|
10962
|
+
const runtimeSamples = options.runtimeSamples ?? [];
|
|
10963
|
+
const issues = [];
|
|
10964
|
+
validateFormat("input", inputFormat, expectedInputFormat, issues);
|
|
10965
|
+
validateFormat("output", outputFormat, expectedOutputFormat, issues);
|
|
10966
|
+
const browserCapture = options.browserCapture ? {
|
|
10967
|
+
...options.browserCapture,
|
|
10968
|
+
resamplingRequired: options.browserCapture.audioContextSampleRateHz !== undefined && options.browserCapture.audioContextSampleRateHz !== inputFormat.sampleRateHz,
|
|
10969
|
+
resamplingTargetHz: inputFormat.sampleRateHz
|
|
10970
|
+
} : undefined;
|
|
10971
|
+
if (!browserCapture) {
|
|
10972
|
+
issues.push({
|
|
10973
|
+
code: "browser-capture-missing",
|
|
10974
|
+
message: "Browser capture settings are missing; realtime proof cannot show capture-to-provider format negotiation.",
|
|
10975
|
+
severity: "warning"
|
|
10976
|
+
});
|
|
10977
|
+
} else {
|
|
10978
|
+
if (browserCapture.sampleRateHz !== inputFormat.sampleRateHz) {
|
|
10979
|
+
issues.push({
|
|
10980
|
+
code: "browser-capture-target-mismatch",
|
|
10981
|
+
message: `Browser capture target ${String(browserCapture.sampleRateHz ?? "unknown")}hz does not match realtime input ${String(inputFormat.sampleRateHz)}hz.`,
|
|
10982
|
+
severity: "error"
|
|
10983
|
+
});
|
|
10984
|
+
}
|
|
10985
|
+
if ((browserCapture.channelCount ?? 1) !== inputFormat.channels) {
|
|
10986
|
+
issues.push({
|
|
10987
|
+
code: "browser-capture-channel-mismatch",
|
|
10988
|
+
message: `Browser capture channel count ${String(browserCapture.channelCount ?? "unknown")} does not match realtime input ${String(inputFormat.channels)}.`,
|
|
10989
|
+
severity: "error"
|
|
10990
|
+
});
|
|
10991
|
+
}
|
|
10992
|
+
}
|
|
10993
|
+
for (const sample of runtimeSamples) {
|
|
10994
|
+
if (sample.ok === false) {
|
|
10995
|
+
issues.push({
|
|
10996
|
+
code: "runtime-sample-failed",
|
|
10997
|
+
message: `Realtime runtime sample failed: ${sample.kind}.`,
|
|
10998
|
+
severity: "error"
|
|
10999
|
+
});
|
|
11000
|
+
}
|
|
11001
|
+
if (sample.format && !formatMatches(sample.format, inputFormat)) {
|
|
11002
|
+
issues.push({
|
|
11003
|
+
code: "runtime-format-mismatch",
|
|
11004
|
+
message: `Runtime sample ${sample.kind} used ${formatLabel(sample.format)} instead of ${formatLabel(inputFormat)}.`,
|
|
11005
|
+
severity: "error"
|
|
11006
|
+
});
|
|
11007
|
+
}
|
|
11008
|
+
}
|
|
11009
|
+
const inputAudioSamples = runtimeSamples.filter((sample) => sample.kind === "input-audio").length;
|
|
11010
|
+
const assistantAudioSamples = runtimeSamples.filter((sample) => sample.kind === "assistant-audio").length;
|
|
11011
|
+
const firstAudioLatencyMs = runtimeSamples.filter((sample) => sample.kind === "assistant-audio" && typeof sample.latencyMs === "number" && Number.isFinite(sample.latencyMs)).map((sample) => sample.latencyMs).sort((a, b) => a - b)[0];
|
|
11012
|
+
const minInputAudioSamples = options.minInputAudioSamples ?? 1;
|
|
11013
|
+
const minAssistantAudioSamples = options.minAssistantAudioSamples ?? 1;
|
|
11014
|
+
const maxFirstAudioLatencyMs = options.maxFirstAudioLatencyMs;
|
|
11015
|
+
if (inputAudioSamples < minInputAudioSamples) {
|
|
11016
|
+
issues.push({
|
|
11017
|
+
code: "runtime-input-audio-missing",
|
|
11018
|
+
message: `Expected at least ${String(minInputAudioSamples)} realtime input audio sample(s), found ${String(inputAudioSamples)}.`,
|
|
11019
|
+
severity: "warning"
|
|
11020
|
+
});
|
|
11021
|
+
}
|
|
11022
|
+
if (assistantAudioSamples < minAssistantAudioSamples) {
|
|
11023
|
+
issues.push({
|
|
11024
|
+
code: "runtime-assistant-audio-missing",
|
|
11025
|
+
message: `Expected at least ${String(minAssistantAudioSamples)} realtime assistant audio sample(s), found ${String(assistantAudioSamples)}.`,
|
|
11026
|
+
severity: "warning"
|
|
11027
|
+
});
|
|
11028
|
+
}
|
|
11029
|
+
if (maxFirstAudioLatencyMs !== undefined && (firstAudioLatencyMs === undefined || firstAudioLatencyMs > maxFirstAudioLatencyMs)) {
|
|
11030
|
+
issues.push({
|
|
11031
|
+
code: "first-audio-latency-over-budget",
|
|
11032
|
+
message: `Expected first realtime assistant audio at or below ${String(maxFirstAudioLatencyMs)}ms, found ${String(firstAudioLatencyMs ?? "missing")}ms.`,
|
|
11033
|
+
severity: "warning"
|
|
11034
|
+
});
|
|
11035
|
+
}
|
|
11036
|
+
const status = issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass";
|
|
11037
|
+
return {
|
|
11038
|
+
browserCapture,
|
|
11039
|
+
checkedAt: Date.now(),
|
|
11040
|
+
inputFormat,
|
|
11041
|
+
issues,
|
|
11042
|
+
operationsRecordHref: options.operationsRecordHref,
|
|
11043
|
+
outputFormat,
|
|
11044
|
+
provider: options.provider,
|
|
11045
|
+
readinessHref: options.readinessHref,
|
|
11046
|
+
runtime: {
|
|
11047
|
+
assistantAudioSamples,
|
|
11048
|
+
firstAudioLatencyMs,
|
|
11049
|
+
inputAudioSamples,
|
|
11050
|
+
samples: runtimeSamples
|
|
11051
|
+
},
|
|
11052
|
+
status,
|
|
11053
|
+
surface: options.surface ?? "Direct realtime/duplex providers"
|
|
11054
|
+
};
|
|
11055
|
+
};
|
|
11056
|
+
var evaluateVoiceRealtimeChannelEvidence = (report, input = {}) => {
|
|
11057
|
+
const issues = [];
|
|
11058
|
+
if ((input.requirePass ?? false) && report.status !== "pass") {
|
|
11059
|
+
issues.push(`Expected realtime channel proof to pass, found ${report.status}.`);
|
|
11060
|
+
}
|
|
11061
|
+
if (input.requireBrowserCapture && !report.browserCapture) {
|
|
11062
|
+
issues.push("Missing browser capture negotiation proof.");
|
|
11063
|
+
}
|
|
11064
|
+
if (input.requireOperationsRecordHref && !report.operationsRecordHref) {
|
|
11065
|
+
issues.push("Missing operations-record link for realtime channel proof.");
|
|
11066
|
+
}
|
|
11067
|
+
if (input.requireReadinessHref && !report.readinessHref) {
|
|
11068
|
+
issues.push("Missing readiness link for realtime channel proof.");
|
|
11069
|
+
}
|
|
11070
|
+
if (input.minInputAudioSamples !== undefined && report.runtime.inputAudioSamples < input.minInputAudioSamples) {
|
|
11071
|
+
issues.push(`Expected at least ${String(input.minInputAudioSamples)} realtime input audio samples, found ${String(report.runtime.inputAudioSamples)}.`);
|
|
11072
|
+
}
|
|
11073
|
+
if (input.minAssistantAudioSamples !== undefined && report.runtime.assistantAudioSamples < input.minAssistantAudioSamples) {
|
|
11074
|
+
issues.push(`Expected at least ${String(input.minAssistantAudioSamples)} realtime assistant audio samples, found ${String(report.runtime.assistantAudioSamples)}.`);
|
|
11075
|
+
}
|
|
11076
|
+
if (input.maxFirstAudioLatencyMs !== undefined && (report.runtime.firstAudioLatencyMs === undefined || report.runtime.firstAudioLatencyMs > input.maxFirstAudioLatencyMs)) {
|
|
11077
|
+
issues.push(`Expected first realtime assistant audio at or below ${String(input.maxFirstAudioLatencyMs)}ms, found ${String(report.runtime.firstAudioLatencyMs ?? "missing")}ms.`);
|
|
11078
|
+
}
|
|
11079
|
+
return {
|
|
11080
|
+
issues,
|
|
11081
|
+
ok: issues.length === 0,
|
|
11082
|
+
provider: report.provider,
|
|
11083
|
+
status: report.status,
|
|
11084
|
+
surface: report.surface
|
|
11085
|
+
};
|
|
11086
|
+
};
|
|
11087
|
+
var assertVoiceRealtimeChannelEvidence = (report, input = {}) => {
|
|
11088
|
+
const assertion = evaluateVoiceRealtimeChannelEvidence(report, input);
|
|
11089
|
+
if (!assertion.ok) {
|
|
11090
|
+
throw new Error(`Voice realtime channel assertion failed: ${assertion.issues.join(" ")}`);
|
|
11091
|
+
}
|
|
11092
|
+
return assertion;
|
|
11093
|
+
};
|
|
11094
|
+
var renderVoiceRealtimeChannelMarkdown = (report) => [
|
|
11095
|
+
"# Voice Realtime Channel Proof",
|
|
11096
|
+
"",
|
|
11097
|
+
`- Status: ${report.status}`,
|
|
11098
|
+
`- Provider: ${report.provider}`,
|
|
11099
|
+
`- Surface: ${report.surface}`,
|
|
11100
|
+
`- Input format: ${formatLabel(report.inputFormat)}`,
|
|
11101
|
+
`- Output format: ${formatLabel(report.outputFormat)}`,
|
|
11102
|
+
`- Browser capture: ${report.browserCapture ? `${String(report.browserCapture.sampleRateHz)}hz target, ${String(report.browserCapture.channelCount ?? 1)}ch` : "missing"}`,
|
|
11103
|
+
`- Resampling required: ${report.browserCapture?.resamplingRequired ? "yes" : "no"}`,
|
|
11104
|
+
`- Input audio samples: ${String(report.runtime.inputAudioSamples)}`,
|
|
11105
|
+
`- Assistant audio samples: ${String(report.runtime.assistantAudioSamples)}`,
|
|
11106
|
+
`- First audio latency: ${String(report.runtime.firstAudioLatencyMs ?? "n/a")}ms`,
|
|
11107
|
+
"",
|
|
11108
|
+
"## Issues",
|
|
11109
|
+
"",
|
|
11110
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue.severity.toUpperCase()} ${issue.code}: ${issue.message}`) : ["- None"]
|
|
11111
|
+
].join(`
|
|
11112
|
+
`);
|
|
11113
|
+
var renderVoiceRealtimeChannelHTML = (report, title = "Voice Realtime Channel Proof") => {
|
|
11114
|
+
const issues = report.issues.map((issue) => `<li class="${escapeHtml12(issue.severity)}"><strong>${escapeHtml12(issue.code)}</strong>: ${escapeHtml12(issue.message)}</li>`).join("");
|
|
11115
|
+
const rows = report.runtime.samples.map((sample) => `<tr><td>${escapeHtml12(sample.kind)}</td><td>${escapeHtml12(sample.source ?? "runtime")}</td><td>${escapeHtml12(sample.format ? formatLabel(sample.format) : "n/a")}</td><td>${escapeHtml12(sample.latencyMs ?? "n/a")}</td><td>${escapeHtml12(sample.ok ?? true)}</td></tr>`).join("");
|
|
11116
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml12(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.card{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(59,130,246,.12))}.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:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}.metric{background:#101814;border:1px solid #2e3d36;border-radius:18px;padding:14px}.metric span{color:#a8b5ad;display:block;font-size:.78rem;text-transform:uppercase}.metric strong{display:block;font-size:1.65rem;margin-top:5px}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:7px 11px}.pass{color:#86efac}.warn{color:#fde68a}.fail,.error{color:#fecaca}.warning{color:#fde68a}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3d36;padding:10px;text-align:left}.links a{color:#5eead4;margin-right:12px}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime / duplex readiness</p><h1>${escapeHtml12(title)}</h1><p class="status ${escapeHtml12(report.status)}">${escapeHtml12(report.status)}</p><p>Provider <strong>${escapeHtml12(report.provider)}</strong> \xB7 ${escapeHtml12(report.surface)}</p><p class="links">${report.readinessHref ? `<a href="${escapeHtml12(report.readinessHref)}">Readiness</a>` : ""}${report.operationsRecordHref ? `<a href="${escapeHtml12(report.operationsRecordHref)}">Operations record</a>` : ""}</p><section class="summary"><div class="metric"><span>Input</span><strong>${escapeHtml12(formatLabel(report.inputFormat))}</strong></div><div class="metric"><span>Output</span><strong>${escapeHtml12(formatLabel(report.outputFormat))}</strong></div><div class="metric"><span>Browser capture</span><strong>${escapeHtml12(report.browserCapture ? `${String(report.browserCapture.sampleRateHz)}hz` : "missing")}</strong></div><div class="metric"><span>Resampling</span><strong>${report.browserCapture?.resamplingRequired ? "required" : "not required"}</strong></div><div class="metric"><span>Input samples</span><strong>${String(report.runtime.inputAudioSamples)}</strong></div><div class="metric"><span>Assistant samples</span><strong>${String(report.runtime.assistantAudioSamples)}</strong></div></section></section><section class="card"><h2>Issues</h2><ul>${issues || '<li class="pass">No realtime channel issues.</li>'}</ul></section><section class="card"><h2>Runtime Samples</h2><table><thead><tr><th>Kind</th><th>Source</th><th>Format</th><th>Latency ms</th><th>OK</th></tr></thead><tbody>${rows || '<tr><td colspan="5">No runtime samples configured.</td></tr>'}</tbody></table></section></main></body></html>`;
|
|
11117
|
+
};
|
|
11118
|
+
var createVoiceRealtimeChannelRoutes = (options) => {
|
|
11119
|
+
const path = options.path ?? "/api/voice/realtime-channel";
|
|
11120
|
+
const htmlPath = options.htmlPath ?? "/voice/realtime-channel";
|
|
11121
|
+
const markdownPath = options.markdownPath ?? "/voice/realtime-channel.md";
|
|
11122
|
+
const headers = options.headers ?? {};
|
|
11123
|
+
const title = options.title ?? "Voice Realtime Channel Proof";
|
|
11124
|
+
const report = () => buildVoiceRealtimeChannelReport(options);
|
|
11125
|
+
const app = new Elysia9({ name: options.name ?? "voice-realtime-channel" }).get(path, () => new Response(JSON.stringify(report(), null, 2), {
|
|
11126
|
+
headers: {
|
|
11127
|
+
"content-type": "application/json; charset=utf-8",
|
|
11128
|
+
...headers
|
|
11129
|
+
}
|
|
11130
|
+
}));
|
|
11131
|
+
if (htmlPath !== false) {
|
|
11132
|
+
app.get(htmlPath, async () => {
|
|
11133
|
+
const current = report();
|
|
11134
|
+
const body = options.render ? await options.render(current) : renderVoiceRealtimeChannelHTML(current, title);
|
|
11135
|
+
return new Response(body, {
|
|
11136
|
+
headers: {
|
|
11137
|
+
"content-type": "text/html; charset=utf-8",
|
|
11138
|
+
...headers
|
|
11139
|
+
}
|
|
11140
|
+
});
|
|
11141
|
+
});
|
|
11142
|
+
}
|
|
11143
|
+
if (markdownPath !== false) {
|
|
11144
|
+
app.get(markdownPath, () => new Response(renderVoiceRealtimeChannelMarkdown(report()), {
|
|
11145
|
+
headers: {
|
|
11146
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
11147
|
+
...headers
|
|
11148
|
+
}
|
|
11149
|
+
}));
|
|
11150
|
+
}
|
|
11151
|
+
return app;
|
|
11152
|
+
};
|
|
11153
|
+
// src/diagnosticsRoutes.ts
|
|
11154
|
+
import { Elysia as Elysia10 } from "elysia";
|
|
11155
|
+
var escapeHtml13 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10926
11156
|
var getString6 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
10927
11157
|
var getNumber4 = (value) => {
|
|
10928
11158
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
|
|
@@ -10988,9 +11218,9 @@ var renderDiagnosticsIndex = (input) => {
|
|
|
10988
11218
|
const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
|
|
10989
11219
|
const summary = summarizeVoiceTrace(events);
|
|
10990
11220
|
const encoded = encodeURIComponent(sessionId);
|
|
10991
|
-
return `<tr><td>${
|
|
11221
|
+
return `<tr><td>${escapeHtml13(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>`;
|
|
10992
11222
|
}).join("");
|
|
10993
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11223
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml13(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>${escapeHtml13(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>`;
|
|
10994
11224
|
};
|
|
10995
11225
|
var withRedaction = (events, query, defaultRedact) => {
|
|
10996
11226
|
const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
|
|
@@ -10999,7 +11229,7 @@ var withRedaction = (events, query, defaultRedact) => {
|
|
|
10999
11229
|
var createVoiceDiagnosticsRoutes = (options) => {
|
|
11000
11230
|
const path = options.path ?? "/diagnostics";
|
|
11001
11231
|
const title = options.title ?? "AbsoluteJS Voice Diagnostics";
|
|
11002
|
-
const routes = new
|
|
11232
|
+
const routes = new Elysia10({
|
|
11003
11233
|
name: options.name ?? "absolutejs-voice-diagnostics"
|
|
11004
11234
|
});
|
|
11005
11235
|
routes.get(path, async () => {
|
|
@@ -11056,8 +11286,8 @@ var createVoiceDiagnosticsRoutes = (options) => {
|
|
|
11056
11286
|
return routes;
|
|
11057
11287
|
};
|
|
11058
11288
|
// src/demoReadyRoutes.ts
|
|
11059
|
-
import { Elysia as
|
|
11060
|
-
var
|
|
11289
|
+
import { Elysia as Elysia11 } from "elysia";
|
|
11290
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11061
11291
|
var rollupStatus = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
11062
11292
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
11063
11293
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
@@ -11141,17 +11371,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11141
11371
|
};
|
|
11142
11372
|
};
|
|
11143
11373
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
11144
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
11145
|
-
<div><span>${
|
|
11146
|
-
<strong>${
|
|
11147
|
-
${section.href ? `<a href="${
|
|
11374
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml14(section.status)}">
|
|
11375
|
+
<div><span>${escapeHtml14(section.status.toUpperCase())}</span><h2>${escapeHtml14(section.label)}</h2>${section.description ? `<p>${escapeHtml14(section.description)}</p>` : ""}</div>
|
|
11376
|
+
<strong>${escapeHtml14(String(section.value ?? section.status))}</strong>
|
|
11377
|
+
${section.href ? `<a href="${escapeHtml14(section.href)}">Open</a>` : ""}
|
|
11148
11378
|
</article>`).join("");
|
|
11149
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11379
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml14(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>${escapeHtml14(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 ${escapeHtml14(report.status)}">Overall: ${escapeHtml14(report.status.toUpperCase())}</p><p>Checked ${escapeHtml14(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>`;
|
|
11150
11380
|
};
|
|
11151
11381
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
11152
11382
|
const path = options.path ?? "/api/demo-ready";
|
|
11153
11383
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
11154
|
-
const routes = new
|
|
11384
|
+
const routes = new Elysia11({
|
|
11155
11385
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
11156
11386
|
});
|
|
11157
11387
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -11170,7 +11400,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
11170
11400
|
return routes;
|
|
11171
11401
|
};
|
|
11172
11402
|
// src/deliverySinkRoutes.ts
|
|
11173
|
-
import { Elysia as
|
|
11403
|
+
import { Elysia as Elysia12 } from "elysia";
|
|
11174
11404
|
|
|
11175
11405
|
// src/queue.ts
|
|
11176
11406
|
var releaseLeaseScript = `
|
|
@@ -12113,7 +12343,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
12113
12343
|
};
|
|
12114
12344
|
|
|
12115
12345
|
// src/deliverySinkRoutes.ts
|
|
12116
|
-
var
|
|
12346
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12117
12347
|
var deliveryStatus = (summary) => {
|
|
12118
12348
|
if (!summary) {
|
|
12119
12349
|
return "warn";
|
|
@@ -12212,13 +12442,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
12212
12442
|
return "";
|
|
12213
12443
|
}
|
|
12214
12444
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
12215
|
-
const body = `<span>${
|
|
12216
|
-
return `<article>${surface.href ? `<a href="${
|
|
12445
|
+
const body = `<span>${escapeHtml15(surface.label)}</span><strong>${escapeHtml15(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
12446
|
+
return `<article>${surface.href ? `<a href="${escapeHtml15(surface.href)}">${body}</a>` : body}</article>`;
|
|
12217
12447
|
};
|
|
12218
12448
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
12219
12449
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
12220
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
12221
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12450
|
+
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${escapeHtml15(sink.kind)}</span><strong style="font-size:1.5rem">${escapeHtml15(sink.label)}</strong>${sink.description ? `<p class="muted">${escapeHtml15(sink.description)}</p>` : ""}${sink.mode ? `<p class="muted">Mode: ${escapeHtml15(sink.mode)}</p>` : ""}${sink.target ? `<p class="muted">Target: <code>${escapeHtml15(sink.target)}</code></p>` : ""}${sink.href ? `<p><a href="${escapeHtml15(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>';
|
|
12451
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{background:#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>${escapeHtml15(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 ${escapeHtml15(report.status)}">Overall: ${escapeHtml15(report.status.toUpperCase())}</p><p class="muted">Checked ${escapeHtml15(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({
|
|
12222
12452
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
12223
12453
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
12224
12454
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -12230,7 +12460,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
12230
12460
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
12231
12461
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
12232
12462
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
12233
|
-
const routes = new
|
|
12463
|
+
const routes = new Elysia12({
|
|
12234
12464
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
12235
12465
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
12236
12466
|
if (htmlPath !== false) {
|
|
@@ -12248,7 +12478,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
12248
12478
|
return routes;
|
|
12249
12479
|
};
|
|
12250
12480
|
// src/opsActionAuditRoutes.ts
|
|
12251
|
-
import { Elysia as
|
|
12481
|
+
import { Elysia as Elysia13 } from "elysia";
|
|
12252
12482
|
var readRecordBody = (body) => {
|
|
12253
12483
|
if (!body || typeof body !== "object") {
|
|
12254
12484
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -12323,7 +12553,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
12323
12553
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
12324
12554
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
12325
12555
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
12326
|
-
const routes = new
|
|
12556
|
+
const routes = new Elysia13({
|
|
12327
12557
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
12328
12558
|
}).post(path, async ({ body, request, set }) => {
|
|
12329
12559
|
try {
|
|
@@ -12373,13 +12603,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
12373
12603
|
total: entries.length
|
|
12374
12604
|
};
|
|
12375
12605
|
};
|
|
12376
|
-
var
|
|
12606
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12377
12607
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
12378
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
12608
|
+
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml16(entry.ok ? "success" : "error")}</span><strong>${escapeHtml16(entry.actionId)}</strong><p>${escapeHtml16(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml16(entry.error)}</p>` : ""}</article>`).join("");
|
|
12379
12609
|
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>`;
|
|
12380
12610
|
};
|
|
12381
12611
|
// src/platformCoverage.ts
|
|
12382
|
-
import { Elysia as
|
|
12612
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12383
12613
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
12384
12614
|
const coverage = input.coverage ?? [];
|
|
12385
12615
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -12440,7 +12670,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
12440
12670
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
12441
12671
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
12442
12672
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
12443
|
-
const routes = new
|
|
12673
|
+
const routes = new Elysia14({
|
|
12444
12674
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
12445
12675
|
});
|
|
12446
12676
|
routes.get(path, async () => {
|
|
@@ -12452,8 +12682,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
12452
12682
|
return routes;
|
|
12453
12683
|
};
|
|
12454
12684
|
// src/competitiveCoverage.ts
|
|
12455
|
-
import { Elysia as
|
|
12456
|
-
var
|
|
12685
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12686
|
+
var escapeHtml17 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12457
12687
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
12458
12688
|
var resolveSurfaceStatus = (surface) => {
|
|
12459
12689
|
if (surface.status)
|
|
@@ -12621,24 +12851,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
12621
12851
|
`);
|
|
12622
12852
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
12623
12853
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
12624
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
12625
|
-
return `<article class="surface ${
|
|
12626
|
-
<header><div><p class="eyebrow">${
|
|
12627
|
-
<p>${
|
|
12854
|
+
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${escapeHtml17(item.name)}</strong>${item.kind ? ` <span>${escapeHtml17(item.kind)}</span>` : ""}${item.status ? ` <em>${escapeHtml17(item.status)}</em>` : ""}${item.href ? ` <a href="${escapeHtml17(item.href)}">open</a>` : ""}</li>`).join("");
|
|
12855
|
+
return `<article class="surface ${escapeHtml17(surface.status)} ${escapeHtml17(surface.depth)}">
|
|
12856
|
+
<header><div><p class="eyebrow">${escapeHtml17(surface.coverage)} \xB7 ${escapeHtml17(surface.depth)}</p><h2>${escapeHtml17(surface.surface)}</h2></div><strong>${escapeHtml17(surface.status)}</strong></header>
|
|
12857
|
+
<p>${escapeHtml17(surface.why)}</p>
|
|
12628
12858
|
<dl>
|
|
12629
|
-
<div><dt>Competitors</dt><dd>${
|
|
12630
|
-
<div><dt>Operations record</dt><dd>${
|
|
12631
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
12632
|
-
<div><dt>Frameworks</dt><dd>${
|
|
12859
|
+
<div><dt>Competitors</dt><dd>${escapeHtml17((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
12860
|
+
<div><dt>Operations record</dt><dd>${escapeHtml17(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
12861
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml17(surface.readinessGate ?? "unknown")}</dd></div>
|
|
12862
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml17((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
12633
12863
|
</dl>
|
|
12634
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
12635
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
12864
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml17(surface.remainingGap)}</p>` : ""}
|
|
12865
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml17(surface.nextMove)}</p>` : ""}
|
|
12636
12866
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
12637
12867
|
</article>`;
|
|
12638
12868
|
}).join(`
|
|
12639
12869
|
`);
|
|
12640
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
12641
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12870
|
+
const issueList = report.issues.map((issue) => `<li class="${escapeHtml17(issue.severity)}"><strong>${escapeHtml17(issue.code)}</strong>${issue.surface ? ` ${escapeHtml17(issue.surface)}` : ""}: ${escapeHtml17(issue.message)}</li>`).join("");
|
|
12871
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(title)}</title><style>body{background:#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>${escapeHtml17(title)}</h1><p>Generated ${escapeHtml17(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 ${escapeHtml17(report.status)}</span><span class="pill">Vapi-style ${escapeHtml17(report.vapiCoverageEstimate)}</span><span class="pill">Market ${escapeHtml17(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>`;
|
|
12642
12872
|
};
|
|
12643
12873
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
12644
12874
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -12651,7 +12881,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12651
12881
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
12652
12882
|
return normalizeCompetitiveCoverageReport(value);
|
|
12653
12883
|
};
|
|
12654
|
-
const app = new
|
|
12884
|
+
const app = new Elysia15({
|
|
12655
12885
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
12656
12886
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
12657
12887
|
headers: {
|
|
@@ -12682,7 +12912,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12682
12912
|
return app;
|
|
12683
12913
|
};
|
|
12684
12914
|
// src/proofTrends.ts
|
|
12685
|
-
import { Elysia as
|
|
12915
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12686
12916
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
12687
12917
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
12688
12918
|
var toTimeMs = (value) => {
|
|
@@ -12833,7 +13063,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
12833
13063
|
};
|
|
12834
13064
|
var createVoiceProofTrendRoutes = (options) => {
|
|
12835
13065
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
12836
|
-
const routes = new
|
|
13066
|
+
const routes = new Elysia16({
|
|
12837
13067
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
12838
13068
|
});
|
|
12839
13069
|
routes.get(path, async () => {
|
|
@@ -12866,11 +13096,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
12866
13096
|
return `${days}d ${hours % 24}h`;
|
|
12867
13097
|
};
|
|
12868
13098
|
// src/providerDecisionTraces.ts
|
|
12869
|
-
import { Elysia as
|
|
13099
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
12870
13100
|
|
|
12871
13101
|
// src/resilienceRoutes.ts
|
|
12872
|
-
import { Elysia as
|
|
12873
|
-
var
|
|
13102
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13103
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12874
13104
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
12875
13105
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
12876
13106
|
var getBoolean2 = (value) => value === true;
|
|
@@ -13018,13 +13248,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
13018
13248
|
};
|
|
13019
13249
|
var renderProviderCards = (title, providers) => {
|
|
13020
13250
|
if (providers.length === 0) {
|
|
13021
|
-
return `<p class="muted">No ${
|
|
13251
|
+
return `<p class="muted">No ${escapeHtml18(title)} provider health yet.</p>`;
|
|
13022
13252
|
}
|
|
13023
13253
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
13024
|
-
<article class="card provider ${
|
|
13254
|
+
<article class="card provider ${escapeHtml18(provider.status)}">
|
|
13025
13255
|
<div class="card-header">
|
|
13026
|
-
<strong>${
|
|
13027
|
-
<span>${
|
|
13256
|
+
<strong>${escapeHtml18(provider.provider)}</strong>
|
|
13257
|
+
<span>${escapeHtml18(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
13028
13258
|
</div>
|
|
13029
13259
|
<dl>
|
|
13030
13260
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -13033,7 +13263,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
13033
13263
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
13034
13264
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
13035
13265
|
</dl>
|
|
13036
|
-
${provider.lastError ? `<p class="muted">${
|
|
13266
|
+
${provider.lastError ? `<p class="muted">${escapeHtml18(provider.lastError)}</p>` : ""}
|
|
13037
13267
|
</article>
|
|
13038
13268
|
`).join("")}</div>`;
|
|
13039
13269
|
};
|
|
@@ -13042,24 +13272,24 @@ var renderTimeline2 = (events) => {
|
|
|
13042
13272
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
13043
13273
|
}
|
|
13044
13274
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
13045
|
-
<article class="card event ${
|
|
13275
|
+
<article class="card event ${escapeHtml18(event.status ?? "unknown")}">
|
|
13046
13276
|
<div class="card-header">
|
|
13047
|
-
<strong>${
|
|
13277
|
+
<strong>${escapeHtml18(event.kind.toUpperCase())} ${escapeHtml18(event.operation ?? "generate")}</strong>
|
|
13048
13278
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
13049
13279
|
</div>
|
|
13050
13280
|
<p>
|
|
13051
|
-
<span class="pill">${
|
|
13052
|
-
<span class="pill">provider: ${
|
|
13053
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
13281
|
+
<span class="pill">${escapeHtml18(event.status ?? "unknown")}</span>
|
|
13282
|
+
<span class="pill">provider: ${escapeHtml18(event.provider ?? "unknown")}</span>
|
|
13283
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml18(event.fallbackProvider)}</span>` : ""}
|
|
13054
13284
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
13055
13285
|
</p>
|
|
13056
13286
|
<dl>
|
|
13057
13287
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
13058
13288
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
13059
13289
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
13060
|
-
<div><dt>Session</dt><dd>${
|
|
13290
|
+
<div><dt>Session</dt><dd>${escapeHtml18(event.sessionId)}</dd></div>
|
|
13061
13291
|
</dl>
|
|
13062
|
-
${event.error ? `<p class="muted">${
|
|
13292
|
+
${event.error ? `<p class="muted">${escapeHtml18(event.error)}</p>` : ""}
|
|
13063
13293
|
</article>
|
|
13064
13294
|
`).join("")}</div>`;
|
|
13065
13295
|
};
|
|
@@ -13069,9 +13299,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
13069
13299
|
const status = latest?.status ?? "idle";
|
|
13070
13300
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
13071
13301
|
return `<div>
|
|
13072
|
-
<dt>${
|
|
13073
|
-
<dd>${
|
|
13074
|
-
<small>${
|
|
13302
|
+
<dt>${escapeHtml18(kind.toUpperCase())}</dt>
|
|
13303
|
+
<dd>${escapeHtml18(provider)}${escapeHtml18(fallback)}</dd>
|
|
13304
|
+
<small>${escapeHtml18(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>
|
|
13075
13305
|
</div>`;
|
|
13076
13306
|
};
|
|
13077
13307
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -13079,10 +13309,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
13079
13309
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
13080
13310
|
}
|
|
13081
13311
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
13082
|
-
<article class="card session ${
|
|
13312
|
+
<article class="card session ${escapeHtml18(session.status)}">
|
|
13083
13313
|
<div class="card-header">
|
|
13084
|
-
<strong>${
|
|
13085
|
-
<span>${
|
|
13314
|
+
<strong>${escapeHtml18(session.sessionId)}</strong>
|
|
13315
|
+
<span>${escapeHtml18(session.status)}</span>
|
|
13086
13316
|
</div>
|
|
13087
13317
|
<p>
|
|
13088
13318
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -13109,21 +13339,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
13109
13339
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
13110
13340
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
13111
13341
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
13112
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
13113
|
-
<p class="muted">${
|
|
13342
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml18(pathPrefix)}">
|
|
13343
|
+
<p class="muted">${escapeHtml18(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
13114
13344
|
<div class="simulate-actions">
|
|
13115
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
13116
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
13345
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml18(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml18(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
13346
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml18(provider.provider)}">Mark ${escapeHtml18(provider.provider)} recovered</button>`).join("")}
|
|
13117
13347
|
</div>
|
|
13118
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
13348
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml18(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
13119
13349
|
<pre class="simulate-output" hidden></pre>
|
|
13120
13350
|
</div>`;
|
|
13121
13351
|
};
|
|
13122
13352
|
var renderVoiceResilienceHTML = (input) => {
|
|
13123
13353
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
13124
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
13125
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
13126
|
-
const snippet =
|
|
13354
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml18(kind)}: ${String(count)}</span>`).join("");
|
|
13355
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join(" \xB7 ") : "";
|
|
13356
|
+
const snippet = escapeHtml18(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
13127
13357
|
kind: 'stt',
|
|
13128
13358
|
providers: ['deepgram', 'assemblyai'],
|
|
13129
13359
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -13161,7 +13391,7 @@ app.use(
|
|
|
13161
13391
|
<head>
|
|
13162
13392
|
<meta charset="utf-8" />
|
|
13163
13393
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13164
|
-
<title>${
|
|
13394
|
+
<title>${escapeHtml18(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
13165
13395
|
<style>
|
|
13166
13396
|
:root { color-scheme: dark; }
|
|
13167
13397
|
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; }
|
|
@@ -13313,7 +13543,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
13313
13543
|
};
|
|
13314
13544
|
var createVoiceResilienceRoutes = (options) => {
|
|
13315
13545
|
const path = options.path ?? "/resilience";
|
|
13316
|
-
const routes = new
|
|
13546
|
+
const routes = new Elysia17({
|
|
13317
13547
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
13318
13548
|
}).get(path, async () => {
|
|
13319
13549
|
const events = await options.store.list();
|
|
@@ -13354,7 +13584,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
13354
13584
|
};
|
|
13355
13585
|
|
|
13356
13586
|
// src/providerDecisionTraces.ts
|
|
13357
|
-
var
|
|
13587
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13358
13588
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
13359
13589
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13360
13590
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -13595,7 +13825,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
13595
13825
|
<head>
|
|
13596
13826
|
<meta charset="utf-8" />
|
|
13597
13827
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13598
|
-
<title>${
|
|
13828
|
+
<title>${escapeHtml19(title)}</title>
|
|
13599
13829
|
<style>
|
|
13600
13830
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
13601
13831
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -13609,8 +13839,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13609
13839
|
</head>
|
|
13610
13840
|
<body>
|
|
13611
13841
|
<main>
|
|
13612
|
-
<p class="status ${report.status}">${
|
|
13613
|
-
<h1>${
|
|
13842
|
+
<p class="status ${report.status}">${escapeHtml19(report.status)}</p>
|
|
13843
|
+
<h1>${escapeHtml19(title)}</h1>
|
|
13614
13844
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
13615
13845
|
<section class="grid">
|
|
13616
13846
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -13621,10 +13851,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13621
13851
|
</section>
|
|
13622
13852
|
<section class="surfaces">
|
|
13623
13853
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
13624
|
-
<header><strong>${
|
|
13854
|
+
<header><strong>${escapeHtml19(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml19(surface.status)}</span></header>
|
|
13625
13855
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
13626
|
-
<p class="muted">Providers: ${
|
|
13627
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
13856
|
+
<p class="muted">Providers: ${escapeHtml19(surface.providers.join(", ") || "none")}</p>
|
|
13857
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml19(reason)}</code>`).join(" ")}</p>
|
|
13628
13858
|
</article>`).join(`
|
|
13629
13859
|
`)}
|
|
13630
13860
|
</section>
|
|
@@ -13638,7 +13868,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13638
13868
|
const headers = options.headers ?? {};
|
|
13639
13869
|
const title = options.title ?? "Provider Decision Traces";
|
|
13640
13870
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
13641
|
-
const app = new
|
|
13871
|
+
const app = new Elysia18({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13642
13872
|
headers: {
|
|
13643
13873
|
"content-type": "application/json; charset=utf-8",
|
|
13644
13874
|
...headers
|
|
@@ -13666,7 +13896,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13666
13896
|
return app;
|
|
13667
13897
|
};
|
|
13668
13898
|
// src/sloCalibration.ts
|
|
13669
|
-
import { Elysia as
|
|
13899
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13670
13900
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
13671
13901
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
13672
13902
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -13846,7 +14076,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
13846
14076
|
};
|
|
13847
14077
|
};
|
|
13848
14078
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
13849
|
-
var
|
|
14079
|
+
var escapeHtml20 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13850
14080
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
13851
14081
|
var readinessThresholdRows = (report) => [
|
|
13852
14082
|
{
|
|
@@ -13937,15 +14167,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
13937
14167
|
};
|
|
13938
14168
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
13939
14169
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
13940
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
13941
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
13942
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
13943
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
14170
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml20(row.control)}</td><td>${escapeHtml20(formatMs(row.value))}</td><td>${escapeHtml20(row.usedBy)}</td></tr>`).join("");
|
|
14171
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml20(issue)}</li>`).join("");
|
|
14172
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml20(source)}</code></li>`).join("");
|
|
14173
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml20(title)}</title><style>body{background:#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>${escapeHtml20(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">${escapeHtml20(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml20(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml20(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml20(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>`;
|
|
13944
14174
|
};
|
|
13945
14175
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
13946
14176
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
13947
14177
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
13948
|
-
const routes = new
|
|
14178
|
+
const routes = new Elysia19({
|
|
13949
14179
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
13950
14180
|
});
|
|
13951
14181
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -13969,7 +14199,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
13969
14199
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
13970
14200
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
13971
14201
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
13972
|
-
const routes = new
|
|
14202
|
+
const routes = new Elysia19({
|
|
13973
14203
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
13974
14204
|
});
|
|
13975
14205
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14003,7 +14233,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14003
14233
|
return routes;
|
|
14004
14234
|
};
|
|
14005
14235
|
// src/liveOps.ts
|
|
14006
|
-
import { Elysia as
|
|
14236
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
14007
14237
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
14008
14238
|
"assign",
|
|
14009
14239
|
"create-task",
|
|
@@ -14313,7 +14543,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14313
14543
|
const controller = createVoiceLiveOpsController(options);
|
|
14314
14544
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
14315
14545
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
14316
|
-
return new
|
|
14546
|
+
return new Elysia20({
|
|
14317
14547
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
14318
14548
|
}).post(path, async ({ request, set }) => {
|
|
14319
14549
|
try {
|
|
@@ -14335,15 +14565,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14335
14565
|
});
|
|
14336
14566
|
};
|
|
14337
14567
|
// src/deliveryRuntime.ts
|
|
14338
|
-
import { Elysia as
|
|
14568
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14339
14569
|
import { mkdir } from "fs/promises";
|
|
14340
14570
|
import { dirname, join } from "path";
|
|
14341
|
-
var
|
|
14571
|
+
var escapeHtml21 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14342
14572
|
var renderSummaryCard = (label, summary) => {
|
|
14343
14573
|
if (!summary) {
|
|
14344
|
-
return `<article><span>${
|
|
14574
|
+
return `<article><span>${escapeHtml21(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
14345
14575
|
}
|
|
14346
|
-
return `<article><span>${
|
|
14576
|
+
return `<article><span>${escapeHtml21(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>`;
|
|
14347
14577
|
};
|
|
14348
14578
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
14349
14579
|
audit: leases,
|
|
@@ -14554,9 +14784,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
14554
14784
|
});
|
|
14555
14785
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
14556
14786
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
14557
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
14558
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
14559
|
-
const snippet =
|
|
14787
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml21(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
14788
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml21(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
14789
|
+
const snippet = escapeHtml21(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
14560
14790
|
createVoiceDeliveryRuntimePresetConfig({
|
|
14561
14791
|
audit: {
|
|
14562
14792
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -14582,14 +14812,14 @@ app.use(
|
|
|
14582
14812
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
14583
14813
|
})
|
|
14584
14814
|
);`);
|
|
14585
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14815
|
+
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:#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>${escapeHtml21(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 ${escapeHtml21(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>`;
|
|
14586
14816
|
};
|
|
14587
14817
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
14588
14818
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
14589
14819
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
14590
14820
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
14591
14821
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
14592
|
-
const routes = new
|
|
14822
|
+
const routes = new Elysia21({
|
|
14593
14823
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
14594
14824
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
14595
14825
|
if (tickPath !== false) {
|
|
@@ -14625,7 +14855,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
14625
14855
|
return routes;
|
|
14626
14856
|
};
|
|
14627
14857
|
// src/dataControl.ts
|
|
14628
|
-
import { Elysia as
|
|
14858
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14629
14859
|
var voiceComplianceRedactionDefaults = {
|
|
14630
14860
|
keys: [
|
|
14631
14861
|
"apiKey",
|
|
@@ -14864,7 +15094,7 @@ var parseRetentionScopes = (value) => {
|
|
|
14864
15094
|
const allowed = new Set(allRetentionScopes);
|
|
14865
15095
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
14866
15096
|
};
|
|
14867
|
-
var
|
|
15097
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14868
15098
|
var buildStorageSurfaces = (options) => [
|
|
14869
15099
|
{
|
|
14870
15100
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -15101,12 +15331,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
15101
15331
|
zeroRetentionAvailable: true
|
|
15102
15332
|
};
|
|
15103
15333
|
};
|
|
15104
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
15334
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml22(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml22(scope.skippedReason ?? "")}</td><td><code>${escapeHtml22(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
15105
15335
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
15106
15336
|
const title = options.title ?? "Voice Data Control";
|
|
15107
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
15108
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
15109
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
15337
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml22(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml22(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
15338
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml22(key.name)}</td><td><code>${escapeHtml22(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml22(key.recommendation)}</td></tr>`).join("");
|
|
15339
|
+
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:#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>${escapeHtml22(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>`;
|
|
15110
15340
|
};
|
|
15111
15341
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
15112
15342
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -15164,7 +15394,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
15164
15394
|
var createVoiceDataControlRoutes = (options) => {
|
|
15165
15395
|
const path = options.path ?? "/data-control";
|
|
15166
15396
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
15167
|
-
const routes = new
|
|
15397
|
+
const routes = new Elysia22({
|
|
15168
15398
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
15169
15399
|
});
|
|
15170
15400
|
routes.get(path, async ({ query }) => {
|
|
@@ -15240,16 +15470,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
15240
15470
|
return routes;
|
|
15241
15471
|
};
|
|
15242
15472
|
// src/evalRoutes.ts
|
|
15243
|
-
import { Elysia as
|
|
15473
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15244
15474
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
15245
15475
|
import { dirname as dirname2 } from "path";
|
|
15246
15476
|
|
|
15247
15477
|
// src/qualityRoutes.ts
|
|
15248
|
-
import { Elysia as
|
|
15478
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15249
15479
|
|
|
15250
15480
|
// src/handoffHealth.ts
|
|
15251
|
-
import { Elysia as
|
|
15252
|
-
var
|
|
15481
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
15482
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15253
15483
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15254
15484
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
15255
15485
|
var increment3 = (record, key) => {
|
|
@@ -15367,10 +15597,10 @@ var renderActionSummary = (summary) => {
|
|
|
15367
15597
|
return [
|
|
15368
15598
|
'<section class="voice-handoff-health-columns">',
|
|
15369
15599
|
"<article><h3>Actions</h3>",
|
|
15370
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
15600
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml23(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
15371
15601
|
"</article>",
|
|
15372
15602
|
"<article><h3>Adapters</h3>",
|
|
15373
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
15603
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml23(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
15374
15604
|
"</article>",
|
|
15375
15605
|
"</section>"
|
|
15376
15606
|
].join("");
|
|
@@ -15384,22 +15614,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
15384
15614
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
15385
15615
|
'<div class="voice-handoff-health-events">',
|
|
15386
15616
|
...summary.events.map((event) => [
|
|
15387
|
-
`<article class="${
|
|
15617
|
+
`<article class="${escapeHtml23(event.status)}">`,
|
|
15388
15618
|
'<div class="voice-handoff-health-event-header">',
|
|
15389
|
-
`<strong>${
|
|
15390
|
-
`<span>${
|
|
15619
|
+
`<strong>${escapeHtml23(event.action ?? "handoff")}</strong>`,
|
|
15620
|
+
`<span>${escapeHtml23(event.status)}</span>`,
|
|
15391
15621
|
"</div>",
|
|
15392
|
-
`<p><small>${
|
|
15393
|
-
event.target ? `<p>Target: ${
|
|
15394
|
-
event.reason ? `<p>Reason: ${
|
|
15622
|
+
`<p><small>${escapeHtml23(event.sessionId)}</small></p>`,
|
|
15623
|
+
event.target ? `<p>Target: ${escapeHtml23(event.target)}</p>` : "",
|
|
15624
|
+
event.reason ? `<p>Reason: ${escapeHtml23(event.reason)}</p>` : "",
|
|
15395
15625
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
15396
15626
|
"<li>",
|
|
15397
|
-
`${
|
|
15398
|
-
delivery.deliveredTo ? ` to ${
|
|
15399
|
-
delivery.error ? ` (${
|
|
15627
|
+
`${escapeHtml23(delivery.adapterId)}: ${escapeHtml23(delivery.status)}`,
|
|
15628
|
+
delivery.deliveredTo ? ` to ${escapeHtml23(delivery.deliveredTo)}` : "",
|
|
15629
|
+
delivery.error ? ` (${escapeHtml23(delivery.error)})` : "",
|
|
15400
15630
|
"</li>"
|
|
15401
15631
|
].join("")).join("")}</ul>` : "",
|
|
15402
|
-
event.replayHref ? `<p><a href="${
|
|
15632
|
+
event.replayHref ? `<p><a href="${escapeHtml23(event.replayHref)}">Open replay</a></p>` : "",
|
|
15403
15633
|
"</article>"
|
|
15404
15634
|
].join("")),
|
|
15405
15635
|
"</div>"
|
|
@@ -15431,7 +15661,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
15431
15661
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
15432
15662
|
const path = options.path ?? "/api/voice-handoffs";
|
|
15433
15663
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
15434
|
-
const routes = new
|
|
15664
|
+
const routes = new Elysia23({
|
|
15435
15665
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
15436
15666
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
15437
15667
|
if (htmlPath) {
|
|
@@ -15552,17 +15782,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
15552
15782
|
thresholds
|
|
15553
15783
|
};
|
|
15554
15784
|
};
|
|
15555
|
-
var
|
|
15785
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15556
15786
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
15557
15787
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
15558
15788
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
15559
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
15560
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
15789
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml24(metric.label)}</td><td>${escapeHtml24(formatMetricValue(metric))}</td><td>${escapeHtml24(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml24(key)}</code></td></tr>`).join("");
|
|
15790
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml24(link.href)}">${escapeHtml24(link.label)}</a>`).join("")}</nav>` : "";
|
|
15561
15791
|
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>`;
|
|
15562
15792
|
};
|
|
15563
15793
|
var createVoiceQualityRoutes = (options) => {
|
|
15564
15794
|
const path = options.path ?? "/quality";
|
|
15565
|
-
const routes = new
|
|
15795
|
+
const routes = new Elysia24({
|
|
15566
15796
|
name: options.name ?? "absolutejs-voice-quality"
|
|
15567
15797
|
});
|
|
15568
15798
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -15591,7 +15821,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
15591
15821
|
};
|
|
15592
15822
|
|
|
15593
15823
|
// src/evalRoutes.ts
|
|
15594
|
-
var
|
|
15824
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15595
15825
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
15596
15826
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
15597
15827
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -15913,7 +16143,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
15913
16143
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
15914
16144
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
15915
16145
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
15916
|
-
const snippet =
|
|
16146
|
+
const snippet = escapeHtml25(`app.use(
|
|
15917
16147
|
createVoiceEvalRoutes({
|
|
15918
16148
|
path: '/evals',
|
|
15919
16149
|
store: traceStore,
|
|
@@ -15934,48 +16164,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
15934
16164
|
};
|
|
15935
16165
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
15936
16166
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
15937
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
15938
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
16167
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
16168
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml25(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>';
|
|
15939
16169
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
15940
16170
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
15941
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
15942
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16171
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml25(session.operationsRecordHref)}">${escapeHtml25(session.sessionId)}</a>` : escapeHtml25(session.sessionId);
|
|
16172
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml25(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml25(formatTime(session.endedAt))}</td><td>${escapeHtml25(failedMetrics || "none")}</td></tr>`;
|
|
15943
16173
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
15944
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16174
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{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>${escapeHtml25(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>`;
|
|
15945
16175
|
};
|
|
15946
16176
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
15947
16177
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
15948
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
15949
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
15950
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
15951
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
15952
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16178
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
16179
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml25(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
16180
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml25(id)}</li>`).join("") : "<li>none</li>";
|
|
16181
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml25(id)}</li>`).join("") : "<li>none</li>";
|
|
16182
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{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>${escapeHtml25(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml25(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml25(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>${escapeHtml25(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>`;
|
|
15953
16183
|
};
|
|
15954
16184
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
15955
16185
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
15956
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16186
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15957
16187
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
15958
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
16188
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml25(issue)}</li>`).join("")}</ul>` : "";
|
|
15959
16189
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
15960
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
15961
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
16190
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml25(session.operationsRecordHref)}">${escapeHtml25(session.sessionId)}</a>` : escapeHtml25(session.sessionId);
|
|
16191
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml25(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml25(session.issues.join(", ") || "none")}</td></tr>`;
|
|
15962
16192
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
15963
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
16193
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml25(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml25(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>`;
|
|
15964
16194
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
15965
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16195
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{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>${escapeHtml25(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>`;
|
|
15966
16196
|
};
|
|
15967
16197
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
15968
16198
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
15969
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16199
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15970
16200
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
15971
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
15972
|
-
return `<section class="${fixture.status}"><h2>${
|
|
16201
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml25(scenario.label)}</td><td>${escapeHtml25(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml25([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
16202
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml25(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml25(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>`;
|
|
15973
16203
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
15974
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16204
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(title)}</title><style>body{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>${escapeHtml25(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>`;
|
|
15975
16205
|
};
|
|
15976
16206
|
var createVoiceEvalRoutes = (options) => {
|
|
15977
16207
|
const path = options.path ?? "/evals";
|
|
15978
|
-
const routes = new
|
|
16208
|
+
const routes = new Elysia25({
|
|
15979
16209
|
name: options.name ?? "absolutejs-voice-evals"
|
|
15980
16210
|
});
|
|
15981
16211
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -16112,11 +16342,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
16112
16342
|
return routes;
|
|
16113
16343
|
};
|
|
16114
16344
|
// src/simulationSuite.ts
|
|
16115
|
-
import { Elysia as
|
|
16345
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16116
16346
|
|
|
16117
16347
|
// src/outcomeContract.ts
|
|
16118
|
-
import { Elysia as
|
|
16119
|
-
var
|
|
16348
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
16349
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16120
16350
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
16121
16351
|
if (value === false) {
|
|
16122
16352
|
return;
|
|
@@ -16327,13 +16557,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
16327
16557
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
16328
16558
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
16329
16559
|
const contracts = report.contracts.map((contract) => {
|
|
16330
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
16560
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml26(href)}">${escapeHtml26(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
16331
16561
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16332
16562
|
<div class="contract-header">
|
|
16333
16563
|
<div>
|
|
16334
|
-
<p class="eyebrow">${
|
|
16335
|
-
<h2>${
|
|
16336
|
-
${contract.description ? `<p>${
|
|
16564
|
+
<p class="eyebrow">${escapeHtml26(contract.contractId)}</p>
|
|
16565
|
+
<h2>${escapeHtml26(contract.label ?? contract.contractId)}</h2>
|
|
16566
|
+
${contract.description ? `<p>${escapeHtml26(contract.description)}</p>` : ""}
|
|
16337
16567
|
${sessionLinks}
|
|
16338
16568
|
</div>
|
|
16339
16569
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -16345,10 +16575,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
16345
16575
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
16346
16576
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
16347
16577
|
</div>
|
|
16348
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
16578
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml26(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
16349
16579
|
</section>`;
|
|
16350
16580
|
}).join("");
|
|
16351
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16581
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.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>${escapeHtml26(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>`;
|
|
16352
16582
|
};
|
|
16353
16583
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
16354
16584
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -16364,7 +16594,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
16364
16594
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
16365
16595
|
const path = options.path ?? "/api/outcome-contracts";
|
|
16366
16596
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16367
|
-
const routes = new
|
|
16597
|
+
const routes = new Elysia26({
|
|
16368
16598
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
16369
16599
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
16370
16600
|
if (htmlPath) {
|
|
@@ -16374,7 +16604,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
16374
16604
|
};
|
|
16375
16605
|
|
|
16376
16606
|
// src/toolContract.ts
|
|
16377
|
-
import { Elysia as
|
|
16607
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16378
16608
|
|
|
16379
16609
|
// src/toolRuntime.ts
|
|
16380
16610
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -16583,7 +16813,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
16583
16813
|
});
|
|
16584
16814
|
var defaultApi = {};
|
|
16585
16815
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
16586
|
-
var
|
|
16816
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16587
16817
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
16588
16818
|
if (value === false) {
|
|
16589
16819
|
return;
|
|
@@ -16832,7 +17062,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
16832
17062
|
};
|
|
16833
17063
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
16834
17064
|
const title = options.title ?? "Voice Tool Contracts";
|
|
16835
|
-
const snippet =
|
|
17065
|
+
const snippet = escapeHtml27(`app.use(
|
|
16836
17066
|
createVoiceToolContractRoutes({
|
|
16837
17067
|
htmlPath: '/tool-contracts',
|
|
16838
17068
|
path: '/api/tool-contracts',
|
|
@@ -16858,20 +17088,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
16858
17088
|
);`);
|
|
16859
17089
|
const contracts = report.contracts.map((contract) => {
|
|
16860
17090
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
16861
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
17091
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml27(testCase.operationsRecordHref)}">${escapeHtml27(testCase.label ?? testCase.caseId)}</a>` : escapeHtml27(testCase.label ?? testCase.caseId)}</td>
|
|
16862
17092
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
16863
|
-
<td>${
|
|
16864
|
-
<td>${
|
|
17093
|
+
<td>${escapeHtml27(testCase.status)}</td>
|
|
17094
|
+
<td>${escapeHtml27(testCase.sessionId)}</td>
|
|
16865
17095
|
<td>${String(testCase.attempts)}</td>
|
|
16866
17096
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
16867
17097
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
16868
|
-
<td>${
|
|
17098
|
+
<td>${escapeHtml27(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
16869
17099
|
</tr>`).join("");
|
|
16870
17100
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16871
17101
|
<div class="contract-header">
|
|
16872
17102
|
<div>
|
|
16873
|
-
<p class="eyebrow">${
|
|
16874
|
-
<h2>${
|
|
17103
|
+
<p class="eyebrow">${escapeHtml27(contract.toolName)}</p>
|
|
17104
|
+
<h2>${escapeHtml27(contract.label ?? contract.contractId)}</h2>
|
|
16875
17105
|
</div>
|
|
16876
17106
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
16877
17107
|
</div>
|
|
@@ -16881,7 +17111,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
16881
17111
|
</table>
|
|
16882
17112
|
</section>`;
|
|
16883
17113
|
}).join("");
|
|
16884
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17114
|
+
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,.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>${escapeHtml27(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml27(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>`;
|
|
16885
17115
|
};
|
|
16886
17116
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
16887
17117
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -16898,7 +17128,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
16898
17128
|
var createVoiceToolContractRoutes = (options) => {
|
|
16899
17129
|
const path = options.path ?? "/api/tool-contracts";
|
|
16900
17130
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16901
|
-
const routes = new
|
|
17131
|
+
const routes = new Elysia27({
|
|
16902
17132
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
16903
17133
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
16904
17134
|
if (htmlPath) {
|
|
@@ -16908,7 +17138,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
16908
17138
|
};
|
|
16909
17139
|
|
|
16910
17140
|
// src/simulationSuite.ts
|
|
16911
|
-
var
|
|
17141
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16912
17142
|
var summarizeSection = (report) => ({
|
|
16913
17143
|
failed: report.failed,
|
|
16914
17144
|
passed: report.passed,
|
|
@@ -17104,15 +17334,15 @@ var renderSection = (label, summary) => {
|
|
|
17104
17334
|
if (!summary) {
|
|
17105
17335
|
return "";
|
|
17106
17336
|
}
|
|
17107
|
-
return `<article class="${
|
|
17337
|
+
return `<article class="${escapeHtml28(summary.status)}"><span>${escapeHtml28(label)}</span><strong>${escapeHtml28(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
17108
17338
|
};
|
|
17109
17339
|
var renderAction = (action) => {
|
|
17110
|
-
const content = `<strong>${
|
|
17111
|
-
return action.href ? `<a class="action" href="${
|
|
17340
|
+
const content = `<strong>${escapeHtml28(action.label)}</strong><p>${escapeHtml28(action.description)}</p><span>${escapeHtml28(action.section)} / ${escapeHtml28(action.severity)}</span>`;
|
|
17341
|
+
return action.href ? `<a class="action" href="${escapeHtml28(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
17112
17342
|
};
|
|
17113
17343
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
17114
17344
|
const title = options.title ?? "Voice Simulation Suite";
|
|
17115
|
-
const snippet =
|
|
17345
|
+
const snippet = escapeHtml28(`app.use(
|
|
17116
17346
|
createVoiceSimulationSuiteRoutes({
|
|
17117
17347
|
htmlPath: '/voice/simulations',
|
|
17118
17348
|
path: '/api/voice/simulations',
|
|
@@ -17145,12 +17375,12 @@ app.use(
|
|
|
17145
17375
|
store: traceStore
|
|
17146
17376
|
})
|
|
17147
17377
|
);`);
|
|
17148
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17378
|
+
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:#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>${escapeHtml28(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml28(report.status)}">Status: ${escapeHtml28(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>${escapeHtml28(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
17149
17379
|
};
|
|
17150
17380
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
17151
17381
|
const path = options.path ?? "/api/voice/simulations";
|
|
17152
17382
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
17153
|
-
const app = new
|
|
17383
|
+
const app = new Elysia28({
|
|
17154
17384
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
17155
17385
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
17156
17386
|
if (htmlPath) {
|
|
@@ -17462,9 +17692,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
17462
17692
|
};
|
|
17463
17693
|
};
|
|
17464
17694
|
// src/sessionReplay.ts
|
|
17465
|
-
import { Elysia as
|
|
17695
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
17466
17696
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
17467
|
-
var
|
|
17697
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17468
17698
|
var increment4 = (record, key) => {
|
|
17469
17699
|
record[key] = (record[key] ?? 0) + 1;
|
|
17470
17700
|
};
|
|
@@ -17658,10 +17888,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
17658
17888
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
17659
17889
|
'<div class="voice-sessions-list">',
|
|
17660
17890
|
...sessions.map((session) => [
|
|
17661
|
-
`<article class="voice-session-card ${
|
|
17891
|
+
`<article class="voice-session-card ${escapeHtml29(session.status)}">`,
|
|
17662
17892
|
'<div class="voice-session-card-header">',
|
|
17663
|
-
`<strong>${
|
|
17664
|
-
`<span>${
|
|
17893
|
+
`<strong>${escapeHtml29(session.sessionId)}</strong>`,
|
|
17894
|
+
`<span>${escapeHtml29(session.status)}</span>`,
|
|
17665
17895
|
"</div>",
|
|
17666
17896
|
"<dl>",
|
|
17667
17897
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -17669,9 +17899,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
17669
17899
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
17670
17900
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
17671
17901
|
"</dl>",
|
|
17672
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
17673
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
17674
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
17902
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml29(session.latestOutcome)}</p>` : "",
|
|
17903
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml29).join(", ")}</p>` : "",
|
|
17904
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml29(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml29(session.replayHref)}">Open replay</a></p>` : "",
|
|
17675
17905
|
"</article>"
|
|
17676
17906
|
].join("")),
|
|
17677
17907
|
"</div>"
|
|
@@ -17702,7 +17932,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
17702
17932
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
17703
17933
|
const path = options.path ?? "/api/voice-sessions";
|
|
17704
17934
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17705
|
-
const routes = new
|
|
17935
|
+
const routes = new Elysia29({
|
|
17706
17936
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
17707
17937
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
17708
17938
|
if (htmlPath) {
|
|
@@ -17730,7 +17960,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
17730
17960
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
17731
17961
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
17732
17962
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17733
|
-
const routes = new
|
|
17963
|
+
const routes = new Elysia29({
|
|
17734
17964
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
17735
17965
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
17736
17966
|
if (htmlPath) {
|
|
@@ -18044,10 +18274,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
18044
18274
|
return report;
|
|
18045
18275
|
};
|
|
18046
18276
|
// src/turnLatency.ts
|
|
18047
|
-
import { Elysia as
|
|
18277
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
18048
18278
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
18049
18279
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
18050
|
-
var
|
|
18280
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18051
18281
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18052
18282
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
18053
18283
|
var createTraceStageIndex = (events) => {
|
|
@@ -18179,11 +18409,11 @@ await traceStore.append({
|
|
|
18179
18409
|
turnId,
|
|
18180
18410
|
type: 'turn_latency.stage'
|
|
18181
18411
|
});`;
|
|
18182
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18183
|
-
<header><div><p class="eyebrow">${
|
|
18184
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
18412
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml30(turn.status)}">
|
|
18413
|
+
<header><div><p class="eyebrow">${escapeHtml30(turn.sessionId)} \xB7 ${escapeHtml30(turn.turnId)}</p><h2>${escapeHtml30(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml30(turn.status)}</strong></header>
|
|
18414
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml30(stage.label)}</dt><dd>${escapeHtml30(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
18185
18415
|
</article>`).join("");
|
|
18186
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18416
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{background:#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>${escapeHtml30(title)}</h1><div class="summary"><span class="pill ${escapeHtml30(report.status)}">${escapeHtml30(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml30(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>${escapeHtml30(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
18187
18417
|
};
|
|
18188
18418
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
18189
18419
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -18200,7 +18430,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
18200
18430
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
18201
18431
|
const path = options.path ?? "/api/turn-latency";
|
|
18202
18432
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18203
|
-
const routes = new
|
|
18433
|
+
const routes = new Elysia30({
|
|
18204
18434
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
18205
18435
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
18206
18436
|
if (htmlPath) {
|
|
@@ -18209,8 +18439,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
18209
18439
|
return routes;
|
|
18210
18440
|
};
|
|
18211
18441
|
// src/liveLatency.ts
|
|
18212
|
-
import { Elysia as
|
|
18213
|
-
var
|
|
18442
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
18443
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18214
18444
|
var percentile3 = (values, percentileValue) => {
|
|
18215
18445
|
if (values.length === 0) {
|
|
18216
18446
|
return;
|
|
@@ -18277,13 +18507,13 @@ await traceStore.append({
|
|
|
18277
18507
|
sessionId,
|
|
18278
18508
|
type: 'client.live_latency'
|
|
18279
18509
|
});`;
|
|
18280
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
18281
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18510
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml31(sample.sessionId)}</td><td>${escapeHtml31(formatMs3(sample.latencyMs))}</td><td>${escapeHtml31(sample.status ?? "unknown")}</td><td>${escapeHtml31(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
18511
|
+
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:#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>${escapeHtml31(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml31(report.status)}">Status: ${escapeHtml31(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml31(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml31(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml31(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>${escapeHtml31(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>`;
|
|
18282
18512
|
};
|
|
18283
18513
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
18284
18514
|
const path = options.path ?? "/api/live-latency";
|
|
18285
18515
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
18286
|
-
const routes = new
|
|
18516
|
+
const routes = new Elysia31({
|
|
18287
18517
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
18288
18518
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
18289
18519
|
if (htmlPath) {
|
|
@@ -18602,9 +18832,9 @@ None.
|
|
|
18602
18832
|
`}`;
|
|
18603
18833
|
};
|
|
18604
18834
|
// src/turnQuality.ts
|
|
18605
|
-
import { Elysia as
|
|
18835
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
18606
18836
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
18607
|
-
var
|
|
18837
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18608
18838
|
var getTurnLatencyMs = (turn) => {
|
|
18609
18839
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18610
18840
|
if (firstTranscriptAt === undefined) {
|
|
@@ -18675,24 +18905,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
18675
18905
|
};
|
|
18676
18906
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
18677
18907
|
const title = options.title ?? "Voice Turn Quality";
|
|
18678
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18908
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml32(turn.status)}">
|
|
18679
18909
|
<div class="turn-header">
|
|
18680
18910
|
<div>
|
|
18681
|
-
<p class="eyebrow">${
|
|
18682
|
-
<h2>${
|
|
18911
|
+
<p class="eyebrow">${escapeHtml32(turn.sessionId)} \xB7 ${escapeHtml32(turn.turnId)}</p>
|
|
18912
|
+
<h2>${escapeHtml32(turn.text || "Empty turn")}</h2>
|
|
18683
18913
|
</div>
|
|
18684
|
-
<strong>${
|
|
18914
|
+
<strong>${escapeHtml32(turn.status)}</strong>
|
|
18685
18915
|
</div>
|
|
18686
18916
|
<dl>
|
|
18687
|
-
<div><dt>Source</dt><dd>${
|
|
18917
|
+
<div><dt>Source</dt><dd>${escapeHtml32(turn.source ?? "unknown")}</dd></div>
|
|
18688
18918
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
18689
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
18690
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
18919
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml32(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
18920
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml32(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
18691
18921
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
18692
18922
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
18693
18923
|
</dl>
|
|
18694
18924
|
</article>`).join("");
|
|
18695
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18925
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.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>${escapeHtml32(title)}</h1><div class="summary"><span class="pill ${escapeHtml32(report.status)}">${escapeHtml32(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>`;
|
|
18696
18926
|
};
|
|
18697
18927
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
18698
18928
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -18709,7 +18939,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
18709
18939
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
18710
18940
|
const path = options.path ?? "/api/turn-quality";
|
|
18711
18941
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18712
|
-
const routes = new
|
|
18942
|
+
const routes = new Elysia32({
|
|
18713
18943
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
18714
18944
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
18715
18945
|
if (htmlPath) {
|
|
@@ -18718,7 +18948,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
18718
18948
|
return routes;
|
|
18719
18949
|
};
|
|
18720
18950
|
// src/telephonyOutcome.ts
|
|
18721
|
-
import { Elysia as
|
|
18951
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18722
18952
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
18723
18953
|
"answered",
|
|
18724
18954
|
"completed",
|
|
@@ -19479,7 +19709,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
19479
19709
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
19480
19710
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
19481
19711
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
19482
|
-
return new
|
|
19712
|
+
return new Elysia33({
|
|
19483
19713
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
19484
19714
|
}).post(path, async ({ query, request }) => {
|
|
19485
19715
|
try {
|
|
@@ -19500,12 +19730,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
19500
19730
|
});
|
|
19501
19731
|
};
|
|
19502
19732
|
// src/phoneAgent.ts
|
|
19503
|
-
import { Elysia as
|
|
19733
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
19504
19734
|
|
|
19505
19735
|
// src/telephony/plivo.ts
|
|
19506
19736
|
import { Buffer as Buffer5 } from "buffer";
|
|
19507
19737
|
import { Database } from "bun:sqlite";
|
|
19508
|
-
import { Elysia as
|
|
19738
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19509
19739
|
|
|
19510
19740
|
// src/telephony/contract.ts
|
|
19511
19741
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -19589,7 +19819,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
19589
19819
|
|
|
19590
19820
|
// src/telephony/twilio.ts
|
|
19591
19821
|
import { Buffer as Buffer4 } from "buffer";
|
|
19592
|
-
import { Elysia as
|
|
19822
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19593
19823
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
19594
19824
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
19595
19825
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -19619,7 +19849,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
19619
19849
|
return parameters;
|
|
19620
19850
|
};
|
|
19621
19851
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19622
|
-
var
|
|
19852
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19623
19853
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
19624
19854
|
if (!webhook?.verificationUrl) {
|
|
19625
19855
|
return;
|
|
@@ -19662,23 +19892,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
19662
19892
|
};
|
|
19663
19893
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19664
19894
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
19665
|
-
<h1>${
|
|
19895
|
+
<h1>${escapeHtml33(title)}</h1>
|
|
19666
19896
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
19667
19897
|
<section>
|
|
19668
19898
|
<h2>URLs</h2>
|
|
19669
19899
|
<ul>
|
|
19670
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19671
|
-
<li><strong>Media stream:</strong> <code>${
|
|
19672
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
19900
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml33(status.urls.twiml)}</code></li>
|
|
19901
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml33(status.urls.stream)}</code></li>
|
|
19902
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml33(status.urls.webhook)}</code></li>
|
|
19673
19903
|
</ul>
|
|
19674
19904
|
</section>
|
|
19675
19905
|
<section>
|
|
19676
19906
|
<h2>Signing</h2>
|
|
19677
19907
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
19678
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
19908
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml33(status.signing.verificationUrl)}</code></p>` : ""}
|
|
19679
19909
|
</section>
|
|
19680
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
19681
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
19910
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml33(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
19911
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml33(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
19682
19912
|
</main>`;
|
|
19683
19913
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
19684
19914
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -19689,20 +19919,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
19689
19919
|
});
|
|
19690
19920
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19691
19921
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
19692
|
-
<h1>${
|
|
19922
|
+
<h1>${escapeHtml33(title)}</h1>
|
|
19693
19923
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
19694
19924
|
<section>
|
|
19695
19925
|
<h2>Checks</h2>
|
|
19696
19926
|
<ul>
|
|
19697
|
-
${report.checks.map((check) => `<li><strong>${
|
|
19927
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml33(check.name)}</strong>: ${escapeHtml33(check.status)}${check.message ? ` - ${escapeHtml33(check.message)}` : ""}</li>`).join("")}
|
|
19698
19928
|
</ul>
|
|
19699
19929
|
</section>
|
|
19700
19930
|
<section>
|
|
19701
19931
|
<h2>Observed URLs</h2>
|
|
19702
19932
|
<ul>
|
|
19703
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19704
|
-
<li><strong>Stream:</strong> <code>${
|
|
19705
|
-
<li><strong>Webhook:</strong> <code>${
|
|
19933
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml33(report.setup.urls.twiml)}</code></li>
|
|
19934
|
+
<li><strong>Stream:</strong> <code>${escapeHtml33(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
19935
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml33(report.setup.urls.webhook)}</code></li>
|
|
19706
19936
|
</ul>
|
|
19707
19937
|
</section>
|
|
19708
19938
|
</main>`;
|
|
@@ -20162,7 +20392,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20162
20392
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
20163
20393
|
const bridges = new WeakMap;
|
|
20164
20394
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
20165
|
-
const app = new
|
|
20395
|
+
const app = new Elysia34({
|
|
20166
20396
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
20167
20397
|
}).get(twimlPath, async ({ query, request }) => {
|
|
20168
20398
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -20299,7 +20529,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20299
20529
|
|
|
20300
20530
|
// src/telephony/plivo.ts
|
|
20301
20531
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20302
|
-
var
|
|
20532
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20303
20533
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20304
20534
|
var resolveRequestOrigin2 = (request) => {
|
|
20305
20535
|
const url = new URL(request.url);
|
|
@@ -20729,21 +20959,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
20729
20959
|
};
|
|
20730
20960
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20731
20961
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
20732
|
-
<h1>${
|
|
20962
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
20733
20963
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20734
20964
|
<ul>
|
|
20735
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
20736
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
20737
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
20965
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml34(status.urls.answer)}</code></li>
|
|
20966
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml34(status.urls.stream)}</code></li>
|
|
20967
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml34(status.urls.webhook)}</code></li>
|
|
20738
20968
|
</ul>
|
|
20739
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20740
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
20969
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml34(name)}</code></li>`).join("")}</ul>` : ""}
|
|
20970
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml34(warning)}</li>`).join("")}</ul>` : ""}
|
|
20741
20971
|
</main>`;
|
|
20742
20972
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20743
20973
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
20744
|
-
<h1>${
|
|
20974
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
20745
20975
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20746
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
20976
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml34(check.name)}</strong>: ${escapeHtml34(check.status)}${check.message ? ` - ${escapeHtml34(check.message)}` : ""}</li>`).join("")}</ul>
|
|
20747
20977
|
</main>`;
|
|
20748
20978
|
var runPlivoSmokeTest = async (input) => {
|
|
20749
20979
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -20833,7 +21063,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
20833
21063
|
nonceStore: options.webhook.nonceStore,
|
|
20834
21064
|
verificationUrl: options.webhook.verificationUrl
|
|
20835
21065
|
}) : undefined);
|
|
20836
|
-
const app = new
|
|
21066
|
+
const app = new Elysia35({
|
|
20837
21067
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
20838
21068
|
}).get(answerPath, async ({ query, request }) => {
|
|
20839
21069
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -20945,9 +21175,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
20945
21175
|
// src/telephony/telnyx.ts
|
|
20946
21176
|
import { Buffer as Buffer6 } from "buffer";
|
|
20947
21177
|
import { Database as Database2 } from "bun:sqlite";
|
|
20948
|
-
import { Elysia as
|
|
21178
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
20949
21179
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20950
|
-
var
|
|
21180
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20951
21181
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20952
21182
|
var resolveRequestOrigin3 = (request) => {
|
|
20953
21183
|
const url = new URL(request.url);
|
|
@@ -21340,21 +21570,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
21340
21570
|
};
|
|
21341
21571
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21342
21572
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
21343
|
-
<h1>${
|
|
21573
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21344
21574
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21345
21575
|
<ul>
|
|
21346
|
-
<li><strong>TeXML:</strong> <code>${
|
|
21347
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21348
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21576
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml35(status.urls.texml)}</code></li>
|
|
21577
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml35(status.urls.stream)}</code></li>
|
|
21578
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml35(status.urls.webhook)}</code></li>
|
|
21349
21579
|
</ul>
|
|
21350
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21351
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21580
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml35(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21581
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml35(warning)}</li>`).join("")}</ul>` : ""}
|
|
21352
21582
|
</main>`;
|
|
21353
21583
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21354
21584
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
21355
|
-
<h1>${
|
|
21585
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21356
21586
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21357
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21587
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml35(check.name)}</strong>: ${escapeHtml35(check.status)}${check.message ? ` - ${escapeHtml35(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21358
21588
|
</main>`;
|
|
21359
21589
|
var runTelnyxSmokeTest = async (input) => {
|
|
21360
21590
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -21447,7 +21677,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21447
21677
|
publicKey: options.webhook.publicKey,
|
|
21448
21678
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
21449
21679
|
}) : undefined);
|
|
21450
|
-
const app = new
|
|
21680
|
+
const app = new Elysia36({
|
|
21451
21681
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
21452
21682
|
}).get(texmlPath, async ({ query, request }) => {
|
|
21453
21683
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -21557,8 +21787,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21557
21787
|
};
|
|
21558
21788
|
|
|
21559
21789
|
// src/telephony/matrix.ts
|
|
21560
|
-
import { Elysia as
|
|
21561
|
-
var
|
|
21790
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
21791
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21562
21792
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
21563
21793
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
21564
21794
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -21619,13 +21849,13 @@ var badgeStyles = {
|
|
|
21619
21849
|
};
|
|
21620
21850
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
21621
21851
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
21622
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
21852
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml36(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
21623
21853
|
<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>
|
|
21624
21854
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
21625
21855
|
${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);">
|
|
21626
21856
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
21627
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
21628
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
21857
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml36(entry.name)}</h2>
|
|
21858
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml36(entry.status.toUpperCase())}</span>
|
|
21629
21859
|
</div>
|
|
21630
21860
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
21631
21861
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -21633,15 +21863,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
21633
21863
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
21634
21864
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
21635
21865
|
</dl>
|
|
21636
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
21637
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
21638
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
21866
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml36(entry.setup.urls.stream || "missing")}</code></p>
|
|
21867
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml36(entry.setup.urls.webhook || "missing")}</code></p>
|
|
21868
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml36(issue.severity)}: ${escapeHtml36(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
21639
21869
|
</article>`).join("")}
|
|
21640
21870
|
</section>
|
|
21641
21871
|
</main>`;
|
|
21642
21872
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
21643
21873
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
21644
|
-
return new
|
|
21874
|
+
return new Elysia37({
|
|
21645
21875
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
21646
21876
|
}).get(path, async ({ query, request }) => {
|
|
21647
21877
|
const providers = await options.load({ query, request });
|
|
@@ -21663,7 +21893,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
21663
21893
|
};
|
|
21664
21894
|
|
|
21665
21895
|
// src/phoneAgentProductionSmoke.ts
|
|
21666
|
-
import { Elysia as
|
|
21896
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
21667
21897
|
var defaultRequirements = [
|
|
21668
21898
|
"media-started",
|
|
21669
21899
|
"transcript",
|
|
@@ -21671,7 +21901,7 @@ var defaultRequirements = [
|
|
|
21671
21901
|
"lifecycle-outcome",
|
|
21672
21902
|
"no-session-error"
|
|
21673
21903
|
];
|
|
21674
|
-
var
|
|
21904
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21675
21905
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
21676
21906
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
21677
21907
|
const value = event.payload[key];
|
|
@@ -21780,10 +22010,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
21780
22010
|
});
|
|
21781
22011
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
21782
22012
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
21783
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
21784
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
21785
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
21786
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22013
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml37(issue.requirement)}</strong>: ${escapeHtml37(issue.message)}</li>`).join("");
|
|
22014
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml37(outcome)}</span>`).join("");
|
|
22015
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml37(requirement)}</span>`).join("");
|
|
22016
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(title)}</title><style>body{background:#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>${escapeHtml37(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml37(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml37(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml37(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>`;
|
|
21787
22017
|
};
|
|
21788
22018
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
21789
22019
|
query,
|
|
@@ -21806,7 +22036,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
21806
22036
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
21807
22037
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
21808
22038
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
21809
|
-
const routes = new
|
|
22039
|
+
const routes = new Elysia38({
|
|
21810
22040
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
21811
22041
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
21812
22042
|
if (htmlPath) {
|
|
@@ -21849,7 +22079,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
21849
22079
|
"completed",
|
|
21850
22080
|
"failed"
|
|
21851
22081
|
];
|
|
21852
|
-
var
|
|
22082
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21853
22083
|
var loadRouteJson = async (input) => {
|
|
21854
22084
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
21855
22085
|
headers: {
|
|
@@ -22087,10 +22317,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
22087
22317
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
22088
22318
|
const urls = entry?.setup.urls;
|
|
22089
22319
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
22090
|
-
return `<tr><td>${
|
|
22320
|
+
return `<tr><td>${escapeHtml38(carrier.name ?? carrier.provider)}</td><td>${escapeHtml38(carrier.provider)}</td><td><code>${escapeHtml38(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml38(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml38(entry.status)}">${escapeHtml38(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml38(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml38(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml38(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
22091
22321
|
}).join("");
|
|
22092
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
22093
|
-
const snippet =
|
|
22322
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml38(stage)}</code></li>`).join("");
|
|
22323
|
+
const snippet = escapeHtml38(`const phoneAgent = createVoicePhoneAgent({
|
|
22094
22324
|
carriers: [
|
|
22095
22325
|
{
|
|
22096
22326
|
provider: 'twilio',
|
|
@@ -22124,11 +22354,11 @@ app.use(
|
|
|
22124
22354
|
);`);
|
|
22125
22355
|
const checklist = report.carriers.map((carrier) => {
|
|
22126
22356
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
22127
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
22128
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
22129
|
-
return `<article><h3>${
|
|
22357
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml38(issue)}</li>`).join("") ?? "";
|
|
22358
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml38(step)}</li>`).join("") ?? "";
|
|
22359
|
+
return `<article><h3>${escapeHtml38(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
22130
22360
|
}).join("");
|
|
22131
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22361
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(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="${escapeHtml38(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>`;
|
|
22132
22362
|
};
|
|
22133
22363
|
var createVoicePhoneAgent = (options) => {
|
|
22134
22364
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -22137,7 +22367,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
22137
22367
|
setupPath: resolveSetupPath(carrier),
|
|
22138
22368
|
smokePath: resolveSmokePath(carrier)
|
|
22139
22369
|
}));
|
|
22140
|
-
const app = new
|
|
22370
|
+
const app = new Elysia39({
|
|
22141
22371
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
22142
22372
|
});
|
|
22143
22373
|
for (const carrier of options.carriers) {
|
|
@@ -24271,8 +24501,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24271
24501
|
};
|
|
24272
24502
|
};
|
|
24273
24503
|
// src/providerCapabilities.ts
|
|
24274
|
-
import { Elysia as
|
|
24275
|
-
var
|
|
24504
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
24505
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24276
24506
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
24277
24507
|
configured: true,
|
|
24278
24508
|
features: options.features?.[provider],
|
|
@@ -24335,27 +24565,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
24335
24565
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
24336
24566
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
24337
24567
|
const cards = report.capabilities.map((capability) => {
|
|
24338
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
24339
|
-
return `<article class="card ${
|
|
24568
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml39(feature)}</span>`).join("");
|
|
24569
|
+
return `<article class="card ${escapeHtml39(capability.status)}">
|
|
24340
24570
|
<div class="card-header">
|
|
24341
24571
|
<div>
|
|
24342
|
-
<p class="eyebrow">${
|
|
24343
|
-
<h2>${
|
|
24572
|
+
<p class="eyebrow">${escapeHtml39(capability.kind)}</p>
|
|
24573
|
+
<h2>${escapeHtml39(capability.label ?? capability.provider)}</h2>
|
|
24344
24574
|
</div>
|
|
24345
|
-
<strong>${
|
|
24575
|
+
<strong>${escapeHtml39(capability.status)}</strong>
|
|
24346
24576
|
</div>
|
|
24347
|
-
${capability.description ? `<p>${
|
|
24577
|
+
${capability.description ? `<p>${escapeHtml39(capability.description)}</p>` : ""}
|
|
24348
24578
|
<dl>
|
|
24349
24579
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
24350
24580
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
24351
|
-
<div><dt>Model</dt><dd>${
|
|
24581
|
+
<div><dt>Model</dt><dd>${escapeHtml39(capability.model ?? "default")}</dd></div>
|
|
24352
24582
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
24353
24583
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
24354
24584
|
</dl>
|
|
24355
24585
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
24356
24586
|
</article>`;
|
|
24357
24587
|
}).join("");
|
|
24358
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24588
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(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>${escapeHtml39(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>`;
|
|
24359
24589
|
};
|
|
24360
24590
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
24361
24591
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -24372,7 +24602,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
24372
24602
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
24373
24603
|
const path = options.path ?? "/api/provider-capabilities";
|
|
24374
24604
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
24375
|
-
const routes = new
|
|
24605
|
+
const routes = new Elysia40({
|
|
24376
24606
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
24377
24607
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
24378
24608
|
if (htmlPath) {
|
|
@@ -24381,7 +24611,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
24381
24611
|
return routes;
|
|
24382
24612
|
};
|
|
24383
24613
|
// src/providerOrchestration.ts
|
|
24384
|
-
import { Elysia as
|
|
24614
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
24385
24615
|
var defaultRequirement = {
|
|
24386
24616
|
minProviders: 1,
|
|
24387
24617
|
requireBudgetPolicy: false,
|
|
@@ -24394,7 +24624,7 @@ var statusRank2 = {
|
|
|
24394
24624
|
warn: 1,
|
|
24395
24625
|
fail: 2
|
|
24396
24626
|
};
|
|
24397
|
-
var
|
|
24627
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24398
24628
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24399
24629
|
var uniqueSorted6 = (values) => [
|
|
24400
24630
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -24537,27 +24767,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
24537
24767
|
};
|
|
24538
24768
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
24539
24769
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
24540
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
24541
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
24770
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml40(surface.status)}">
|
|
24771
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml40(surface.surface)}</p><h2>${escapeHtml40(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml40(surface.status)}</strong></div>
|
|
24542
24772
|
<dl>
|
|
24543
|
-
<div><dt>Providers</dt><dd>${
|
|
24544
|
-
<div><dt>Fallback</dt><dd>${
|
|
24773
|
+
<div><dt>Providers</dt><dd>${escapeHtml40(surface.providers.join(", ") || "none")}</dd></div>
|
|
24774
|
+
<div><dt>Fallback</dt><dd>${escapeHtml40(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
24545
24775
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
24546
24776
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
24547
24777
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
24548
24778
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
24549
24779
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
24550
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
24780
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml40(surface.fallbackMode || "default")}</dd></div>
|
|
24551
24781
|
</dl>
|
|
24552
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
24782
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml40(issue.status)}</strong> ${escapeHtml40(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
24553
24783
|
</article>`).join("");
|
|
24554
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24784
|
+
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:#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>${escapeHtml40(title)}</h1><div class="summary"><span class="pill">${escapeHtml40(report.profileId)}</span><span class="pill">${escapeHtml40(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>`;
|
|
24555
24785
|
};
|
|
24556
24786
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
24557
24787
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
24558
24788
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
24559
24789
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
24560
|
-
const routes = new
|
|
24790
|
+
const routes = new Elysia41({
|
|
24561
24791
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
24562
24792
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
24563
24793
|
if (htmlPath) {
|
|
@@ -24728,7 +24958,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
24728
24958
|
return report;
|
|
24729
24959
|
};
|
|
24730
24960
|
// src/providerSlo.ts
|
|
24731
|
-
import { Elysia as
|
|
24961
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
24732
24962
|
var defaultThresholds = {
|
|
24733
24963
|
llm: {
|
|
24734
24964
|
maxAverageElapsedMs: 2500,
|
|
@@ -24761,7 +24991,7 @@ var statusRank3 = {
|
|
|
24761
24991
|
warn: 1,
|
|
24762
24992
|
fail: 2
|
|
24763
24993
|
};
|
|
24764
|
-
var
|
|
24994
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24765
24995
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
24766
24996
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
24767
24997
|
var uniqueSorted7 = (values) => [
|
|
@@ -25057,11 +25287,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25057
25287
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25058
25288
|
const kindCards = providerKinds.map((kind) => {
|
|
25059
25289
|
const kindReport = report.kinds[kind];
|
|
25060
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
25290
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml41(metric.label)}</dt><dd>${escapeHtml41(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml41(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
25061
25291
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25062
|
-
return `<article class="${
|
|
25292
|
+
return `<article class="${escapeHtml41(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml41(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml41(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
25063
25293
|
}).join("");
|
|
25064
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
25294
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml41(issue.status)}"><strong>${escapeHtml41(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml41(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
25065
25295
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25066
25296
|
store: runtimeStorage.traces,
|
|
25067
25297
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25071,7 +25301,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25071
25301
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25072
25302
|
}
|
|
25073
25303
|
})`;
|
|
25074
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25304
|
+
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:#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>${escapeHtml41(title)}</h1><p class="status ${escapeHtml41(report.status)}">${escapeHtml41(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>${escapeHtml41(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
25075
25305
|
};
|
|
25076
25306
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25077
25307
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25082,7 +25312,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25082
25312
|
...options.headers ?? {}
|
|
25083
25313
|
};
|
|
25084
25314
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25085
|
-
const app = new
|
|
25315
|
+
const app = new Elysia42({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25086
25316
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25087
25317
|
if (markdownPath !== false) {
|
|
25088
25318
|
app.get(markdownPath, async () => {
|
|
@@ -25112,10 +25342,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25112
25342
|
return app;
|
|
25113
25343
|
};
|
|
25114
25344
|
// src/productionReadiness.ts
|
|
25115
|
-
import { Elysia as
|
|
25345
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
25116
25346
|
|
|
25117
25347
|
// src/telephony/security.ts
|
|
25118
|
-
import { Elysia as
|
|
25348
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
25119
25349
|
|
|
25120
25350
|
// src/postgresStore.ts
|
|
25121
25351
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -25853,7 +26083,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
25853
26083
|
};
|
|
25854
26084
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
25855
26085
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
25856
|
-
return new
|
|
26086
|
+
return new Elysia43({
|
|
25857
26087
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
25858
26088
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
25859
26089
|
};
|
|
@@ -25910,8 +26140,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
25910
26140
|
};
|
|
25911
26141
|
|
|
25912
26142
|
// src/opsRecovery.ts
|
|
25913
|
-
import { Elysia as
|
|
25914
|
-
var
|
|
26143
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
26144
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25915
26145
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
25916
26146
|
var hrefForSession = (value, sessionId) => {
|
|
25917
26147
|
if (typeof value === "function") {
|
|
@@ -26125,19 +26355,19 @@ ${failedSessions || "None."}
|
|
|
26125
26355
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26126
26356
|
`;
|
|
26127
26357
|
};
|
|
26128
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
26358
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml42(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>${escapeHtml42(label)}</span><strong>not configured</strong></article>`;
|
|
26129
26359
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26130
26360
|
const title = options.title ?? "Voice Ops Recovery";
|
|
26131
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
26132
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
26133
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
26134
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26361
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml42(issue.severity)}</td><td><code>${escapeHtml42(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml42(issue.href)}">${escapeHtml42(issue.label)}</a>` : escapeHtml42(issue.label)}</td><td>${escapeHtml42(String(issue.value ?? ""))}</td><td>${escapeHtml42(issue.detail ?? "")}</td></tr>`).join("");
|
|
26362
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml42(provider.provider)}</td><td>${escapeHtml42(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml42(provider.lastError ?? "")}</td></tr>`).join("");
|
|
26363
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml42(session.operationsRecordHref)}">${escapeHtml42(session.sessionId)}</a>` : escapeHtml42(session.sessionId)}${session.provider ? ` via ${escapeHtml42(session.provider)}` : ""}${session.error ? `: ${escapeHtml42(session.error)}` : ""}</li>`).join("");
|
|
26364
|
+
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{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>${escapeHtml42(title)}</h1><p><span class="status">${escapeHtml42(report.status)}</span> Checked ${escapeHtml42(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>${escapeHtml42(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>`;
|
|
26135
26365
|
};
|
|
26136
26366
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26137
26367
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26138
26368
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26139
26369
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26140
|
-
const routes = new
|
|
26370
|
+
const routes = new Elysia44({
|
|
26141
26371
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26142
26372
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26143
26373
|
if (htmlPath) {
|
|
@@ -26167,18 +26397,18 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26167
26397
|
};
|
|
26168
26398
|
|
|
26169
26399
|
// src/observabilityExport.ts
|
|
26170
|
-
import { Elysia as
|
|
26400
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
26171
26401
|
import { Database as Database4 } from "bun:sqlite";
|
|
26172
26402
|
import { createHash } from "crypto";
|
|
26173
26403
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26174
26404
|
import { join as join3 } from "path";
|
|
26175
26405
|
|
|
26176
26406
|
// src/operationsRecord.ts
|
|
26177
|
-
import { Elysia as
|
|
26407
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26178
26408
|
|
|
26179
26409
|
// src/traceTimeline.ts
|
|
26180
|
-
import { Elysia as
|
|
26181
|
-
var
|
|
26410
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
26411
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26182
26412
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26183
26413
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26184
26414
|
var firstString3 = (payload, keys) => {
|
|
@@ -26361,17 +26591,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
26361
26591
|
};
|
|
26362
26592
|
};
|
|
26363
26593
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26364
|
-
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>${
|
|
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>${escapeHtml43(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>`;
|
|
26365
26595
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
26366
|
-
const events = session.events.map((event) => `<tr class="${
|
|
26367
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
26368
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
26369
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26596
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml43(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml43(event.type)}</td><td>${escapeHtml43(event.label)}</td><td>${escapeHtml43(event.provider ?? "")}</td><td>${escapeHtml43(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
26597
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml43(issue.severity)}">${escapeHtml43(issue.code)}: ${escapeHtml43(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
26598
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml43(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
26599
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(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>${escapeHtml43(session.sessionId)}</h1><p class="status ${escapeHtml43(session.status)}">${escapeHtml43(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>`;
|
|
26370
26600
|
};
|
|
26371
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
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="${escapeHtml43(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml43(session.operationsRecordHref)}">${escapeHtml43(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml43(session.sessionId)}</a>`}</td><td>${escapeHtml43(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) => escapeHtml43(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
26372
26602
|
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}}";
|
|
26373
26603
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
26374
|
-
const snippet =
|
|
26604
|
+
const snippet = escapeHtml43(`const traceStore = createVoiceTraceSinkStore({
|
|
26375
26605
|
store: runtimeStorage.traces,
|
|
26376
26606
|
sinks: [
|
|
26377
26607
|
createVoiceTraceHTTPSink({
|
|
@@ -26397,13 +26627,13 @@ app.use(
|
|
|
26397
26627
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
26398
26628
|
})
|
|
26399
26629
|
);`);
|
|
26400
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26630
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(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>${escapeHtml43(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>`;
|
|
26401
26631
|
};
|
|
26402
26632
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
26403
26633
|
const path = options.path ?? "/api/voice-traces";
|
|
26404
26634
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
26405
26635
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
26406
|
-
const routes = new
|
|
26636
|
+
const routes = new Elysia45({
|
|
26407
26637
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
26408
26638
|
});
|
|
26409
26639
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -26832,7 +27062,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
26832
27062
|
}
|
|
26833
27063
|
return report;
|
|
26834
27064
|
};
|
|
26835
|
-
var
|
|
27065
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26836
27066
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26837
27067
|
var outcomeLabels = (outcome) => [
|
|
26838
27068
|
outcome.complete ? "complete" : undefined,
|
|
@@ -26912,20 +27142,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
26912
27142
|
`);
|
|
26913
27143
|
};
|
|
26914
27144
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
26915
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
26916
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
26917
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
27145
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml44(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>';
|
|
27146
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml44(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml44(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml44(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml44(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
27147
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml44(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml44(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml44(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml44(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml44(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml44(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml44(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml44(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
26918
27148
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
26919
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
26920
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
26921
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
26922
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
26923
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
27149
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml44(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml44(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml44(handoff.status ?? "")}</span><p>${escapeHtml44(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
27150
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml44(tool.toolName ?? "tool")}</strong> <span>${escapeHtml44(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml44(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
27151
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml44(review.title)}</strong> <span>${escapeHtml44(review.summary.outcome ?? "")}</span><p>${escapeHtml44(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
27152
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml44(task.title)}</strong> <span>${escapeHtml44(task.status)}</span><p>${escapeHtml44(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
27153
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml44(event.type)}</strong> <span>${escapeHtml44(event.deliveryStatus ?? "local")}</span><p>${escapeHtml44(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
26924
27154
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
26925
27155
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
26926
|
-
return `<li><strong>assistant.guardrail ${
|
|
27156
|
+
return `<li><strong>assistant.guardrail ${escapeHtml44(decision.stage ?? "unknown")}</strong> <span>${escapeHtml44(decision.status ?? "")}</span><p>Allowed: ${escapeHtml44(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml44(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml44(decision.turnId)}` : ""}</p><p>${escapeHtml44(findings)}</p></li>`;
|
|
26927
27157
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
26928
|
-
const snippet =
|
|
27158
|
+
const snippet = escapeHtml44(`app.use(
|
|
26929
27159
|
createVoiceOperationsRecordRoutes({
|
|
26930
27160
|
audit: auditStore,
|
|
26931
27161
|
integrationEvents: opsEvents,
|
|
@@ -26939,16 +27169,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
26939
27169
|
tasks: opsTasks
|
|
26940
27170
|
})
|
|
26941
27171
|
);`);
|
|
26942
|
-
const incidentMarkdown =
|
|
26943
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
26944
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27172
|
+
const incidentMarkdown = escapeHtml44(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
27173
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml44(options.incidentHref)}">Download incident.md</a>` : "";
|
|
27174
|
+
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 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>${escapeHtml44(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml44(record.status)}">${escapeHtml44(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>${escapeHtml44(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>`;
|
|
26945
27175
|
};
|
|
26946
27176
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
26947
27177
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
26948
27178
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
26949
27179
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
26950
27180
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
26951
|
-
const routes = new
|
|
27181
|
+
const routes = new Elysia46({
|
|
26952
27182
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
26953
27183
|
});
|
|
26954
27184
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -27599,7 +27829,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
27599
27829
|
...options.headers ?? {}
|
|
27600
27830
|
};
|
|
27601
27831
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
27602
|
-
const app = new
|
|
27832
|
+
const app = new Elysia47({
|
|
27603
27833
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
27604
27834
|
});
|
|
27605
27835
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28408,7 +28638,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28408
28638
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
28409
28639
|
}
|
|
28410
28640
|
});
|
|
28411
|
-
const app = new
|
|
28641
|
+
const app = new Elysia47({
|
|
28412
28642
|
name: options.name ?? "absolute-voice-observability-export"
|
|
28413
28643
|
});
|
|
28414
28644
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28485,7 +28715,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28485
28715
|
};
|
|
28486
28716
|
|
|
28487
28717
|
// src/productionReadiness.ts
|
|
28488
|
-
var
|
|
28718
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28489
28719
|
var rollupStatus3 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
28490
28720
|
var readinessGateCodes = {
|
|
28491
28721
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -29940,25 +30170,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
29940
30170
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
29941
30171
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
29942
30172
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
29943
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
29944
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
30173
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml45(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
30174
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml45(report.profile.name)}</h2><p>${escapeHtml45(report.profile.description)}</p><p>${escapeHtml45(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="${escapeHtml45(surface.href)}">${escapeHtml45(surface.label)}</a>` : escapeHtml45(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
29945
30175
|
const checks = report.checks.map((check, index) => {
|
|
29946
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
29947
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
29948
|
-
return `<article class="check ${
|
|
30176
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml45(action.href)}">${escapeHtml45(action.label)}</button>` : `<a href="${escapeHtml45(action.href)}">${escapeHtml45(action.label)}</a>`).join("");
|
|
30177
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml45(check.status)}: observed ${escapeHtml45(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml45(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml45(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml45(check.gateExplanation.unit)}` : ""}. ${escapeHtml45(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml45(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
30178
|
+
return `<article class="check ${escapeHtml45(check.status)}">
|
|
29949
30179
|
<div>
|
|
29950
|
-
<span>${
|
|
29951
|
-
<h2>${
|
|
29952
|
-
${check.detail ? `<p>${
|
|
30180
|
+
<span>${escapeHtml45(check.status.toUpperCase())}</span>
|
|
30181
|
+
<h2>${escapeHtml45(check.label)}</h2>
|
|
30182
|
+
${check.detail ? `<p>${escapeHtml45(check.detail)}</p>` : ""}
|
|
29953
30183
|
${explanation}
|
|
29954
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
30184
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml45(check.proofSource.href)}">${escapeHtml45(check.proofSource.sourceLabel)}</a>` : escapeHtml45(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml45(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
29955
30185
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
29956
30186
|
</div>
|
|
29957
|
-
<strong>${
|
|
29958
|
-
${check.href ? `<a href="${
|
|
30187
|
+
<strong>${escapeHtml45(String(check.value ?? check.status))}</strong>
|
|
30188
|
+
${check.href ? `<a href="${escapeHtml45(check.href)}">Open surface</a>` : ""}
|
|
29959
30189
|
</article>`;
|
|
29960
30190
|
}).join("");
|
|
29961
|
-
const snippet =
|
|
30191
|
+
const snippet = escapeHtml45(`createVoiceProductionReadinessRoutes({
|
|
29962
30192
|
htmlPath: '/production-readiness',
|
|
29963
30193
|
path: '/api/production-readiness',
|
|
29964
30194
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -29974,13 +30204,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
29974
30204
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
29975
30205
|
store: traceStore
|
|
29976
30206
|
});`);
|
|
29977
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30207
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml45(title)}</title><style>body{background:#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>${escapeHtml45(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 ${escapeHtml45(report.status)}">Overall: ${escapeHtml45(report.status.toUpperCase())}</p><p>Checked ${escapeHtml45(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>`;
|
|
29978
30208
|
};
|
|
29979
30209
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
29980
30210
|
const path = options.path ?? "/api/production-readiness";
|
|
29981
30211
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
29982
30212
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
29983
|
-
const routes = new
|
|
30213
|
+
const routes = new Elysia48({
|
|
29984
30214
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
29985
30215
|
});
|
|
29986
30216
|
const resolveOptions = async (input) => {
|
|
@@ -30028,8 +30258,8 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30028
30258
|
return routes;
|
|
30029
30259
|
};
|
|
30030
30260
|
// src/voiceMonitoring.ts
|
|
30031
|
-
import { Elysia as
|
|
30032
|
-
var
|
|
30261
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
30262
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30033
30263
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30034
30264
|
var rollupStatus4 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30035
30265
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -30282,14 +30512,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
30282
30512
|
};
|
|
30283
30513
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
30284
30514
|
const title = options.title ?? "Voice Monitors";
|
|
30285
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
30286
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
30287
|
-
const snippet =
|
|
30515
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml46(run.label)}</td><td class="${escapeHtml46(run.status)}">${escapeHtml46(run.status)}</td><td>${escapeHtml46(run.severity)}</td><td>${escapeHtml46(String(run.value ?? ""))}</td><td>${escapeHtml46(String(run.threshold ?? ""))}</td><td>${escapeHtml46(run.detail ?? "")}</td></tr>`).join("");
|
|
30516
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml46(issue.label)}</strong> <span class="${escapeHtml46(issue.status)}">${escapeHtml46(issue.status)}</span> ${escapeHtml46(issue.detail ?? "")}</li>`).join("");
|
|
30517
|
+
const snippet = escapeHtml46(`app.use(createVoiceMonitorRoutes({
|
|
30288
30518
|
evidence,
|
|
30289
30519
|
issueStore,
|
|
30290
30520
|
monitors: [defineVoiceMonitor(...)]
|
|
30291
30521
|
}));`);
|
|
30292
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30522
|
+
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:#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>${escapeHtml46(title)}</h1><p class="pill ${escapeHtml46(report.status)}">Status: ${escapeHtml46(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>`;
|
|
30293
30523
|
};
|
|
30294
30524
|
var actorFromRequest = async (request) => {
|
|
30295
30525
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -30313,7 +30543,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30313
30543
|
monitors: options.monitors,
|
|
30314
30544
|
now: options.now
|
|
30315
30545
|
});
|
|
30316
|
-
const routes = new
|
|
30546
|
+
const routes = new Elysia49({
|
|
30317
30547
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
30318
30548
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
30319
30549
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -30360,7 +30590,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30360
30590
|
};
|
|
30361
30591
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
30362
30592
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
30363
|
-
return new
|
|
30593
|
+
return new Elysia49({
|
|
30364
30594
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
30365
30595
|
}).get(path, () => ({
|
|
30366
30596
|
isRunning: options.runner.isRunning()
|
|
@@ -30736,8 +30966,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
30736
30966
|
};
|
|
30737
30967
|
};
|
|
30738
30968
|
// src/providerStackRecommendations.ts
|
|
30739
|
-
import { Elysia as
|
|
30740
|
-
var
|
|
30969
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
30970
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30741
30971
|
var profileProviderPriorities = {
|
|
30742
30972
|
"meeting-recorder": {
|
|
30743
30973
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31056,17 +31286,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31056
31286
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31057
31287
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31058
31288
|
const rows = report.rows.map((row) => {
|
|
31059
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31060
|
-
return `<article class="row ${
|
|
31289
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml47(check.status)}"><strong>${escapeHtml47(check.label)}</strong><span>${escapeHtml47(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml47(check.remediation.href)}">${escapeHtml47(check.remediation.label)}</a>` : escapeHtml47(check.remediation.label)}: ${escapeHtml47(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
31290
|
+
return `<article class="row ${escapeHtml47(row.status)}">
|
|
31061
31291
|
<div>
|
|
31062
|
-
<p class="eyebrow">${
|
|
31063
|
-
<h2>${
|
|
31064
|
-
<p class="status ${
|
|
31292
|
+
<p class="eyebrow">${escapeHtml47(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
31293
|
+
<h2>${escapeHtml47(row.provider)}</h2>
|
|
31294
|
+
<p class="status ${escapeHtml47(row.status)}">${escapeHtml47(row.status.toUpperCase())}</p>
|
|
31065
31295
|
</div>
|
|
31066
31296
|
<ul>${checks}</ul>
|
|
31067
31297
|
</article>`;
|
|
31068
31298
|
}).join("");
|
|
31069
|
-
const snippet =
|
|
31299
|
+
const snippet = escapeHtml47(`const providerContracts = () =>
|
|
31070
31300
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31071
31301
|
env: process.env,
|
|
31072
31302
|
providers: {
|
|
@@ -31087,7 +31317,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31087
31317
|
providerContractMatrix: () =>
|
|
31088
31318
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31089
31319
|
});`);
|
|
31090
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31320
|
+
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:#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>${escapeHtml47(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>`;
|
|
31091
31321
|
};
|
|
31092
31322
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31093
31323
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31102,7 +31332,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31102
31332
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31103
31333
|
const path = options.path ?? "/api/provider-contracts";
|
|
31104
31334
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31105
|
-
const routes = new
|
|
31335
|
+
const routes = new Elysia50({
|
|
31106
31336
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31107
31337
|
});
|
|
31108
31338
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -31220,7 +31450,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31220
31450
|
return assertion;
|
|
31221
31451
|
};
|
|
31222
31452
|
// src/opsConsoleRoutes.ts
|
|
31223
|
-
import { Elysia as
|
|
31453
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
31224
31454
|
var DEFAULT_LINKS = [
|
|
31225
31455
|
{
|
|
31226
31456
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -31255,7 +31485,7 @@ var DEFAULT_LINKS = [
|
|
|
31255
31485
|
label: "Handoffs"
|
|
31256
31486
|
}
|
|
31257
31487
|
];
|
|
31258
|
-
var
|
|
31488
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31259
31489
|
var countProviderStatuses = (providers) => {
|
|
31260
31490
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
31261
31491
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -31324,20 +31554,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
31324
31554
|
trace
|
|
31325
31555
|
};
|
|
31326
31556
|
};
|
|
31327
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
31557
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml48(input.label)}</span><strong>${escapeHtml48(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml48(input.status)}">${escapeHtml48(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml48(input.href)}">Open</a>` : ""}</article>`;
|
|
31328
31558
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
31329
31559
|
const links = report.links.map((link) => `<article class="surface">
|
|
31330
|
-
<div><h2>${
|
|
31331
|
-
<p><a href="${
|
|
31560
|
+
<div><h2>${escapeHtml48(link.label)}</h2>${link.description ? `<p>${escapeHtml48(link.description)}</p>` : ""}</div>
|
|
31561
|
+
<p><a href="${escapeHtml48(link.href)}">Open ${escapeHtml48(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml48(link.statusHref)}">Status</a>` : ""}</p>
|
|
31332
31562
|
</article>`).join("");
|
|
31333
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
31334
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
31563
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml48(session.sessionId)}</td><td>${escapeHtml48(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml48(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
31564
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml48(event.kind)}</td><td>${escapeHtml48(event.provider ?? "unknown")}</td><td>${escapeHtml48(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml48(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
31335
31565
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
31336
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31566
|
+
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{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>${escapeHtml48(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 ${escapeHtml48(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>`;
|
|
31337
31567
|
};
|
|
31338
31568
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
31339
31569
|
const path = options.path ?? "/ops-console";
|
|
31340
|
-
const routes = new
|
|
31570
|
+
const routes = new Elysia51({
|
|
31341
31571
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
31342
31572
|
});
|
|
31343
31573
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -31354,7 +31584,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
31354
31584
|
return routes;
|
|
31355
31585
|
};
|
|
31356
31586
|
// src/incidentBundle.ts
|
|
31357
|
-
import { Elysia as
|
|
31587
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
31358
31588
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
31359
31589
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
31360
31590
|
return false;
|
|
@@ -31555,7 +31785,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
31555
31785
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
31556
31786
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
31557
31787
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
31558
|
-
const routes = new
|
|
31788
|
+
const routes = new Elysia52({
|
|
31559
31789
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
31560
31790
|
});
|
|
31561
31791
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -31756,19 +31986,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
31756
31986
|
};
|
|
31757
31987
|
};
|
|
31758
31988
|
// src/opsStatusRoutes.ts
|
|
31759
|
-
import { Elysia as
|
|
31760
|
-
var
|
|
31989
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31990
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31761
31991
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
31762
31992
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
31763
31993
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
31764
31994
|
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;
|
|
31765
|
-
return `<article class="surface ${
|
|
31995
|
+
return `<article class="surface ${escapeHtml49(surface.status)}"><span>${escapeHtml49(surface.status.toUpperCase())}</span><h2>${escapeHtml49(key)}</h2><strong>${escapeHtml49(value)}</strong></article>`;
|
|
31766
31996
|
}).join("");
|
|
31767
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31997
|
+
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{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>${escapeHtml49(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml49(report.status)}">Overall: ${escapeHtml49(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>`;
|
|
31768
31998
|
};
|
|
31769
31999
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
31770
32000
|
const path = options.path ?? "/api/voice/ops-status";
|
|
31771
|
-
const routes = new
|
|
32001
|
+
const routes = new Elysia53({
|
|
31772
32002
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
31773
32003
|
});
|
|
31774
32004
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -32201,8 +32431,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
32201
32431
|
};
|
|
32202
32432
|
};
|
|
32203
32433
|
// src/traceDeliveryRoutes.ts
|
|
32204
|
-
import { Elysia as
|
|
32205
|
-
var
|
|
32434
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
32435
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32206
32436
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
32207
32437
|
var getNumber12 = (value) => {
|
|
32208
32438
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -32283,14 +32513,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
32283
32513
|
if (entries.length === 0) {
|
|
32284
32514
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
32285
32515
|
}
|
|
32286
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
32516
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml50(sinkId)}</strong>: ${escapeHtml50(result.status)}${result.deliveredTo ? ` to ${escapeHtml50(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml50(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
32287
32517
|
};
|
|
32288
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
32518
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml50(event.type)} <small>${escapeHtml50(event.id)}</small>${event.sessionId ? ` session=${escapeHtml50(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
32289
32519
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
32290
32520
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
32291
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
32292
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
32293
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32521
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml50(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
32522
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml50(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml50(delivery.deliveryStatus)}</span><h2>${escapeHtml50(delivery.id)}</h2><p>${escapeHtml50(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml50(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml50(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
32523
|
+
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:#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>${escapeHtml50(title)}</h1><p>Checked ${escapeHtml50(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>`;
|
|
32294
32524
|
};
|
|
32295
32525
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
32296
32526
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32310,7 +32540,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
32310
32540
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
32311
32541
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
32312
32542
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
32313
|
-
const routes = new
|
|
32543
|
+
const routes = new Elysia54({
|
|
32314
32544
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
32315
32545
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
32316
32546
|
if (htmlPath !== false) {
|
|
@@ -32407,7 +32637,7 @@ var createVoiceMemoryStore = () => {
|
|
|
32407
32637
|
return { get, getOrCreate, list, remove, set };
|
|
32408
32638
|
};
|
|
32409
32639
|
// src/opsWebhook.ts
|
|
32410
|
-
import { Elysia as
|
|
32640
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32411
32641
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
32412
32642
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
32413
32643
|
const encoder = new TextEncoder;
|
|
@@ -32537,7 +32767,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
32537
32767
|
};
|
|
32538
32768
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
32539
32769
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
32540
|
-
return new
|
|
32770
|
+
return new Elysia55().post(path, async ({ body, request, set }) => {
|
|
32541
32771
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
32542
32772
|
if (options.signingSecret) {
|
|
32543
32773
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -32992,7 +33222,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
32992
33222
|
};
|
|
32993
33223
|
};
|
|
32994
33224
|
// src/postCallAnalysis.ts
|
|
32995
|
-
import { Elysia as
|
|
33225
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32996
33226
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
32997
33227
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
32998
33228
|
var getPathValue3 = (source, path) => {
|
|
@@ -33171,7 +33401,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
33171
33401
|
};
|
|
33172
33402
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
33173
33403
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
33174
|
-
const routes = new
|
|
33404
|
+
const routes = new Elysia56({
|
|
33175
33405
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
33176
33406
|
});
|
|
33177
33407
|
routes.get(path, async ({ query }) => {
|
|
@@ -33196,7 +33426,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
33196
33426
|
return routes;
|
|
33197
33427
|
};
|
|
33198
33428
|
// src/guardrails.ts
|
|
33199
|
-
import { Elysia as
|
|
33429
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
33200
33430
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
33201
33431
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
33202
33432
|
var matchesRule = async (rule, input) => {
|
|
@@ -33498,7 +33728,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
33498
33728
|
};
|
|
33499
33729
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
33500
33730
|
const path = options.path ?? "/api/voice/guardrails";
|
|
33501
|
-
const routes = new
|
|
33731
|
+
const routes = new Elysia57({
|
|
33502
33732
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
33503
33733
|
});
|
|
33504
33734
|
routes.all(path, async ({ request }) => {
|
|
@@ -34022,6 +34252,8 @@ export {
|
|
|
34022
34252
|
renderVoiceScenarioEvalHTML,
|
|
34023
34253
|
renderVoiceResilienceHTML,
|
|
34024
34254
|
renderVoiceReconnectContractHTML,
|
|
34255
|
+
renderVoiceRealtimeChannelMarkdown,
|
|
34256
|
+
renderVoiceRealtimeChannelHTML,
|
|
34025
34257
|
renderVoiceQualityHTML,
|
|
34026
34258
|
renderVoiceProviderSloMarkdown,
|
|
34027
34259
|
renderVoiceProviderSloHTML,
|
|
@@ -34117,6 +34349,7 @@ export {
|
|
|
34117
34349
|
evaluateVoiceTelephonyWebhookNormalizationEvidence,
|
|
34118
34350
|
evaluateVoiceTelephonyContract,
|
|
34119
34351
|
evaluateVoiceSimulationSuiteEvidence,
|
|
34352
|
+
evaluateVoiceRealtimeChannelEvidence,
|
|
34120
34353
|
evaluateVoiceQuality,
|
|
34121
34354
|
evaluateVoiceProviderStackGaps,
|
|
34122
34355
|
evaluateVoiceProviderStackEvidence,
|
|
@@ -34246,6 +34479,7 @@ export {
|
|
|
34246
34479
|
createVoiceRedisPlivoWebhookNonceStore,
|
|
34247
34480
|
createVoiceRedisIdempotencyStore,
|
|
34248
34481
|
createVoiceReconnectContractRoutes,
|
|
34482
|
+
createVoiceRealtimeChannelRoutes,
|
|
34249
34483
|
createVoiceReadinessProfile,
|
|
34250
34484
|
createVoiceQualityRoutes,
|
|
34251
34485
|
createVoiceProviderSloRoutes,
|
|
@@ -34449,6 +34683,7 @@ export {
|
|
|
34449
34683
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
34450
34684
|
buildVoiceSloReadinessThresholdReport,
|
|
34451
34685
|
buildVoiceSloCalibrationReport,
|
|
34686
|
+
buildVoiceRealtimeChannelReport,
|
|
34452
34687
|
buildVoiceProviderSloReport,
|
|
34453
34688
|
buildVoiceProviderOrchestrationReport,
|
|
34454
34689
|
buildVoiceProviderDecisionTraceReport,
|
|
@@ -34492,6 +34727,7 @@ export {
|
|
|
34492
34727
|
assertVoiceTelephonyWebhookNormalizationEvidence,
|
|
34493
34728
|
assertVoiceSloCalibration,
|
|
34494
34729
|
assertVoiceSimulationSuiteEvidence,
|
|
34730
|
+
assertVoiceRealtimeChannelEvidence,
|
|
34495
34731
|
assertVoiceProviderStackEvidence,
|
|
34496
34732
|
assertVoiceProviderSloEvidence,
|
|
34497
34733
|
assertVoiceProviderRoutingContractEvidence,
|