@absolutejs/voice 0.0.22-beta.301 → 0.0.22-beta.303
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 +736 -410
- package/dist/realtimeChannel.d.ts +136 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10920,9 +10920,328 @@ 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 readString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
10958
|
+
var readNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
10959
|
+
var eventHasRealtimeAssistantProof = (event) => event.type === "turn.assistant" && (event.payload.realtimeConfigured === true || event.payload.mode === "realtime" || event.metadata?.realtime === true);
|
|
10960
|
+
var buildVoiceRealtimeChannelRuntimeSamplesFromTrace = (events, options = {}) => {
|
|
10961
|
+
const format = options.format ?? DEFAULT_REALTIME_FORMAT2;
|
|
10962
|
+
const source = options.source ?? "trace-store";
|
|
10963
|
+
const samples = [];
|
|
10964
|
+
const stagesByTurn = new Map;
|
|
10965
|
+
for (const event of events) {
|
|
10966
|
+
if (event.type !== "turn_latency.stage" || !event.turnId) {
|
|
10967
|
+
continue;
|
|
10968
|
+
}
|
|
10969
|
+
const stage = readString(event.payload.stage);
|
|
10970
|
+
if (!stage) {
|
|
10971
|
+
continue;
|
|
10972
|
+
}
|
|
10973
|
+
const stages = stagesByTurn.get(event.turnId) ?? new Map;
|
|
10974
|
+
stages.set(stage, event.at);
|
|
10975
|
+
stagesByTurn.set(event.turnId, stages);
|
|
10976
|
+
}
|
|
10977
|
+
for (const event of [...events].sort((left, right) => left.at - right.at)) {
|
|
10978
|
+
if (event.type === "turn.committed") {
|
|
10979
|
+
samples.push({
|
|
10980
|
+
format,
|
|
10981
|
+
kind: "input-audio",
|
|
10982
|
+
observedAt: event.at,
|
|
10983
|
+
ok: true,
|
|
10984
|
+
sessionId: event.sessionId,
|
|
10985
|
+
source,
|
|
10986
|
+
turnId: event.turnId
|
|
10987
|
+
});
|
|
10988
|
+
samples.push({
|
|
10989
|
+
kind: "turn-commit",
|
|
10990
|
+
observedAt: event.at,
|
|
10991
|
+
ok: true,
|
|
10992
|
+
sessionId: event.sessionId,
|
|
10993
|
+
source,
|
|
10994
|
+
turnId: event.turnId
|
|
10995
|
+
});
|
|
10996
|
+
continue;
|
|
10997
|
+
}
|
|
10998
|
+
if (eventHasRealtimeAssistantProof(event)) {
|
|
10999
|
+
const stages = event.turnId ? stagesByTurn.get(event.turnId) : undefined;
|
|
11000
|
+
const committedAt = stages?.get("turn_committed");
|
|
11001
|
+
const audioAt = stages?.get("assistant_audio_received") ?? stages?.get("tts_send_completed") ?? stages?.get("assistant_text_started") ?? event.at;
|
|
11002
|
+
const latencyMs = committedAt !== undefined ? Math.max(0, audioAt - committedAt) : readNumber(event.payload.elapsedMs);
|
|
11003
|
+
samples.push({
|
|
11004
|
+
format,
|
|
11005
|
+
kind: "assistant-audio",
|
|
11006
|
+
latencyMs,
|
|
11007
|
+
observedAt: event.at,
|
|
11008
|
+
ok: event.payload.status !== "realtime-send-failed",
|
|
11009
|
+
sessionId: event.sessionId,
|
|
11010
|
+
source,
|
|
11011
|
+
turnId: event.turnId
|
|
11012
|
+
});
|
|
11013
|
+
continue;
|
|
11014
|
+
}
|
|
11015
|
+
if (event.type === "client.reconnect") {
|
|
11016
|
+
samples.push({
|
|
11017
|
+
kind: "reconnect",
|
|
11018
|
+
observedAt: event.at,
|
|
11019
|
+
ok: event.payload.status !== "failed",
|
|
11020
|
+
sessionId: event.sessionId,
|
|
11021
|
+
source,
|
|
11022
|
+
turnId: event.turnId
|
|
11023
|
+
});
|
|
11024
|
+
}
|
|
11025
|
+
}
|
|
11026
|
+
return samples;
|
|
11027
|
+
};
|
|
11028
|
+
var buildVoiceRealtimeChannelReport = (options) => {
|
|
11029
|
+
const expectedInputFormat = options.expectedInputFormat ?? DEFAULT_REALTIME_FORMAT2;
|
|
11030
|
+
const expectedOutputFormat = options.expectedOutputFormat ?? expectedInputFormat;
|
|
11031
|
+
const inputFormat = options.inputFormat ?? expectedInputFormat;
|
|
11032
|
+
const outputFormat = options.outputFormat ?? expectedOutputFormat;
|
|
11033
|
+
const runtimeSamples = options.runtimeSamples ?? [];
|
|
11034
|
+
const issues = [];
|
|
11035
|
+
validateFormat("input", inputFormat, expectedInputFormat, issues);
|
|
11036
|
+
validateFormat("output", outputFormat, expectedOutputFormat, issues);
|
|
11037
|
+
const browserCapture = options.browserCapture ? {
|
|
11038
|
+
...options.browserCapture,
|
|
11039
|
+
resamplingRequired: options.browserCapture.audioContextSampleRateHz !== undefined && options.browserCapture.audioContextSampleRateHz !== inputFormat.sampleRateHz,
|
|
11040
|
+
resamplingTargetHz: inputFormat.sampleRateHz
|
|
11041
|
+
} : undefined;
|
|
11042
|
+
if (!browserCapture) {
|
|
11043
|
+
issues.push({
|
|
11044
|
+
code: "browser-capture-missing",
|
|
11045
|
+
message: "Browser capture settings are missing; realtime proof cannot show capture-to-provider format negotiation.",
|
|
11046
|
+
severity: "warning"
|
|
11047
|
+
});
|
|
11048
|
+
} else {
|
|
11049
|
+
if (browserCapture.sampleRateHz !== inputFormat.sampleRateHz) {
|
|
11050
|
+
issues.push({
|
|
11051
|
+
code: "browser-capture-target-mismatch",
|
|
11052
|
+
message: `Browser capture target ${String(browserCapture.sampleRateHz ?? "unknown")}hz does not match realtime input ${String(inputFormat.sampleRateHz)}hz.`,
|
|
11053
|
+
severity: "error"
|
|
11054
|
+
});
|
|
11055
|
+
}
|
|
11056
|
+
if ((browserCapture.channelCount ?? 1) !== inputFormat.channels) {
|
|
11057
|
+
issues.push({
|
|
11058
|
+
code: "browser-capture-channel-mismatch",
|
|
11059
|
+
message: `Browser capture channel count ${String(browserCapture.channelCount ?? "unknown")} does not match realtime input ${String(inputFormat.channels)}.`,
|
|
11060
|
+
severity: "error"
|
|
11061
|
+
});
|
|
11062
|
+
}
|
|
11063
|
+
}
|
|
11064
|
+
for (const sample of runtimeSamples) {
|
|
11065
|
+
if (sample.ok === false) {
|
|
11066
|
+
issues.push({
|
|
11067
|
+
code: "runtime-sample-failed",
|
|
11068
|
+
message: `Realtime runtime sample failed: ${sample.kind}.`,
|
|
11069
|
+
severity: "error"
|
|
11070
|
+
});
|
|
11071
|
+
}
|
|
11072
|
+
if (sample.format && !formatMatches(sample.format, inputFormat)) {
|
|
11073
|
+
issues.push({
|
|
11074
|
+
code: "runtime-format-mismatch",
|
|
11075
|
+
message: `Runtime sample ${sample.kind} used ${formatLabel(sample.format)} instead of ${formatLabel(inputFormat)}.`,
|
|
11076
|
+
severity: "error"
|
|
11077
|
+
});
|
|
11078
|
+
}
|
|
11079
|
+
}
|
|
11080
|
+
const inputAudioSamples = runtimeSamples.filter((sample) => sample.kind === "input-audio").length;
|
|
11081
|
+
const assistantAudioSamples = runtimeSamples.filter((sample) => sample.kind === "assistant-audio").length;
|
|
11082
|
+
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];
|
|
11083
|
+
const minInputAudioSamples = options.minInputAudioSamples ?? 1;
|
|
11084
|
+
const minAssistantAudioSamples = options.minAssistantAudioSamples ?? 1;
|
|
11085
|
+
const maxFirstAudioLatencyMs = options.maxFirstAudioLatencyMs;
|
|
11086
|
+
if (inputAudioSamples < minInputAudioSamples) {
|
|
11087
|
+
issues.push({
|
|
11088
|
+
code: "runtime-input-audio-missing",
|
|
11089
|
+
message: `Expected at least ${String(minInputAudioSamples)} realtime input audio sample(s), found ${String(inputAudioSamples)}.`,
|
|
11090
|
+
severity: "warning"
|
|
11091
|
+
});
|
|
11092
|
+
}
|
|
11093
|
+
if (assistantAudioSamples < minAssistantAudioSamples) {
|
|
11094
|
+
issues.push({
|
|
11095
|
+
code: "runtime-assistant-audio-missing",
|
|
11096
|
+
message: `Expected at least ${String(minAssistantAudioSamples)} realtime assistant audio sample(s), found ${String(assistantAudioSamples)}.`,
|
|
11097
|
+
severity: "warning"
|
|
11098
|
+
});
|
|
11099
|
+
}
|
|
11100
|
+
if (maxFirstAudioLatencyMs !== undefined && (firstAudioLatencyMs === undefined || firstAudioLatencyMs > maxFirstAudioLatencyMs)) {
|
|
11101
|
+
issues.push({
|
|
11102
|
+
code: "first-audio-latency-over-budget",
|
|
11103
|
+
message: `Expected first realtime assistant audio at or below ${String(maxFirstAudioLatencyMs)}ms, found ${String(firstAudioLatencyMs ?? "missing")}ms.`,
|
|
11104
|
+
severity: "warning"
|
|
11105
|
+
});
|
|
11106
|
+
}
|
|
11107
|
+
const status = issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass";
|
|
11108
|
+
return {
|
|
11109
|
+
browserCapture,
|
|
11110
|
+
checkedAt: Date.now(),
|
|
11111
|
+
inputFormat,
|
|
11112
|
+
issues,
|
|
11113
|
+
operationsRecordHref: options.operationsRecordHref,
|
|
11114
|
+
outputFormat,
|
|
11115
|
+
provider: options.provider,
|
|
11116
|
+
readinessHref: options.readinessHref,
|
|
11117
|
+
runtime: {
|
|
11118
|
+
assistantAudioSamples,
|
|
11119
|
+
firstAudioLatencyMs,
|
|
11120
|
+
inputAudioSamples,
|
|
11121
|
+
samples: runtimeSamples
|
|
11122
|
+
},
|
|
11123
|
+
status,
|
|
11124
|
+
surface: options.surface ?? "Direct realtime/duplex providers"
|
|
11125
|
+
};
|
|
11126
|
+
};
|
|
11127
|
+
var evaluateVoiceRealtimeChannelEvidence = (report, input = {}) => {
|
|
11128
|
+
const issues = [];
|
|
11129
|
+
if ((input.requirePass ?? false) && report.status !== "pass") {
|
|
11130
|
+
issues.push(`Expected realtime channel proof to pass, found ${report.status}.`);
|
|
11131
|
+
}
|
|
11132
|
+
if (input.requireBrowserCapture && !report.browserCapture) {
|
|
11133
|
+
issues.push("Missing browser capture negotiation proof.");
|
|
11134
|
+
}
|
|
11135
|
+
if (input.requireOperationsRecordHref && !report.operationsRecordHref) {
|
|
11136
|
+
issues.push("Missing operations-record link for realtime channel proof.");
|
|
11137
|
+
}
|
|
11138
|
+
if (input.requireReadinessHref && !report.readinessHref) {
|
|
11139
|
+
issues.push("Missing readiness link for realtime channel proof.");
|
|
11140
|
+
}
|
|
11141
|
+
if (input.minInputAudioSamples !== undefined && report.runtime.inputAudioSamples < input.minInputAudioSamples) {
|
|
11142
|
+
issues.push(`Expected at least ${String(input.minInputAudioSamples)} realtime input audio samples, found ${String(report.runtime.inputAudioSamples)}.`);
|
|
11143
|
+
}
|
|
11144
|
+
if (input.minAssistantAudioSamples !== undefined && report.runtime.assistantAudioSamples < input.minAssistantAudioSamples) {
|
|
11145
|
+
issues.push(`Expected at least ${String(input.minAssistantAudioSamples)} realtime assistant audio samples, found ${String(report.runtime.assistantAudioSamples)}.`);
|
|
11146
|
+
}
|
|
11147
|
+
if (input.maxFirstAudioLatencyMs !== undefined && (report.runtime.firstAudioLatencyMs === undefined || report.runtime.firstAudioLatencyMs > input.maxFirstAudioLatencyMs)) {
|
|
11148
|
+
issues.push(`Expected first realtime assistant audio at or below ${String(input.maxFirstAudioLatencyMs)}ms, found ${String(report.runtime.firstAudioLatencyMs ?? "missing")}ms.`);
|
|
11149
|
+
}
|
|
11150
|
+
return {
|
|
11151
|
+
issues,
|
|
11152
|
+
ok: issues.length === 0,
|
|
11153
|
+
provider: report.provider,
|
|
11154
|
+
status: report.status,
|
|
11155
|
+
surface: report.surface
|
|
11156
|
+
};
|
|
11157
|
+
};
|
|
11158
|
+
var assertVoiceRealtimeChannelEvidence = (report, input = {}) => {
|
|
11159
|
+
const assertion = evaluateVoiceRealtimeChannelEvidence(report, input);
|
|
11160
|
+
if (!assertion.ok) {
|
|
11161
|
+
throw new Error(`Voice realtime channel assertion failed: ${assertion.issues.join(" ")}`);
|
|
11162
|
+
}
|
|
11163
|
+
return assertion;
|
|
11164
|
+
};
|
|
11165
|
+
var renderVoiceRealtimeChannelMarkdown = (report) => [
|
|
11166
|
+
"# Voice Realtime Channel Proof",
|
|
11167
|
+
"",
|
|
11168
|
+
`- Status: ${report.status}`,
|
|
11169
|
+
`- Provider: ${report.provider}`,
|
|
11170
|
+
`- Surface: ${report.surface}`,
|
|
11171
|
+
`- Input format: ${formatLabel(report.inputFormat)}`,
|
|
11172
|
+
`- Output format: ${formatLabel(report.outputFormat)}`,
|
|
11173
|
+
`- Browser capture: ${report.browserCapture ? `${String(report.browserCapture.sampleRateHz)}hz target, ${String(report.browserCapture.channelCount ?? 1)}ch` : "missing"}`,
|
|
11174
|
+
`- Resampling required: ${report.browserCapture?.resamplingRequired ? "yes" : "no"}`,
|
|
11175
|
+
`- Input audio samples: ${String(report.runtime.inputAudioSamples)}`,
|
|
11176
|
+
`- Assistant audio samples: ${String(report.runtime.assistantAudioSamples)}`,
|
|
11177
|
+
`- First audio latency: ${String(report.runtime.firstAudioLatencyMs ?? "n/a")}ms`,
|
|
11178
|
+
"",
|
|
11179
|
+
"## Issues",
|
|
11180
|
+
"",
|
|
11181
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue.severity.toUpperCase()} ${issue.code}: ${issue.message}`) : ["- None"]
|
|
11182
|
+
].join(`
|
|
11183
|
+
`);
|
|
11184
|
+
var renderVoiceRealtimeChannelHTML = (report, title = "Voice Realtime Channel Proof") => {
|
|
11185
|
+
const issues = report.issues.map((issue) => `<li class="${escapeHtml12(issue.severity)}"><strong>${escapeHtml12(issue.code)}</strong>: ${escapeHtml12(issue.message)}</li>`).join("");
|
|
11186
|
+
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("");
|
|
11187
|
+
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>`;
|
|
11188
|
+
};
|
|
11189
|
+
var createVoiceRealtimeChannelRoutes = (options) => {
|
|
11190
|
+
const path = options.path ?? "/api/voice/realtime-channel";
|
|
11191
|
+
const htmlPath = options.htmlPath ?? "/voice/realtime-channel";
|
|
11192
|
+
const markdownPath = options.markdownPath ?? "/voice/realtime-channel.md";
|
|
11193
|
+
const headers = options.headers ?? {};
|
|
11194
|
+
const title = options.title ?? "Voice Realtime Channel Proof";
|
|
11195
|
+
const resolveOptions = async () => {
|
|
11196
|
+
const source = typeof options.source === "function" ? await options.source() : options.source ?? options;
|
|
11197
|
+
const {
|
|
11198
|
+
headers: _headers,
|
|
11199
|
+
htmlPath: _htmlPath,
|
|
11200
|
+
markdownPath: _markdownPath,
|
|
11201
|
+
name: _name,
|
|
11202
|
+
path: _path,
|
|
11203
|
+
render: _render,
|
|
11204
|
+
source: _source,
|
|
11205
|
+
title: _title,
|
|
11206
|
+
...reportOptions
|
|
11207
|
+
} = {
|
|
11208
|
+
...options,
|
|
11209
|
+
...source
|
|
11210
|
+
};
|
|
11211
|
+
return reportOptions;
|
|
11212
|
+
};
|
|
11213
|
+
const report = async () => buildVoiceRealtimeChannelReport(await resolveOptions());
|
|
11214
|
+
const app = new Elysia9({ name: options.name ?? "voice-realtime-channel" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
11215
|
+
headers: {
|
|
11216
|
+
"content-type": "application/json; charset=utf-8",
|
|
11217
|
+
...headers
|
|
11218
|
+
}
|
|
11219
|
+
}));
|
|
11220
|
+
if (htmlPath !== false) {
|
|
11221
|
+
app.get(htmlPath, async () => {
|
|
11222
|
+
const current = await report();
|
|
11223
|
+
const body = options.render ? await options.render(current) : renderVoiceRealtimeChannelHTML(current, title);
|
|
11224
|
+
return new Response(body, {
|
|
11225
|
+
headers: {
|
|
11226
|
+
"content-type": "text/html; charset=utf-8",
|
|
11227
|
+
...headers
|
|
11228
|
+
}
|
|
11229
|
+
});
|
|
11230
|
+
});
|
|
11231
|
+
}
|
|
11232
|
+
if (markdownPath !== false) {
|
|
11233
|
+
app.get(markdownPath, async () => new Response(renderVoiceRealtimeChannelMarkdown(await report()), {
|
|
11234
|
+
headers: {
|
|
11235
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
11236
|
+
...headers
|
|
11237
|
+
}
|
|
11238
|
+
}));
|
|
11239
|
+
}
|
|
11240
|
+
return app;
|
|
11241
|
+
};
|
|
11242
|
+
// src/diagnosticsRoutes.ts
|
|
11243
|
+
import { Elysia as Elysia10 } from "elysia";
|
|
11244
|
+
var escapeHtml13 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10926
11245
|
var getString6 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
10927
11246
|
var getNumber4 = (value) => {
|
|
10928
11247
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
|
|
@@ -10988,9 +11307,9 @@ var renderDiagnosticsIndex = (input) => {
|
|
|
10988
11307
|
const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
|
|
10989
11308
|
const summary = summarizeVoiceTrace(events);
|
|
10990
11309
|
const encoded = encodeURIComponent(sessionId);
|
|
10991
|
-
return `<tr><td>${
|
|
11310
|
+
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
11311
|
}).join("");
|
|
10993
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11312
|
+
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
11313
|
};
|
|
10995
11314
|
var withRedaction = (events, query, defaultRedact) => {
|
|
10996
11315
|
const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
|
|
@@ -10999,7 +11318,7 @@ var withRedaction = (events, query, defaultRedact) => {
|
|
|
10999
11318
|
var createVoiceDiagnosticsRoutes = (options) => {
|
|
11000
11319
|
const path = options.path ?? "/diagnostics";
|
|
11001
11320
|
const title = options.title ?? "AbsoluteJS Voice Diagnostics";
|
|
11002
|
-
const routes = new
|
|
11321
|
+
const routes = new Elysia10({
|
|
11003
11322
|
name: options.name ?? "absolutejs-voice-diagnostics"
|
|
11004
11323
|
});
|
|
11005
11324
|
routes.get(path, async () => {
|
|
@@ -11056,8 +11375,8 @@ var createVoiceDiagnosticsRoutes = (options) => {
|
|
|
11056
11375
|
return routes;
|
|
11057
11376
|
};
|
|
11058
11377
|
// src/demoReadyRoutes.ts
|
|
11059
|
-
import { Elysia as
|
|
11060
|
-
var
|
|
11378
|
+
import { Elysia as Elysia11 } from "elysia";
|
|
11379
|
+
var escapeHtml14 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11061
11380
|
var rollupStatus = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
11062
11381
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
11063
11382
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
@@ -11141,17 +11460,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
11141
11460
|
};
|
|
11142
11461
|
};
|
|
11143
11462
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
11144
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
11145
|
-
<div><span>${
|
|
11146
|
-
<strong>${
|
|
11147
|
-
${section.href ? `<a href="${
|
|
11463
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml14(section.status)}">
|
|
11464
|
+
<div><span>${escapeHtml14(section.status.toUpperCase())}</span><h2>${escapeHtml14(section.label)}</h2>${section.description ? `<p>${escapeHtml14(section.description)}</p>` : ""}</div>
|
|
11465
|
+
<strong>${escapeHtml14(String(section.value ?? section.status))}</strong>
|
|
11466
|
+
${section.href ? `<a href="${escapeHtml14(section.href)}">Open</a>` : ""}
|
|
11148
11467
|
</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>${
|
|
11468
|
+
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
11469
|
};
|
|
11151
11470
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
11152
11471
|
const path = options.path ?? "/api/demo-ready";
|
|
11153
11472
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
11154
|
-
const routes = new
|
|
11473
|
+
const routes = new Elysia11({
|
|
11155
11474
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
11156
11475
|
});
|
|
11157
11476
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -11170,7 +11489,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
11170
11489
|
return routes;
|
|
11171
11490
|
};
|
|
11172
11491
|
// src/deliverySinkRoutes.ts
|
|
11173
|
-
import { Elysia as
|
|
11492
|
+
import { Elysia as Elysia12 } from "elysia";
|
|
11174
11493
|
|
|
11175
11494
|
// src/queue.ts
|
|
11176
11495
|
var releaseLeaseScript = `
|
|
@@ -12113,7 +12432,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
12113
12432
|
};
|
|
12114
12433
|
|
|
12115
12434
|
// src/deliverySinkRoutes.ts
|
|
12116
|
-
var
|
|
12435
|
+
var escapeHtml15 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12117
12436
|
var deliveryStatus = (summary) => {
|
|
12118
12437
|
if (!summary) {
|
|
12119
12438
|
return "warn";
|
|
@@ -12212,13 +12531,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
12212
12531
|
return "";
|
|
12213
12532
|
}
|
|
12214
12533
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
12215
|
-
const body = `<span>${
|
|
12216
|
-
return `<article>${surface.href ? `<a href="${
|
|
12534
|
+
const body = `<span>${escapeHtml15(surface.label)}</span><strong>${escapeHtml15(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
12535
|
+
return `<article>${surface.href ? `<a href="${escapeHtml15(surface.href)}">${body}</a>` : body}</article>`;
|
|
12217
12536
|
};
|
|
12218
12537
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
12219
12538
|
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>${
|
|
12539
|
+
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>';
|
|
12540
|
+
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
12541
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
12223
12542
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
12224
12543
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -12230,7 +12549,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
12230
12549
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
12231
12550
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
12232
12551
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
12233
|
-
const routes = new
|
|
12552
|
+
const routes = new Elysia12({
|
|
12234
12553
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
12235
12554
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
12236
12555
|
if (htmlPath !== false) {
|
|
@@ -12248,7 +12567,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
12248
12567
|
return routes;
|
|
12249
12568
|
};
|
|
12250
12569
|
// src/opsActionAuditRoutes.ts
|
|
12251
|
-
import { Elysia as
|
|
12570
|
+
import { Elysia as Elysia13 } from "elysia";
|
|
12252
12571
|
var readRecordBody = (body) => {
|
|
12253
12572
|
if (!body || typeof body !== "object") {
|
|
12254
12573
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -12323,7 +12642,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
12323
12642
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
12324
12643
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
12325
12644
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
12326
|
-
const routes = new
|
|
12645
|
+
const routes = new Elysia13({
|
|
12327
12646
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
12328
12647
|
}).post(path, async ({ body, request, set }) => {
|
|
12329
12648
|
try {
|
|
@@ -12373,13 +12692,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
12373
12692
|
total: entries.length
|
|
12374
12693
|
};
|
|
12375
12694
|
};
|
|
12376
|
-
var
|
|
12695
|
+
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12377
12696
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
12378
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
12697
|
+
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
12698
|
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
12699
|
};
|
|
12381
12700
|
// src/platformCoverage.ts
|
|
12382
|
-
import { Elysia as
|
|
12701
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12383
12702
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
12384
12703
|
const coverage = input.coverage ?? [];
|
|
12385
12704
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -12440,7 +12759,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
12440
12759
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
12441
12760
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
12442
12761
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
12443
|
-
const routes = new
|
|
12762
|
+
const routes = new Elysia14({
|
|
12444
12763
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
12445
12764
|
});
|
|
12446
12765
|
routes.get(path, async () => {
|
|
@@ -12452,8 +12771,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
12452
12771
|
return routes;
|
|
12453
12772
|
};
|
|
12454
12773
|
// src/competitiveCoverage.ts
|
|
12455
|
-
import { Elysia as
|
|
12456
|
-
var
|
|
12774
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12775
|
+
var escapeHtml17 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12457
12776
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
12458
12777
|
var resolveSurfaceStatus = (surface) => {
|
|
12459
12778
|
if (surface.status)
|
|
@@ -12621,24 +12940,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
12621
12940
|
`);
|
|
12622
12941
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
12623
12942
|
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>${
|
|
12943
|
+
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("");
|
|
12944
|
+
return `<article class="surface ${escapeHtml17(surface.status)} ${escapeHtml17(surface.depth)}">
|
|
12945
|
+
<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>
|
|
12946
|
+
<p>${escapeHtml17(surface.why)}</p>
|
|
12628
12947
|
<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>${
|
|
12948
|
+
<div><dt>Competitors</dt><dd>${escapeHtml17((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
12949
|
+
<div><dt>Operations record</dt><dd>${escapeHtml17(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
12950
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml17(surface.readinessGate ?? "unknown")}</dd></div>
|
|
12951
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml17((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
12633
12952
|
</dl>
|
|
12634
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
12635
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
12953
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml17(surface.remainingGap)}</p>` : ""}
|
|
12954
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml17(surface.nextMove)}</p>` : ""}
|
|
12636
12955
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
12637
12956
|
</article>`;
|
|
12638
12957
|
}).join(`
|
|
12639
12958
|
`);
|
|
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>${
|
|
12959
|
+
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("");
|
|
12960
|
+
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
12961
|
};
|
|
12643
12962
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
12644
12963
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -12651,7 +12970,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12651
12970
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
12652
12971
|
return normalizeCompetitiveCoverageReport(value);
|
|
12653
12972
|
};
|
|
12654
|
-
const app = new
|
|
12973
|
+
const app = new Elysia15({
|
|
12655
12974
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
12656
12975
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
12657
12976
|
headers: {
|
|
@@ -12682,7 +13001,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
12682
13001
|
return app;
|
|
12683
13002
|
};
|
|
12684
13003
|
// src/proofTrends.ts
|
|
12685
|
-
import { Elysia as
|
|
13004
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12686
13005
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
12687
13006
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
12688
13007
|
var toTimeMs = (value) => {
|
|
@@ -12833,7 +13152,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
12833
13152
|
};
|
|
12834
13153
|
var createVoiceProofTrendRoutes = (options) => {
|
|
12835
13154
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
12836
|
-
const routes = new
|
|
13155
|
+
const routes = new Elysia16({
|
|
12837
13156
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
12838
13157
|
});
|
|
12839
13158
|
routes.get(path, async () => {
|
|
@@ -12866,11 +13185,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
12866
13185
|
return `${days}d ${hours % 24}h`;
|
|
12867
13186
|
};
|
|
12868
13187
|
// src/providerDecisionTraces.ts
|
|
12869
|
-
import { Elysia as
|
|
13188
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
12870
13189
|
|
|
12871
13190
|
// src/resilienceRoutes.ts
|
|
12872
|
-
import { Elysia as
|
|
12873
|
-
var
|
|
13191
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13192
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12874
13193
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
12875
13194
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
12876
13195
|
var getBoolean2 = (value) => value === true;
|
|
@@ -13018,13 +13337,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
13018
13337
|
};
|
|
13019
13338
|
var renderProviderCards = (title, providers) => {
|
|
13020
13339
|
if (providers.length === 0) {
|
|
13021
|
-
return `<p class="muted">No ${
|
|
13340
|
+
return `<p class="muted">No ${escapeHtml18(title)} provider health yet.</p>`;
|
|
13022
13341
|
}
|
|
13023
13342
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
13024
|
-
<article class="card provider ${
|
|
13343
|
+
<article class="card provider ${escapeHtml18(provider.status)}">
|
|
13025
13344
|
<div class="card-header">
|
|
13026
|
-
<strong>${
|
|
13027
|
-
<span>${
|
|
13345
|
+
<strong>${escapeHtml18(provider.provider)}</strong>
|
|
13346
|
+
<span>${escapeHtml18(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
13028
13347
|
</div>
|
|
13029
13348
|
<dl>
|
|
13030
13349
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -13033,7 +13352,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
13033
13352
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
13034
13353
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
13035
13354
|
</dl>
|
|
13036
|
-
${provider.lastError ? `<p class="muted">${
|
|
13355
|
+
${provider.lastError ? `<p class="muted">${escapeHtml18(provider.lastError)}</p>` : ""}
|
|
13037
13356
|
</article>
|
|
13038
13357
|
`).join("")}</div>`;
|
|
13039
13358
|
};
|
|
@@ -13042,24 +13361,24 @@ var renderTimeline2 = (events) => {
|
|
|
13042
13361
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
13043
13362
|
}
|
|
13044
13363
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
13045
|
-
<article class="card event ${
|
|
13364
|
+
<article class="card event ${escapeHtml18(event.status ?? "unknown")}">
|
|
13046
13365
|
<div class="card-header">
|
|
13047
|
-
<strong>${
|
|
13366
|
+
<strong>${escapeHtml18(event.kind.toUpperCase())} ${escapeHtml18(event.operation ?? "generate")}</strong>
|
|
13048
13367
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
13049
13368
|
</div>
|
|
13050
13369
|
<p>
|
|
13051
|
-
<span class="pill">${
|
|
13052
|
-
<span class="pill">provider: ${
|
|
13053
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
13370
|
+
<span class="pill">${escapeHtml18(event.status ?? "unknown")}</span>
|
|
13371
|
+
<span class="pill">provider: ${escapeHtml18(event.provider ?? "unknown")}</span>
|
|
13372
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml18(event.fallbackProvider)}</span>` : ""}
|
|
13054
13373
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
13055
13374
|
</p>
|
|
13056
13375
|
<dl>
|
|
13057
13376
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
13058
13377
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
13059
13378
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
13060
|
-
<div><dt>Session</dt><dd>${
|
|
13379
|
+
<div><dt>Session</dt><dd>${escapeHtml18(event.sessionId)}</dd></div>
|
|
13061
13380
|
</dl>
|
|
13062
|
-
${event.error ? `<p class="muted">${
|
|
13381
|
+
${event.error ? `<p class="muted">${escapeHtml18(event.error)}</p>` : ""}
|
|
13063
13382
|
</article>
|
|
13064
13383
|
`).join("")}</div>`;
|
|
13065
13384
|
};
|
|
@@ -13069,9 +13388,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
13069
13388
|
const status = latest?.status ?? "idle";
|
|
13070
13389
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
13071
13390
|
return `<div>
|
|
13072
|
-
<dt>${
|
|
13073
|
-
<dd>${
|
|
13074
|
-
<small>${
|
|
13391
|
+
<dt>${escapeHtml18(kind.toUpperCase())}</dt>
|
|
13392
|
+
<dd>${escapeHtml18(provider)}${escapeHtml18(fallback)}</dd>
|
|
13393
|
+
<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
13394
|
</div>`;
|
|
13076
13395
|
};
|
|
13077
13396
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -13079,10 +13398,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
13079
13398
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
13080
13399
|
}
|
|
13081
13400
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
13082
|
-
<article class="card session ${
|
|
13401
|
+
<article class="card session ${escapeHtml18(session.status)}">
|
|
13083
13402
|
<div class="card-header">
|
|
13084
|
-
<strong>${
|
|
13085
|
-
<span>${
|
|
13403
|
+
<strong>${escapeHtml18(session.sessionId)}</strong>
|
|
13404
|
+
<span>${escapeHtml18(session.status)}</span>
|
|
13086
13405
|
</div>
|
|
13087
13406
|
<p>
|
|
13088
13407
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -13109,21 +13428,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
13109
13428
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
13110
13429
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
13111
13430
|
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">${
|
|
13431
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml18(pathPrefix)}">
|
|
13432
|
+
<p class="muted">${escapeHtml18(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
13114
13433
|
<div class="simulate-actions">
|
|
13115
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
13116
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
13434
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml18(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml18(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
13435
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml18(provider.provider)}">Mark ${escapeHtml18(provider.provider)} recovered</button>`).join("")}
|
|
13117
13436
|
</div>
|
|
13118
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
13437
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml18(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
13119
13438
|
<pre class="simulate-output" hidden></pre>
|
|
13120
13439
|
</div>`;
|
|
13121
13440
|
};
|
|
13122
13441
|
var renderVoiceResilienceHTML = (input) => {
|
|
13123
13442
|
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 =
|
|
13443
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml18(kind)}: ${String(count)}</span>`).join("");
|
|
13444
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join(" \xB7 ") : "";
|
|
13445
|
+
const snippet = escapeHtml18(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
13127
13446
|
kind: 'stt',
|
|
13128
13447
|
providers: ['deepgram', 'assemblyai'],
|
|
13129
13448
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -13161,7 +13480,7 @@ app.use(
|
|
|
13161
13480
|
<head>
|
|
13162
13481
|
<meta charset="utf-8" />
|
|
13163
13482
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13164
|
-
<title>${
|
|
13483
|
+
<title>${escapeHtml18(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
13165
13484
|
<style>
|
|
13166
13485
|
:root { color-scheme: dark; }
|
|
13167
13486
|
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 +13632,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
13313
13632
|
};
|
|
13314
13633
|
var createVoiceResilienceRoutes = (options) => {
|
|
13315
13634
|
const path = options.path ?? "/resilience";
|
|
13316
|
-
const routes = new
|
|
13635
|
+
const routes = new Elysia17({
|
|
13317
13636
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
13318
13637
|
}).get(path, async () => {
|
|
13319
13638
|
const events = await options.store.list();
|
|
@@ -13354,7 +13673,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
13354
13673
|
};
|
|
13355
13674
|
|
|
13356
13675
|
// src/providerDecisionTraces.ts
|
|
13357
|
-
var
|
|
13676
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13358
13677
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
13359
13678
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13360
13679
|
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 +13914,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
13595
13914
|
<head>
|
|
13596
13915
|
<meta charset="utf-8" />
|
|
13597
13916
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13598
|
-
<title>${
|
|
13917
|
+
<title>${escapeHtml19(title)}</title>
|
|
13599
13918
|
<style>
|
|
13600
13919
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
13601
13920
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -13609,8 +13928,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13609
13928
|
</head>
|
|
13610
13929
|
<body>
|
|
13611
13930
|
<main>
|
|
13612
|
-
<p class="status ${report.status}">${
|
|
13613
|
-
<h1>${
|
|
13931
|
+
<p class="status ${report.status}">${escapeHtml19(report.status)}</p>
|
|
13932
|
+
<h1>${escapeHtml19(title)}</h1>
|
|
13614
13933
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
13615
13934
|
<section class="grid">
|
|
13616
13935
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -13621,10 +13940,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
13621
13940
|
</section>
|
|
13622
13941
|
<section class="surfaces">
|
|
13623
13942
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
13624
|
-
<header><strong>${
|
|
13943
|
+
<header><strong>${escapeHtml19(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml19(surface.status)}</span></header>
|
|
13625
13944
|
<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>${
|
|
13945
|
+
<p class="muted">Providers: ${escapeHtml19(surface.providers.join(", ") || "none")}</p>
|
|
13946
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml19(reason)}</code>`).join(" ")}</p>
|
|
13628
13947
|
</article>`).join(`
|
|
13629
13948
|
`)}
|
|
13630
13949
|
</section>
|
|
@@ -13638,7 +13957,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13638
13957
|
const headers = options.headers ?? {};
|
|
13639
13958
|
const title = options.title ?? "Provider Decision Traces";
|
|
13640
13959
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
13641
|
-
const app = new
|
|
13960
|
+
const app = new Elysia18({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13642
13961
|
headers: {
|
|
13643
13962
|
"content-type": "application/json; charset=utf-8",
|
|
13644
13963
|
...headers
|
|
@@ -13666,7 +13985,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
13666
13985
|
return app;
|
|
13667
13986
|
};
|
|
13668
13987
|
// src/sloCalibration.ts
|
|
13669
|
-
import { Elysia as
|
|
13988
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13670
13989
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
13671
13990
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
13672
13991
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -13846,7 +14165,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
13846
14165
|
};
|
|
13847
14166
|
};
|
|
13848
14167
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
13849
|
-
var
|
|
14168
|
+
var escapeHtml20 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13850
14169
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
13851
14170
|
var readinessThresholdRows = (report) => [
|
|
13852
14171
|
{
|
|
@@ -13937,15 +14256,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
13937
14256
|
};
|
|
13938
14257
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
13939
14258
|
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>${
|
|
14259
|
+
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("");
|
|
14260
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml20(issue)}</li>`).join("");
|
|
14261
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml20(source)}</code></li>`).join("");
|
|
14262
|
+
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
14263
|
};
|
|
13945
14264
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
13946
14265
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
13947
14266
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
13948
|
-
const routes = new
|
|
14267
|
+
const routes = new Elysia19({
|
|
13949
14268
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
13950
14269
|
});
|
|
13951
14270
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -13969,7 +14288,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
13969
14288
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
13970
14289
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
13971
14290
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
13972
|
-
const routes = new
|
|
14291
|
+
const routes = new Elysia19({
|
|
13973
14292
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
13974
14293
|
});
|
|
13975
14294
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -14003,7 +14322,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
14003
14322
|
return routes;
|
|
14004
14323
|
};
|
|
14005
14324
|
// src/liveOps.ts
|
|
14006
|
-
import { Elysia as
|
|
14325
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
14007
14326
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
14008
14327
|
"assign",
|
|
14009
14328
|
"create-task",
|
|
@@ -14313,7 +14632,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14313
14632
|
const controller = createVoiceLiveOpsController(options);
|
|
14314
14633
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
14315
14634
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
14316
|
-
return new
|
|
14635
|
+
return new Elysia20({
|
|
14317
14636
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
14318
14637
|
}).post(path, async ({ request, set }) => {
|
|
14319
14638
|
try {
|
|
@@ -14335,15 +14654,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
14335
14654
|
});
|
|
14336
14655
|
};
|
|
14337
14656
|
// src/deliveryRuntime.ts
|
|
14338
|
-
import { Elysia as
|
|
14657
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14339
14658
|
import { mkdir } from "fs/promises";
|
|
14340
14659
|
import { dirname, join } from "path";
|
|
14341
|
-
var
|
|
14660
|
+
var escapeHtml21 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14342
14661
|
var renderSummaryCard = (label, summary) => {
|
|
14343
14662
|
if (!summary) {
|
|
14344
|
-
return `<article><span>${
|
|
14663
|
+
return `<article><span>${escapeHtml21(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
14345
14664
|
}
|
|
14346
|
-
return `<article><span>${
|
|
14665
|
+
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
14666
|
};
|
|
14348
14667
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
14349
14668
|
audit: leases,
|
|
@@ -14554,9 +14873,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
14554
14873
|
});
|
|
14555
14874
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
14556
14875
|
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 =
|
|
14876
|
+
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>`;
|
|
14877
|
+
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>`;
|
|
14878
|
+
const snippet = escapeHtml21(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
14560
14879
|
createVoiceDeliveryRuntimePresetConfig({
|
|
14561
14880
|
audit: {
|
|
14562
14881
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -14582,14 +14901,14 @@ app.use(
|
|
|
14582
14901
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
14583
14902
|
})
|
|
14584
14903
|
);`);
|
|
14585
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14904
|
+
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
14905
|
};
|
|
14587
14906
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
14588
14907
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
14589
14908
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
14590
14909
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
14591
14910
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
14592
|
-
const routes = new
|
|
14911
|
+
const routes = new Elysia21({
|
|
14593
14912
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
14594
14913
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
14595
14914
|
if (tickPath !== false) {
|
|
@@ -14625,7 +14944,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
14625
14944
|
return routes;
|
|
14626
14945
|
};
|
|
14627
14946
|
// src/dataControl.ts
|
|
14628
|
-
import { Elysia as
|
|
14947
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14629
14948
|
var voiceComplianceRedactionDefaults = {
|
|
14630
14949
|
keys: [
|
|
14631
14950
|
"apiKey",
|
|
@@ -14864,7 +15183,7 @@ var parseRetentionScopes = (value) => {
|
|
|
14864
15183
|
const allowed = new Set(allRetentionScopes);
|
|
14865
15184
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
14866
15185
|
};
|
|
14867
|
-
var
|
|
15186
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14868
15187
|
var buildStorageSurfaces = (options) => [
|
|
14869
15188
|
{
|
|
14870
15189
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -15101,12 +15420,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
15101
15420
|
zeroRetentionAvailable: true
|
|
15102
15421
|
};
|
|
15103
15422
|
};
|
|
15104
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
15423
|
+
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
15424
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
15106
15425
|
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>${
|
|
15426
|
+
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("");
|
|
15427
|
+
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("");
|
|
15428
|
+
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
15429
|
};
|
|
15111
15430
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
15112
15431
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -15164,7 +15483,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
15164
15483
|
var createVoiceDataControlRoutes = (options) => {
|
|
15165
15484
|
const path = options.path ?? "/data-control";
|
|
15166
15485
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
15167
|
-
const routes = new
|
|
15486
|
+
const routes = new Elysia22({
|
|
15168
15487
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
15169
15488
|
});
|
|
15170
15489
|
routes.get(path, async ({ query }) => {
|
|
@@ -15240,16 +15559,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
15240
15559
|
return routes;
|
|
15241
15560
|
};
|
|
15242
15561
|
// src/evalRoutes.ts
|
|
15243
|
-
import { Elysia as
|
|
15562
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15244
15563
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
15245
15564
|
import { dirname as dirname2 } from "path";
|
|
15246
15565
|
|
|
15247
15566
|
// src/qualityRoutes.ts
|
|
15248
|
-
import { Elysia as
|
|
15567
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15249
15568
|
|
|
15250
15569
|
// src/handoffHealth.ts
|
|
15251
|
-
import { Elysia as
|
|
15252
|
-
var
|
|
15570
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
15571
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15253
15572
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15254
15573
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
15255
15574
|
var increment3 = (record, key) => {
|
|
@@ -15367,10 +15686,10 @@ var renderActionSummary = (summary) => {
|
|
|
15367
15686
|
return [
|
|
15368
15687
|
'<section class="voice-handoff-health-columns">',
|
|
15369
15688
|
"<article><h3>Actions</h3>",
|
|
15370
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
15689
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml23(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
15371
15690
|
"</article>",
|
|
15372
15691
|
"<article><h3>Adapters</h3>",
|
|
15373
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
15692
|
+
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
15693
|
"</article>",
|
|
15375
15694
|
"</section>"
|
|
15376
15695
|
].join("");
|
|
@@ -15384,22 +15703,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
15384
15703
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
15385
15704
|
'<div class="voice-handoff-health-events">',
|
|
15386
15705
|
...summary.events.map((event) => [
|
|
15387
|
-
`<article class="${
|
|
15706
|
+
`<article class="${escapeHtml23(event.status)}">`,
|
|
15388
15707
|
'<div class="voice-handoff-health-event-header">',
|
|
15389
|
-
`<strong>${
|
|
15390
|
-
`<span>${
|
|
15708
|
+
`<strong>${escapeHtml23(event.action ?? "handoff")}</strong>`,
|
|
15709
|
+
`<span>${escapeHtml23(event.status)}</span>`,
|
|
15391
15710
|
"</div>",
|
|
15392
|
-
`<p><small>${
|
|
15393
|
-
event.target ? `<p>Target: ${
|
|
15394
|
-
event.reason ? `<p>Reason: ${
|
|
15711
|
+
`<p><small>${escapeHtml23(event.sessionId)}</small></p>`,
|
|
15712
|
+
event.target ? `<p>Target: ${escapeHtml23(event.target)}</p>` : "",
|
|
15713
|
+
event.reason ? `<p>Reason: ${escapeHtml23(event.reason)}</p>` : "",
|
|
15395
15714
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
15396
15715
|
"<li>",
|
|
15397
|
-
`${
|
|
15398
|
-
delivery.deliveredTo ? ` to ${
|
|
15399
|
-
delivery.error ? ` (${
|
|
15716
|
+
`${escapeHtml23(delivery.adapterId)}: ${escapeHtml23(delivery.status)}`,
|
|
15717
|
+
delivery.deliveredTo ? ` to ${escapeHtml23(delivery.deliveredTo)}` : "",
|
|
15718
|
+
delivery.error ? ` (${escapeHtml23(delivery.error)})` : "",
|
|
15400
15719
|
"</li>"
|
|
15401
15720
|
].join("")).join("")}</ul>` : "",
|
|
15402
|
-
event.replayHref ? `<p><a href="${
|
|
15721
|
+
event.replayHref ? `<p><a href="${escapeHtml23(event.replayHref)}">Open replay</a></p>` : "",
|
|
15403
15722
|
"</article>"
|
|
15404
15723
|
].join("")),
|
|
15405
15724
|
"</div>"
|
|
@@ -15431,7 +15750,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
15431
15750
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
15432
15751
|
const path = options.path ?? "/api/voice-handoffs";
|
|
15433
15752
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
15434
|
-
const routes = new
|
|
15753
|
+
const routes = new Elysia23({
|
|
15435
15754
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
15436
15755
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
15437
15756
|
if (htmlPath) {
|
|
@@ -15552,17 +15871,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
15552
15871
|
thresholds
|
|
15553
15872
|
};
|
|
15554
15873
|
};
|
|
15555
|
-
var
|
|
15874
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15556
15875
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
15557
15876
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
15558
15877
|
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="${
|
|
15878
|
+
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("");
|
|
15879
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml24(link.href)}">${escapeHtml24(link.label)}</a>`).join("")}</nav>` : "";
|
|
15561
15880
|
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
15881
|
};
|
|
15563
15882
|
var createVoiceQualityRoutes = (options) => {
|
|
15564
15883
|
const path = options.path ?? "/quality";
|
|
15565
|
-
const routes = new
|
|
15884
|
+
const routes = new Elysia24({
|
|
15566
15885
|
name: options.name ?? "absolutejs-voice-quality"
|
|
15567
15886
|
});
|
|
15568
15887
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -15591,7 +15910,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
15591
15910
|
};
|
|
15592
15911
|
|
|
15593
15912
|
// src/evalRoutes.ts
|
|
15594
|
-
var
|
|
15913
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15595
15914
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
15596
15915
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
15597
15916
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -15913,7 +16232,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
15913
16232
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
15914
16233
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
15915
16234
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
15916
|
-
const snippet =
|
|
16235
|
+
const snippet = escapeHtml25(`app.use(
|
|
15917
16236
|
createVoiceEvalRoutes({
|
|
15918
16237
|
path: '/evals',
|
|
15919
16238
|
store: traceStore,
|
|
@@ -15934,48 +16253,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
15934
16253
|
};
|
|
15935
16254
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
15936
16255
|
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>${
|
|
16256
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
16257
|
+
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
16258
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
15940
16259
|
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>${
|
|
16260
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml25(session.operationsRecordHref)}">${escapeHtml25(session.sessionId)}</a>` : escapeHtml25(session.sessionId);
|
|
16261
|
+
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
16262
|
}).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>${
|
|
16263
|
+
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
16264
|
};
|
|
15946
16265
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
15947
16266
|
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>${
|
|
16267
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
16268
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml25(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
16269
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml25(id)}</li>`).join("") : "<li>none</li>";
|
|
16270
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml25(id)}</li>`).join("") : "<li>none</li>";
|
|
16271
|
+
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
16272
|
};
|
|
15954
16273
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
15955
16274
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
15956
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16275
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15957
16276
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
15958
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
16277
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml25(issue)}</li>`).join("")}</ul>` : "";
|
|
15959
16278
|
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>${
|
|
16279
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml25(session.operationsRecordHref)}">${escapeHtml25(session.sessionId)}</a>` : escapeHtml25(session.sessionId);
|
|
16280
|
+
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
16281
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
15963
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
16282
|
+
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
16283
|
}).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>${
|
|
16284
|
+
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
16285
|
};
|
|
15967
16286
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
15968
16287
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
15969
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16288
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml25(link.href)}">${escapeHtml25(link.label)}</a>`).join("")}</nav>` : "";
|
|
15970
16289
|
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>${
|
|
16290
|
+
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("");
|
|
16291
|
+
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
16292
|
}).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>${
|
|
16293
|
+
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
16294
|
};
|
|
15976
16295
|
var createVoiceEvalRoutes = (options) => {
|
|
15977
16296
|
const path = options.path ?? "/evals";
|
|
15978
|
-
const routes = new
|
|
16297
|
+
const routes = new Elysia25({
|
|
15979
16298
|
name: options.name ?? "absolutejs-voice-evals"
|
|
15980
16299
|
});
|
|
15981
16300
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -16112,11 +16431,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
16112
16431
|
return routes;
|
|
16113
16432
|
};
|
|
16114
16433
|
// src/simulationSuite.ts
|
|
16115
|
-
import { Elysia as
|
|
16434
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16116
16435
|
|
|
16117
16436
|
// src/outcomeContract.ts
|
|
16118
|
-
import { Elysia as
|
|
16119
|
-
var
|
|
16437
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
16438
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16120
16439
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
16121
16440
|
if (value === false) {
|
|
16122
16441
|
return;
|
|
@@ -16327,13 +16646,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
16327
16646
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
16328
16647
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
16329
16648
|
const contracts = report.contracts.map((contract) => {
|
|
16330
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
16649
|
+
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
16650
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16332
16651
|
<div class="contract-header">
|
|
16333
16652
|
<div>
|
|
16334
|
-
<p class="eyebrow">${
|
|
16335
|
-
<h2>${
|
|
16336
|
-
${contract.description ? `<p>${
|
|
16653
|
+
<p class="eyebrow">${escapeHtml26(contract.contractId)}</p>
|
|
16654
|
+
<h2>${escapeHtml26(contract.label ?? contract.contractId)}</h2>
|
|
16655
|
+
${contract.description ? `<p>${escapeHtml26(contract.description)}</p>` : ""}
|
|
16337
16656
|
${sessionLinks}
|
|
16338
16657
|
</div>
|
|
16339
16658
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -16345,10 +16664,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
16345
16664
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
16346
16665
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
16347
16666
|
</div>
|
|
16348
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
16667
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml26(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
16349
16668
|
</section>`;
|
|
16350
16669
|
}).join("");
|
|
16351
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16670
|
+
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
16671
|
};
|
|
16353
16672
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
16354
16673
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -16364,7 +16683,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
16364
16683
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
16365
16684
|
const path = options.path ?? "/api/outcome-contracts";
|
|
16366
16685
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16367
|
-
const routes = new
|
|
16686
|
+
const routes = new Elysia26({
|
|
16368
16687
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
16369
16688
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
16370
16689
|
if (htmlPath) {
|
|
@@ -16374,7 +16693,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
16374
16693
|
};
|
|
16375
16694
|
|
|
16376
16695
|
// src/toolContract.ts
|
|
16377
|
-
import { Elysia as
|
|
16696
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16378
16697
|
|
|
16379
16698
|
// src/toolRuntime.ts
|
|
16380
16699
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -16583,7 +16902,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
16583
16902
|
});
|
|
16584
16903
|
var defaultApi = {};
|
|
16585
16904
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
16586
|
-
var
|
|
16905
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16587
16906
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
16588
16907
|
if (value === false) {
|
|
16589
16908
|
return;
|
|
@@ -16832,7 +17151,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
16832
17151
|
};
|
|
16833
17152
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
16834
17153
|
const title = options.title ?? "Voice Tool Contracts";
|
|
16835
|
-
const snippet =
|
|
17154
|
+
const snippet = escapeHtml27(`app.use(
|
|
16836
17155
|
createVoiceToolContractRoutes({
|
|
16837
17156
|
htmlPath: '/tool-contracts',
|
|
16838
17157
|
path: '/api/tool-contracts',
|
|
@@ -16858,20 +17177,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
16858
17177
|
);`);
|
|
16859
17178
|
const contracts = report.contracts.map((contract) => {
|
|
16860
17179
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
16861
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
17180
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml27(testCase.operationsRecordHref)}">${escapeHtml27(testCase.label ?? testCase.caseId)}</a>` : escapeHtml27(testCase.label ?? testCase.caseId)}</td>
|
|
16862
17181
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
16863
|
-
<td>${
|
|
16864
|
-
<td>${
|
|
17182
|
+
<td>${escapeHtml27(testCase.status)}</td>
|
|
17183
|
+
<td>${escapeHtml27(testCase.sessionId)}</td>
|
|
16865
17184
|
<td>${String(testCase.attempts)}</td>
|
|
16866
17185
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
16867
17186
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
16868
|
-
<td>${
|
|
17187
|
+
<td>${escapeHtml27(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
16869
17188
|
</tr>`).join("");
|
|
16870
17189
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
16871
17190
|
<div class="contract-header">
|
|
16872
17191
|
<div>
|
|
16873
|
-
<p class="eyebrow">${
|
|
16874
|
-
<h2>${
|
|
17192
|
+
<p class="eyebrow">${escapeHtml27(contract.toolName)}</p>
|
|
17193
|
+
<h2>${escapeHtml27(contract.label ?? contract.contractId)}</h2>
|
|
16875
17194
|
</div>
|
|
16876
17195
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
16877
17196
|
</div>
|
|
@@ -16881,7 +17200,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
16881
17200
|
</table>
|
|
16882
17201
|
</section>`;
|
|
16883
17202
|
}).join("");
|
|
16884
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17203
|
+
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
17204
|
};
|
|
16886
17205
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
16887
17206
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -16898,7 +17217,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
16898
17217
|
var createVoiceToolContractRoutes = (options) => {
|
|
16899
17218
|
const path = options.path ?? "/api/tool-contracts";
|
|
16900
17219
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16901
|
-
const routes = new
|
|
17220
|
+
const routes = new Elysia27({
|
|
16902
17221
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
16903
17222
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
16904
17223
|
if (htmlPath) {
|
|
@@ -16908,7 +17227,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
16908
17227
|
};
|
|
16909
17228
|
|
|
16910
17229
|
// src/simulationSuite.ts
|
|
16911
|
-
var
|
|
17230
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16912
17231
|
var summarizeSection = (report) => ({
|
|
16913
17232
|
failed: report.failed,
|
|
16914
17233
|
passed: report.passed,
|
|
@@ -17104,15 +17423,15 @@ var renderSection = (label, summary) => {
|
|
|
17104
17423
|
if (!summary) {
|
|
17105
17424
|
return "";
|
|
17106
17425
|
}
|
|
17107
|
-
return `<article class="${
|
|
17426
|
+
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
17427
|
};
|
|
17109
17428
|
var renderAction = (action) => {
|
|
17110
|
-
const content = `<strong>${
|
|
17111
|
-
return action.href ? `<a class="action" href="${
|
|
17429
|
+
const content = `<strong>${escapeHtml28(action.label)}</strong><p>${escapeHtml28(action.description)}</p><span>${escapeHtml28(action.section)} / ${escapeHtml28(action.severity)}</span>`;
|
|
17430
|
+
return action.href ? `<a class="action" href="${escapeHtml28(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
17112
17431
|
};
|
|
17113
17432
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
17114
17433
|
const title = options.title ?? "Voice Simulation Suite";
|
|
17115
|
-
const snippet =
|
|
17434
|
+
const snippet = escapeHtml28(`app.use(
|
|
17116
17435
|
createVoiceSimulationSuiteRoutes({
|
|
17117
17436
|
htmlPath: '/voice/simulations',
|
|
17118
17437
|
path: '/api/voice/simulations',
|
|
@@ -17145,12 +17464,12 @@ app.use(
|
|
|
17145
17464
|
store: traceStore
|
|
17146
17465
|
})
|
|
17147
17466
|
);`);
|
|
17148
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17467
|
+
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
17468
|
};
|
|
17150
17469
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
17151
17470
|
const path = options.path ?? "/api/voice/simulations";
|
|
17152
17471
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
17153
|
-
const app = new
|
|
17472
|
+
const app = new Elysia28({
|
|
17154
17473
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
17155
17474
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
17156
17475
|
if (htmlPath) {
|
|
@@ -17462,9 +17781,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
17462
17781
|
};
|
|
17463
17782
|
};
|
|
17464
17783
|
// src/sessionReplay.ts
|
|
17465
|
-
import { Elysia as
|
|
17784
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
17466
17785
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
17467
|
-
var
|
|
17786
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17468
17787
|
var increment4 = (record, key) => {
|
|
17469
17788
|
record[key] = (record[key] ?? 0) + 1;
|
|
17470
17789
|
};
|
|
@@ -17658,10 +17977,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
17658
17977
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
17659
17978
|
'<div class="voice-sessions-list">',
|
|
17660
17979
|
...sessions.map((session) => [
|
|
17661
|
-
`<article class="voice-session-card ${
|
|
17980
|
+
`<article class="voice-session-card ${escapeHtml29(session.status)}">`,
|
|
17662
17981
|
'<div class="voice-session-card-header">',
|
|
17663
|
-
`<strong>${
|
|
17664
|
-
`<span>${
|
|
17982
|
+
`<strong>${escapeHtml29(session.sessionId)}</strong>`,
|
|
17983
|
+
`<span>${escapeHtml29(session.status)}</span>`,
|
|
17665
17984
|
"</div>",
|
|
17666
17985
|
"<dl>",
|
|
17667
17986
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -17669,9 +17988,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
17669
17988
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
17670
17989
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
17671
17990
|
"</dl>",
|
|
17672
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
17673
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
17674
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
17991
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml29(session.latestOutcome)}</p>` : "",
|
|
17992
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml29).join(", ")}</p>` : "",
|
|
17993
|
+
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
17994
|
"</article>"
|
|
17676
17995
|
].join("")),
|
|
17677
17996
|
"</div>"
|
|
@@ -17702,7 +18021,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
17702
18021
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
17703
18022
|
const path = options.path ?? "/api/voice-sessions";
|
|
17704
18023
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17705
|
-
const routes = new
|
|
18024
|
+
const routes = new Elysia29({
|
|
17706
18025
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
17707
18026
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
17708
18027
|
if (htmlPath) {
|
|
@@ -17730,7 +18049,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
17730
18049
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
17731
18050
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
17732
18051
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17733
|
-
const routes = new
|
|
18052
|
+
const routes = new Elysia29({
|
|
17734
18053
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
17735
18054
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
17736
18055
|
if (htmlPath) {
|
|
@@ -18044,10 +18363,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
18044
18363
|
return report;
|
|
18045
18364
|
};
|
|
18046
18365
|
// src/turnLatency.ts
|
|
18047
|
-
import { Elysia as
|
|
18366
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
18048
18367
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
18049
18368
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
18050
|
-
var
|
|
18369
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18051
18370
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18052
18371
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
18053
18372
|
var createTraceStageIndex = (events) => {
|
|
@@ -18179,11 +18498,11 @@ await traceStore.append({
|
|
|
18179
18498
|
turnId,
|
|
18180
18499
|
type: 'turn_latency.stage'
|
|
18181
18500
|
});`;
|
|
18182
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18183
|
-
<header><div><p class="eyebrow">${
|
|
18184
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
18501
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml30(turn.status)}">
|
|
18502
|
+
<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>
|
|
18503
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml30(stage.label)}</dt><dd>${escapeHtml30(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
18185
18504
|
</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>${
|
|
18505
|
+
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
18506
|
};
|
|
18188
18507
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
18189
18508
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -18200,7 +18519,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
18200
18519
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
18201
18520
|
const path = options.path ?? "/api/turn-latency";
|
|
18202
18521
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18203
|
-
const routes = new
|
|
18522
|
+
const routes = new Elysia30({
|
|
18204
18523
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
18205
18524
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
18206
18525
|
if (htmlPath) {
|
|
@@ -18209,8 +18528,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
18209
18528
|
return routes;
|
|
18210
18529
|
};
|
|
18211
18530
|
// src/liveLatency.ts
|
|
18212
|
-
import { Elysia as
|
|
18213
|
-
var
|
|
18531
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
18532
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18214
18533
|
var percentile3 = (values, percentileValue) => {
|
|
18215
18534
|
if (values.length === 0) {
|
|
18216
18535
|
return;
|
|
@@ -18277,13 +18596,13 @@ await traceStore.append({
|
|
|
18277
18596
|
sessionId,
|
|
18278
18597
|
type: 'client.live_latency'
|
|
18279
18598
|
});`;
|
|
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>${
|
|
18599
|
+
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("");
|
|
18600
|
+
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
18601
|
};
|
|
18283
18602
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
18284
18603
|
const path = options.path ?? "/api/live-latency";
|
|
18285
18604
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
18286
|
-
const routes = new
|
|
18605
|
+
const routes = new Elysia31({
|
|
18287
18606
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
18288
18607
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
18289
18608
|
if (htmlPath) {
|
|
@@ -18602,9 +18921,9 @@ None.
|
|
|
18602
18921
|
`}`;
|
|
18603
18922
|
};
|
|
18604
18923
|
// src/turnQuality.ts
|
|
18605
|
-
import { Elysia as
|
|
18924
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
18606
18925
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
18607
|
-
var
|
|
18926
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18608
18927
|
var getTurnLatencyMs = (turn) => {
|
|
18609
18928
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
18610
18929
|
if (firstTranscriptAt === undefined) {
|
|
@@ -18675,24 +18994,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
18675
18994
|
};
|
|
18676
18995
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
18677
18996
|
const title = options.title ?? "Voice Turn Quality";
|
|
18678
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
18997
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml32(turn.status)}">
|
|
18679
18998
|
<div class="turn-header">
|
|
18680
18999
|
<div>
|
|
18681
|
-
<p class="eyebrow">${
|
|
18682
|
-
<h2>${
|
|
19000
|
+
<p class="eyebrow">${escapeHtml32(turn.sessionId)} \xB7 ${escapeHtml32(turn.turnId)}</p>
|
|
19001
|
+
<h2>${escapeHtml32(turn.text || "Empty turn")}</h2>
|
|
18683
19002
|
</div>
|
|
18684
|
-
<strong>${
|
|
19003
|
+
<strong>${escapeHtml32(turn.status)}</strong>
|
|
18685
19004
|
</div>
|
|
18686
19005
|
<dl>
|
|
18687
|
-
<div><dt>Source</dt><dd>${
|
|
19006
|
+
<div><dt>Source</dt><dd>${escapeHtml32(turn.source ?? "unknown")}</dd></div>
|
|
18688
19007
|
<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 ${
|
|
19008
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml32(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
19009
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml32(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
18691
19010
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
18692
19011
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
18693
19012
|
</dl>
|
|
18694
19013
|
</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>${
|
|
19014
|
+
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
19015
|
};
|
|
18697
19016
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
18698
19017
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -18709,7 +19028,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
18709
19028
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
18710
19029
|
const path = options.path ?? "/api/turn-quality";
|
|
18711
19030
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18712
|
-
const routes = new
|
|
19031
|
+
const routes = new Elysia32({
|
|
18713
19032
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
18714
19033
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
18715
19034
|
if (htmlPath) {
|
|
@@ -18718,7 +19037,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
18718
19037
|
return routes;
|
|
18719
19038
|
};
|
|
18720
19039
|
// src/telephonyOutcome.ts
|
|
18721
|
-
import { Elysia as
|
|
19040
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18722
19041
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
18723
19042
|
"answered",
|
|
18724
19043
|
"completed",
|
|
@@ -19479,7 +19798,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
19479
19798
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
19480
19799
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
19481
19800
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
19482
|
-
return new
|
|
19801
|
+
return new Elysia33({
|
|
19483
19802
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
19484
19803
|
}).post(path, async ({ query, request }) => {
|
|
19485
19804
|
try {
|
|
@@ -19500,12 +19819,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
19500
19819
|
});
|
|
19501
19820
|
};
|
|
19502
19821
|
// src/phoneAgent.ts
|
|
19503
|
-
import { Elysia as
|
|
19822
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
19504
19823
|
|
|
19505
19824
|
// src/telephony/plivo.ts
|
|
19506
19825
|
import { Buffer as Buffer5 } from "buffer";
|
|
19507
19826
|
import { Database } from "bun:sqlite";
|
|
19508
|
-
import { Elysia as
|
|
19827
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19509
19828
|
|
|
19510
19829
|
// src/telephony/contract.ts
|
|
19511
19830
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -19589,7 +19908,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
19589
19908
|
|
|
19590
19909
|
// src/telephony/twilio.ts
|
|
19591
19910
|
import { Buffer as Buffer4 } from "buffer";
|
|
19592
|
-
import { Elysia as
|
|
19911
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19593
19912
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
19594
19913
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
19595
19914
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -19619,7 +19938,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
19619
19938
|
return parameters;
|
|
19620
19939
|
};
|
|
19621
19940
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
19622
|
-
var
|
|
19941
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
19623
19942
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
19624
19943
|
if (!webhook?.verificationUrl) {
|
|
19625
19944
|
return;
|
|
@@ -19662,23 +19981,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
19662
19981
|
};
|
|
19663
19982
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19664
19983
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
19665
|
-
<h1>${
|
|
19984
|
+
<h1>${escapeHtml33(title)}</h1>
|
|
19666
19985
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
19667
19986
|
<section>
|
|
19668
19987
|
<h2>URLs</h2>
|
|
19669
19988
|
<ul>
|
|
19670
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19671
|
-
<li><strong>Media stream:</strong> <code>${
|
|
19672
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
19989
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml33(status.urls.twiml)}</code></li>
|
|
19990
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml33(status.urls.stream)}</code></li>
|
|
19991
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml33(status.urls.webhook)}</code></li>
|
|
19673
19992
|
</ul>
|
|
19674
19993
|
</section>
|
|
19675
19994
|
<section>
|
|
19676
19995
|
<h2>Signing</h2>
|
|
19677
19996
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
19678
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
19997
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml33(status.signing.verificationUrl)}</code></p>` : ""}
|
|
19679
19998
|
</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>${
|
|
19999
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml33(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
20000
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml33(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
19682
20001
|
</main>`;
|
|
19683
20002
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
19684
20003
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -19689,20 +20008,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
19689
20008
|
});
|
|
19690
20009
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
19691
20010
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
19692
|
-
<h1>${
|
|
20011
|
+
<h1>${escapeHtml33(title)}</h1>
|
|
19693
20012
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
19694
20013
|
<section>
|
|
19695
20014
|
<h2>Checks</h2>
|
|
19696
20015
|
<ul>
|
|
19697
|
-
${report.checks.map((check) => `<li><strong>${
|
|
20016
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml33(check.name)}</strong>: ${escapeHtml33(check.status)}${check.message ? ` - ${escapeHtml33(check.message)}` : ""}</li>`).join("")}
|
|
19698
20017
|
</ul>
|
|
19699
20018
|
</section>
|
|
19700
20019
|
<section>
|
|
19701
20020
|
<h2>Observed URLs</h2>
|
|
19702
20021
|
<ul>
|
|
19703
|
-
<li><strong>TwiML:</strong> <code>${
|
|
19704
|
-
<li><strong>Stream:</strong> <code>${
|
|
19705
|
-
<li><strong>Webhook:</strong> <code>${
|
|
20022
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml33(report.setup.urls.twiml)}</code></li>
|
|
20023
|
+
<li><strong>Stream:</strong> <code>${escapeHtml33(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
20024
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml33(report.setup.urls.webhook)}</code></li>
|
|
19706
20025
|
</ul>
|
|
19707
20026
|
</section>
|
|
19708
20027
|
</main>`;
|
|
@@ -20162,7 +20481,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20162
20481
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
20163
20482
|
const bridges = new WeakMap;
|
|
20164
20483
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
20165
|
-
const app = new
|
|
20484
|
+
const app = new Elysia34({
|
|
20166
20485
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
20167
20486
|
}).get(twimlPath, async ({ query, request }) => {
|
|
20168
20487
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -20299,7 +20618,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
20299
20618
|
|
|
20300
20619
|
// src/telephony/plivo.ts
|
|
20301
20620
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20302
|
-
var
|
|
20621
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20303
20622
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20304
20623
|
var resolveRequestOrigin2 = (request) => {
|
|
20305
20624
|
const url = new URL(request.url);
|
|
@@ -20729,21 +21048,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
20729
21048
|
};
|
|
20730
21049
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20731
21050
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
20732
|
-
<h1>${
|
|
21051
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
20733
21052
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20734
21053
|
<ul>
|
|
20735
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
20736
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
20737
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21054
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml34(status.urls.answer)}</code></li>
|
|
21055
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml34(status.urls.stream)}</code></li>
|
|
21056
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml34(status.urls.webhook)}</code></li>
|
|
20738
21057
|
</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>${
|
|
21058
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml34(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21059
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml34(warning)}</li>`).join("")}</ul>` : ""}
|
|
20741
21060
|
</main>`;
|
|
20742
21061
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20743
21062
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
20744
|
-
<h1>${
|
|
21063
|
+
<h1>${escapeHtml34(title)}</h1>
|
|
20745
21064
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20746
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21065
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml34(check.name)}</strong>: ${escapeHtml34(check.status)}${check.message ? ` - ${escapeHtml34(check.message)}` : ""}</li>`).join("")}</ul>
|
|
20747
21066
|
</main>`;
|
|
20748
21067
|
var runPlivoSmokeTest = async (input) => {
|
|
20749
21068
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -20833,7 +21152,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
20833
21152
|
nonceStore: options.webhook.nonceStore,
|
|
20834
21153
|
verificationUrl: options.webhook.verificationUrl
|
|
20835
21154
|
}) : undefined);
|
|
20836
|
-
const app = new
|
|
21155
|
+
const app = new Elysia35({
|
|
20837
21156
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
20838
21157
|
}).get(answerPath, async ({ query, request }) => {
|
|
20839
21158
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -20945,9 +21264,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
20945
21264
|
// src/telephony/telnyx.ts
|
|
20946
21265
|
import { Buffer as Buffer6 } from "buffer";
|
|
20947
21266
|
import { Database as Database2 } from "bun:sqlite";
|
|
20948
|
-
import { Elysia as
|
|
21267
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
20949
21268
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20950
|
-
var
|
|
21269
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20951
21270
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20952
21271
|
var resolveRequestOrigin3 = (request) => {
|
|
20953
21272
|
const url = new URL(request.url);
|
|
@@ -21340,21 +21659,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
21340
21659
|
};
|
|
21341
21660
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21342
21661
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
21343
|
-
<h1>${
|
|
21662
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21344
21663
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21345
21664
|
<ul>
|
|
21346
|
-
<li><strong>TeXML:</strong> <code>${
|
|
21347
|
-
<li><strong>Media stream:</strong> <code>${
|
|
21348
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21665
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml35(status.urls.texml)}</code></li>
|
|
21666
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml35(status.urls.stream)}</code></li>
|
|
21667
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml35(status.urls.webhook)}</code></li>
|
|
21349
21668
|
</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>${
|
|
21669
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml35(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21670
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml35(warning)}</li>`).join("")}</ul>` : ""}
|
|
21352
21671
|
</main>`;
|
|
21353
21672
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21354
21673
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
21355
|
-
<h1>${
|
|
21674
|
+
<h1>${escapeHtml35(title)}</h1>
|
|
21356
21675
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21357
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21676
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml35(check.name)}</strong>: ${escapeHtml35(check.status)}${check.message ? ` - ${escapeHtml35(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21358
21677
|
</main>`;
|
|
21359
21678
|
var runTelnyxSmokeTest = async (input) => {
|
|
21360
21679
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -21447,7 +21766,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21447
21766
|
publicKey: options.webhook.publicKey,
|
|
21448
21767
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
21449
21768
|
}) : undefined);
|
|
21450
|
-
const app = new
|
|
21769
|
+
const app = new Elysia36({
|
|
21451
21770
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
21452
21771
|
}).get(texmlPath, async ({ query, request }) => {
|
|
21453
21772
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -21557,8 +21876,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
21557
21876
|
};
|
|
21558
21877
|
|
|
21559
21878
|
// src/telephony/matrix.ts
|
|
21560
|
-
import { Elysia as
|
|
21561
|
-
var
|
|
21879
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
21880
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21562
21881
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
21563
21882
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
21564
21883
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -21619,13 +21938,13 @@ var badgeStyles = {
|
|
|
21619
21938
|
};
|
|
21620
21939
|
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
21940
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
21622
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
21941
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml36(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
21623
21942
|
<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
21943
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
21625
21944
|
${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
21945
|
<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]}">${
|
|
21946
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml36(entry.name)}</h2>
|
|
21947
|
+
<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
21948
|
</div>
|
|
21630
21949
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
21631
21950
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -21633,15 +21952,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
21633
21952
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
21634
21953
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
21635
21954
|
</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>${
|
|
21955
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml36(entry.setup.urls.stream || "missing")}</code></p>
|
|
21956
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml36(entry.setup.urls.webhook || "missing")}</code></p>
|
|
21957
|
+
${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
21958
|
</article>`).join("")}
|
|
21640
21959
|
</section>
|
|
21641
21960
|
</main>`;
|
|
21642
21961
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
21643
21962
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
21644
|
-
return new
|
|
21963
|
+
return new Elysia37({
|
|
21645
21964
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
21646
21965
|
}).get(path, async ({ query, request }) => {
|
|
21647
21966
|
const providers = await options.load({ query, request });
|
|
@@ -21663,7 +21982,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
21663
21982
|
};
|
|
21664
21983
|
|
|
21665
21984
|
// src/phoneAgentProductionSmoke.ts
|
|
21666
|
-
import { Elysia as
|
|
21985
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
21667
21986
|
var defaultRequirements = [
|
|
21668
21987
|
"media-started",
|
|
21669
21988
|
"transcript",
|
|
@@ -21671,7 +21990,7 @@ var defaultRequirements = [
|
|
|
21671
21990
|
"lifecycle-outcome",
|
|
21672
21991
|
"no-session-error"
|
|
21673
21992
|
];
|
|
21674
|
-
var
|
|
21993
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
21675
21994
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
21676
21995
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
21677
21996
|
const value = event.payload[key];
|
|
@@ -21780,10 +22099,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
21780
22099
|
});
|
|
21781
22100
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
21782
22101
|
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>${
|
|
22102
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml37(issue.requirement)}</strong>: ${escapeHtml37(issue.message)}</li>`).join("");
|
|
22103
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml37(outcome)}</span>`).join("");
|
|
22104
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml37(requirement)}</span>`).join("");
|
|
22105
|
+
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
22106
|
};
|
|
21788
22107
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
21789
22108
|
query,
|
|
@@ -21806,7 +22125,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
21806
22125
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
21807
22126
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
21808
22127
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
21809
|
-
const routes = new
|
|
22128
|
+
const routes = new Elysia38({
|
|
21810
22129
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
21811
22130
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
21812
22131
|
if (htmlPath) {
|
|
@@ -21849,7 +22168,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
21849
22168
|
"completed",
|
|
21850
22169
|
"failed"
|
|
21851
22170
|
];
|
|
21852
|
-
var
|
|
22171
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21853
22172
|
var loadRouteJson = async (input) => {
|
|
21854
22173
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
21855
22174
|
headers: {
|
|
@@ -22087,10 +22406,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
22087
22406
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
22088
22407
|
const urls = entry?.setup.urls;
|
|
22089
22408
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
22090
|
-
return `<tr><td>${
|
|
22409
|
+
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
22410
|
}).join("");
|
|
22092
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
22093
|
-
const snippet =
|
|
22411
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml38(stage)}</code></li>`).join("");
|
|
22412
|
+
const snippet = escapeHtml38(`const phoneAgent = createVoicePhoneAgent({
|
|
22094
22413
|
carriers: [
|
|
22095
22414
|
{
|
|
22096
22415
|
provider: 'twilio',
|
|
@@ -22124,11 +22443,11 @@ app.use(
|
|
|
22124
22443
|
);`);
|
|
22125
22444
|
const checklist = report.carriers.map((carrier) => {
|
|
22126
22445
|
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>${
|
|
22446
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml38(issue)}</li>`).join("") ?? "";
|
|
22447
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml38(step)}</li>`).join("") ?? "";
|
|
22448
|
+
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
22449
|
}).join("");
|
|
22131
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
22450
|
+
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
22451
|
};
|
|
22133
22452
|
var createVoicePhoneAgent = (options) => {
|
|
22134
22453
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -22137,7 +22456,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
22137
22456
|
setupPath: resolveSetupPath(carrier),
|
|
22138
22457
|
smokePath: resolveSmokePath(carrier)
|
|
22139
22458
|
}));
|
|
22140
|
-
const app = new
|
|
22459
|
+
const app = new Elysia39({
|
|
22141
22460
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
22142
22461
|
});
|
|
22143
22462
|
for (const carrier of options.carriers) {
|
|
@@ -24271,8 +24590,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24271
24590
|
};
|
|
24272
24591
|
};
|
|
24273
24592
|
// src/providerCapabilities.ts
|
|
24274
|
-
import { Elysia as
|
|
24275
|
-
var
|
|
24593
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
24594
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24276
24595
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
24277
24596
|
configured: true,
|
|
24278
24597
|
features: options.features?.[provider],
|
|
@@ -24335,27 +24654,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
24335
24654
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
24336
24655
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
24337
24656
|
const cards = report.capabilities.map((capability) => {
|
|
24338
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
24339
|
-
return `<article class="card ${
|
|
24657
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml39(feature)}</span>`).join("");
|
|
24658
|
+
return `<article class="card ${escapeHtml39(capability.status)}">
|
|
24340
24659
|
<div class="card-header">
|
|
24341
24660
|
<div>
|
|
24342
|
-
<p class="eyebrow">${
|
|
24343
|
-
<h2>${
|
|
24661
|
+
<p class="eyebrow">${escapeHtml39(capability.kind)}</p>
|
|
24662
|
+
<h2>${escapeHtml39(capability.label ?? capability.provider)}</h2>
|
|
24344
24663
|
</div>
|
|
24345
|
-
<strong>${
|
|
24664
|
+
<strong>${escapeHtml39(capability.status)}</strong>
|
|
24346
24665
|
</div>
|
|
24347
|
-
${capability.description ? `<p>${
|
|
24666
|
+
${capability.description ? `<p>${escapeHtml39(capability.description)}</p>` : ""}
|
|
24348
24667
|
<dl>
|
|
24349
24668
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
24350
24669
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
24351
|
-
<div><dt>Model</dt><dd>${
|
|
24670
|
+
<div><dt>Model</dt><dd>${escapeHtml39(capability.model ?? "default")}</dd></div>
|
|
24352
24671
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
24353
24672
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
24354
24673
|
</dl>
|
|
24355
24674
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
24356
24675
|
</article>`;
|
|
24357
24676
|
}).join("");
|
|
24358
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24677
|
+
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
24678
|
};
|
|
24360
24679
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
24361
24680
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -24372,7 +24691,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
24372
24691
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
24373
24692
|
const path = options.path ?? "/api/provider-capabilities";
|
|
24374
24693
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
24375
|
-
const routes = new
|
|
24694
|
+
const routes = new Elysia40({
|
|
24376
24695
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
24377
24696
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
24378
24697
|
if (htmlPath) {
|
|
@@ -24381,7 +24700,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
24381
24700
|
return routes;
|
|
24382
24701
|
};
|
|
24383
24702
|
// src/providerOrchestration.ts
|
|
24384
|
-
import { Elysia as
|
|
24703
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
24385
24704
|
var defaultRequirement = {
|
|
24386
24705
|
minProviders: 1,
|
|
24387
24706
|
requireBudgetPolicy: false,
|
|
@@ -24394,7 +24713,7 @@ var statusRank2 = {
|
|
|
24394
24713
|
warn: 1,
|
|
24395
24714
|
fail: 2
|
|
24396
24715
|
};
|
|
24397
|
-
var
|
|
24716
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24398
24717
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24399
24718
|
var uniqueSorted6 = (values) => [
|
|
24400
24719
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -24537,27 +24856,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
24537
24856
|
};
|
|
24538
24857
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
24539
24858
|
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">${
|
|
24859
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml40(surface.status)}">
|
|
24860
|
+
<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
24861
|
<dl>
|
|
24543
|
-
<div><dt>Providers</dt><dd>${
|
|
24544
|
-
<div><dt>Fallback</dt><dd>${
|
|
24862
|
+
<div><dt>Providers</dt><dd>${escapeHtml40(surface.providers.join(", ") || "none")}</dd></div>
|
|
24863
|
+
<div><dt>Fallback</dt><dd>${escapeHtml40(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
24545
24864
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
24546
24865
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
24547
24866
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
24548
24867
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
24549
24868
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
24550
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
24869
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml40(surface.fallbackMode || "default")}</dd></div>
|
|
24551
24870
|
</dl>
|
|
24552
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
24871
|
+
${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
24872
|
</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>${
|
|
24873
|
+
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
24874
|
};
|
|
24556
24875
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
24557
24876
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
24558
24877
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
24559
24878
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
24560
|
-
const routes = new
|
|
24879
|
+
const routes = new Elysia41({
|
|
24561
24880
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
24562
24881
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
24563
24882
|
if (htmlPath) {
|
|
@@ -24728,7 +25047,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
24728
25047
|
return report;
|
|
24729
25048
|
};
|
|
24730
25049
|
// src/providerSlo.ts
|
|
24731
|
-
import { Elysia as
|
|
25050
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
24732
25051
|
var defaultThresholds = {
|
|
24733
25052
|
llm: {
|
|
24734
25053
|
maxAverageElapsedMs: 2500,
|
|
@@ -24761,7 +25080,7 @@ var statusRank3 = {
|
|
|
24761
25080
|
warn: 1,
|
|
24762
25081
|
fail: 2
|
|
24763
25082
|
};
|
|
24764
|
-
var
|
|
25083
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24765
25084
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
24766
25085
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
24767
25086
|
var uniqueSorted7 = (values) => [
|
|
@@ -25057,11 +25376,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25057
25376
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25058
25377
|
const kindCards = providerKinds.map((kind) => {
|
|
25059
25378
|
const kindReport = report.kinds[kind];
|
|
25060
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
25379
|
+
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
25380
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25062
|
-
return `<article class="${
|
|
25381
|
+
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
25382
|
}).join("");
|
|
25064
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
25383
|
+
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
25384
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25066
25385
|
store: runtimeStorage.traces,
|
|
25067
25386
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25071,7 +25390,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25071
25390
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25072
25391
|
}
|
|
25073
25392
|
})`;
|
|
25074
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25393
|
+
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
25394
|
};
|
|
25076
25395
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25077
25396
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25082,7 +25401,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25082
25401
|
...options.headers ?? {}
|
|
25083
25402
|
};
|
|
25084
25403
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25085
|
-
const app = new
|
|
25404
|
+
const app = new Elysia42({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25086
25405
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25087
25406
|
if (markdownPath !== false) {
|
|
25088
25407
|
app.get(markdownPath, async () => {
|
|
@@ -25112,10 +25431,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25112
25431
|
return app;
|
|
25113
25432
|
};
|
|
25114
25433
|
// src/productionReadiness.ts
|
|
25115
|
-
import { Elysia as
|
|
25434
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
25116
25435
|
|
|
25117
25436
|
// src/telephony/security.ts
|
|
25118
|
-
import { Elysia as
|
|
25437
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
25119
25438
|
|
|
25120
25439
|
// src/postgresStore.ts
|
|
25121
25440
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -25853,7 +26172,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
25853
26172
|
};
|
|
25854
26173
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
25855
26174
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
25856
|
-
return new
|
|
26175
|
+
return new Elysia43({
|
|
25857
26176
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
25858
26177
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
25859
26178
|
};
|
|
@@ -25910,8 +26229,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
25910
26229
|
};
|
|
25911
26230
|
|
|
25912
26231
|
// src/opsRecovery.ts
|
|
25913
|
-
import { Elysia as
|
|
25914
|
-
var
|
|
26232
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
26233
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25915
26234
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
25916
26235
|
var hrefForSession = (value, sessionId) => {
|
|
25917
26236
|
if (typeof value === "function") {
|
|
@@ -26125,19 +26444,19 @@ ${failedSessions || "None."}
|
|
|
26125
26444
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26126
26445
|
`;
|
|
26127
26446
|
};
|
|
26128
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
26447
|
+
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
26448
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26130
26449
|
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>${
|
|
26450
|
+
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("");
|
|
26451
|
+
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("");
|
|
26452
|
+
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("");
|
|
26453
|
+
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
26454
|
};
|
|
26136
26455
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26137
26456
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26138
26457
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26139
26458
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26140
|
-
const routes = new
|
|
26459
|
+
const routes = new Elysia44({
|
|
26141
26460
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26142
26461
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26143
26462
|
if (htmlPath) {
|
|
@@ -26167,18 +26486,18 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26167
26486
|
};
|
|
26168
26487
|
|
|
26169
26488
|
// src/observabilityExport.ts
|
|
26170
|
-
import { Elysia as
|
|
26489
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
26171
26490
|
import { Database as Database4 } from "bun:sqlite";
|
|
26172
26491
|
import { createHash } from "crypto";
|
|
26173
26492
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26174
26493
|
import { join as join3 } from "path";
|
|
26175
26494
|
|
|
26176
26495
|
// src/operationsRecord.ts
|
|
26177
|
-
import { Elysia as
|
|
26496
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26178
26497
|
|
|
26179
26498
|
// src/traceTimeline.ts
|
|
26180
|
-
import { Elysia as
|
|
26181
|
-
var
|
|
26499
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
26500
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26182
26501
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26183
26502
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26184
26503
|
var firstString3 = (payload, keys) => {
|
|
@@ -26361,17 +26680,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
26361
26680
|
};
|
|
26362
26681
|
};
|
|
26363
26682
|
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>${
|
|
26683
|
+
var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${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
26684
|
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>${
|
|
26685
|
+
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("");
|
|
26686
|
+
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>";
|
|
26687
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml43(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
26688
|
+
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
26689
|
};
|
|
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="${
|
|
26690
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${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
26691
|
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
26692
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
26374
|
-
const snippet =
|
|
26693
|
+
const snippet = escapeHtml43(`const traceStore = createVoiceTraceSinkStore({
|
|
26375
26694
|
store: runtimeStorage.traces,
|
|
26376
26695
|
sinks: [
|
|
26377
26696
|
createVoiceTraceHTTPSink({
|
|
@@ -26397,13 +26716,13 @@ app.use(
|
|
|
26397
26716
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
26398
26717
|
})
|
|
26399
26718
|
);`);
|
|
26400
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26719
|
+
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
26720
|
};
|
|
26402
26721
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
26403
26722
|
const path = options.path ?? "/api/voice-traces";
|
|
26404
26723
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
26405
26724
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
26406
|
-
const routes = new
|
|
26725
|
+
const routes = new Elysia45({
|
|
26407
26726
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
26408
26727
|
});
|
|
26409
26728
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -26832,7 +27151,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
26832
27151
|
}
|
|
26833
27152
|
return report;
|
|
26834
27153
|
};
|
|
26835
|
-
var
|
|
27154
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26836
27155
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26837
27156
|
var outcomeLabels = (outcome) => [
|
|
26838
27157
|
outcome.complete ? "complete" : undefined,
|
|
@@ -26912,20 +27231,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
26912
27231
|
`);
|
|
26913
27232
|
};
|
|
26914
27233
|
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>${
|
|
27234
|
+
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>';
|
|
27235
|
+
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>";
|
|
27236
|
+
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
27237
|
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>${
|
|
27238
|
+
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>";
|
|
27239
|
+
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>";
|
|
27240
|
+
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>";
|
|
27241
|
+
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>";
|
|
27242
|
+
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
27243
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
26925
27244
|
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 ${
|
|
27245
|
+
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
27246
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
26928
|
-
const snippet =
|
|
27247
|
+
const snippet = escapeHtml44(`app.use(
|
|
26929
27248
|
createVoiceOperationsRecordRoutes({
|
|
26930
27249
|
audit: auditStore,
|
|
26931
27250
|
integrationEvents: opsEvents,
|
|
@@ -26939,16 +27258,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
26939
27258
|
tasks: opsTasks
|
|
26940
27259
|
})
|
|
26941
27260
|
);`);
|
|
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>${
|
|
27261
|
+
const incidentMarkdown = escapeHtml44(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
27262
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml44(options.incidentHref)}">Download incident.md</a>` : "";
|
|
27263
|
+
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
27264
|
};
|
|
26946
27265
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
26947
27266
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
26948
27267
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
26949
27268
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
26950
27269
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
26951
|
-
const routes = new
|
|
27270
|
+
const routes = new Elysia46({
|
|
26952
27271
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
26953
27272
|
});
|
|
26954
27273
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -27599,7 +27918,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
27599
27918
|
...options.headers ?? {}
|
|
27600
27919
|
};
|
|
27601
27920
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
27602
|
-
const app = new
|
|
27921
|
+
const app = new Elysia47({
|
|
27603
27922
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
27604
27923
|
});
|
|
27605
27924
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28408,7 +28727,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28408
28727
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
28409
28728
|
}
|
|
28410
28729
|
});
|
|
28411
|
-
const app = new
|
|
28730
|
+
const app = new Elysia47({
|
|
28412
28731
|
name: options.name ?? "absolute-voice-observability-export"
|
|
28413
28732
|
});
|
|
28414
28733
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28485,7 +28804,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28485
28804
|
};
|
|
28486
28805
|
|
|
28487
28806
|
// src/productionReadiness.ts
|
|
28488
|
-
var
|
|
28807
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28489
28808
|
var rollupStatus3 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
28490
28809
|
var readinessGateCodes = {
|
|
28491
28810
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -29940,25 +30259,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
29940
30259
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
29941
30260
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
29942
30261
|
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>${
|
|
30262
|
+
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>` : "";
|
|
30263
|
+
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
30264
|
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 ${
|
|
30265
|
+
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("");
|
|
30266
|
+
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>` : "";
|
|
30267
|
+
return `<article class="check ${escapeHtml45(check.status)}">
|
|
29949
30268
|
<div>
|
|
29950
|
-
<span>${
|
|
29951
|
-
<h2>${
|
|
29952
|
-
${check.detail ? `<p>${
|
|
30269
|
+
<span>${escapeHtml45(check.status.toUpperCase())}</span>
|
|
30270
|
+
<h2>${escapeHtml45(check.label)}</h2>
|
|
30271
|
+
${check.detail ? `<p>${escapeHtml45(check.detail)}</p>` : ""}
|
|
29953
30272
|
${explanation}
|
|
29954
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
30273
|
+
${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
30274
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
29956
30275
|
</div>
|
|
29957
|
-
<strong>${
|
|
29958
|
-
${check.href ? `<a href="${
|
|
30276
|
+
<strong>${escapeHtml45(String(check.value ?? check.status))}</strong>
|
|
30277
|
+
${check.href ? `<a href="${escapeHtml45(check.href)}">Open surface</a>` : ""}
|
|
29959
30278
|
</article>`;
|
|
29960
30279
|
}).join("");
|
|
29961
|
-
const snippet =
|
|
30280
|
+
const snippet = escapeHtml45(`createVoiceProductionReadinessRoutes({
|
|
29962
30281
|
htmlPath: '/production-readiness',
|
|
29963
30282
|
path: '/api/production-readiness',
|
|
29964
30283
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -29974,13 +30293,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
29974
30293
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
29975
30294
|
store: traceStore
|
|
29976
30295
|
});`);
|
|
29977
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30296
|
+
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
30297
|
};
|
|
29979
30298
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
29980
30299
|
const path = options.path ?? "/api/production-readiness";
|
|
29981
30300
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
29982
30301
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
29983
|
-
const routes = new
|
|
30302
|
+
const routes = new Elysia48({
|
|
29984
30303
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
29985
30304
|
});
|
|
29986
30305
|
const resolveOptions = async (input) => {
|
|
@@ -30028,8 +30347,8 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30028
30347
|
return routes;
|
|
30029
30348
|
};
|
|
30030
30349
|
// src/voiceMonitoring.ts
|
|
30031
|
-
import { Elysia as
|
|
30032
|
-
var
|
|
30350
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
30351
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30033
30352
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30034
30353
|
var rollupStatus4 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30035
30354
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -30282,14 +30601,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
30282
30601
|
};
|
|
30283
30602
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
30284
30603
|
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 =
|
|
30604
|
+
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("");
|
|
30605
|
+
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("");
|
|
30606
|
+
const snippet = escapeHtml46(`app.use(createVoiceMonitorRoutes({
|
|
30288
30607
|
evidence,
|
|
30289
30608
|
issueStore,
|
|
30290
30609
|
monitors: [defineVoiceMonitor(...)]
|
|
30291
30610
|
}));`);
|
|
30292
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30611
|
+
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
30612
|
};
|
|
30294
30613
|
var actorFromRequest = async (request) => {
|
|
30295
30614
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -30313,7 +30632,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30313
30632
|
monitors: options.monitors,
|
|
30314
30633
|
now: options.now
|
|
30315
30634
|
});
|
|
30316
|
-
const routes = new
|
|
30635
|
+
const routes = new Elysia49({
|
|
30317
30636
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
30318
30637
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
30319
30638
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -30360,7 +30679,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30360
30679
|
};
|
|
30361
30680
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
30362
30681
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
30363
|
-
return new
|
|
30682
|
+
return new Elysia49({
|
|
30364
30683
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
30365
30684
|
}).get(path, () => ({
|
|
30366
30685
|
isRunning: options.runner.isRunning()
|
|
@@ -30736,8 +31055,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
30736
31055
|
};
|
|
30737
31056
|
};
|
|
30738
31057
|
// src/providerStackRecommendations.ts
|
|
30739
|
-
import { Elysia as
|
|
30740
|
-
var
|
|
31058
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
31059
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30741
31060
|
var profileProviderPriorities = {
|
|
30742
31061
|
"meeting-recorder": {
|
|
30743
31062
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31056,17 +31375,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31056
31375
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31057
31376
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31058
31377
|
const rows = report.rows.map((row) => {
|
|
31059
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31060
|
-
return `<article class="row ${
|
|
31378
|
+
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("");
|
|
31379
|
+
return `<article class="row ${escapeHtml47(row.status)}">
|
|
31061
31380
|
<div>
|
|
31062
|
-
<p class="eyebrow">${
|
|
31063
|
-
<h2>${
|
|
31064
|
-
<p class="status ${
|
|
31381
|
+
<p class="eyebrow">${escapeHtml47(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
31382
|
+
<h2>${escapeHtml47(row.provider)}</h2>
|
|
31383
|
+
<p class="status ${escapeHtml47(row.status)}">${escapeHtml47(row.status.toUpperCase())}</p>
|
|
31065
31384
|
</div>
|
|
31066
31385
|
<ul>${checks}</ul>
|
|
31067
31386
|
</article>`;
|
|
31068
31387
|
}).join("");
|
|
31069
|
-
const snippet =
|
|
31388
|
+
const snippet = escapeHtml47(`const providerContracts = () =>
|
|
31070
31389
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31071
31390
|
env: process.env,
|
|
31072
31391
|
providers: {
|
|
@@ -31087,7 +31406,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31087
31406
|
providerContractMatrix: () =>
|
|
31088
31407
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31089
31408
|
});`);
|
|
31090
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31409
|
+
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
31410
|
};
|
|
31092
31411
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31093
31412
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31102,7 +31421,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31102
31421
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31103
31422
|
const path = options.path ?? "/api/provider-contracts";
|
|
31104
31423
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31105
|
-
const routes = new
|
|
31424
|
+
const routes = new Elysia50({
|
|
31106
31425
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31107
31426
|
});
|
|
31108
31427
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -31220,7 +31539,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31220
31539
|
return assertion;
|
|
31221
31540
|
};
|
|
31222
31541
|
// src/opsConsoleRoutes.ts
|
|
31223
|
-
import { Elysia as
|
|
31542
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
31224
31543
|
var DEFAULT_LINKS = [
|
|
31225
31544
|
{
|
|
31226
31545
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -31255,7 +31574,7 @@ var DEFAULT_LINKS = [
|
|
|
31255
31574
|
label: "Handoffs"
|
|
31256
31575
|
}
|
|
31257
31576
|
];
|
|
31258
|
-
var
|
|
31577
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31259
31578
|
var countProviderStatuses = (providers) => {
|
|
31260
31579
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
31261
31580
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -31324,20 +31643,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
31324
31643
|
trace
|
|
31325
31644
|
};
|
|
31326
31645
|
};
|
|
31327
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
31646
|
+
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
31647
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
31329
31648
|
const links = report.links.map((link) => `<article class="surface">
|
|
31330
|
-
<div><h2>${
|
|
31331
|
-
<p><a href="${
|
|
31649
|
+
<div><h2>${escapeHtml48(link.label)}</h2>${link.description ? `<p>${escapeHtml48(link.description)}</p>` : ""}</div>
|
|
31650
|
+
<p><a href="${escapeHtml48(link.href)}">Open ${escapeHtml48(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml48(link.statusHref)}">Status</a>` : ""}</p>
|
|
31332
31651
|
</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>${
|
|
31652
|
+
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>';
|
|
31653
|
+
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
31654
|
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>${
|
|
31655
|
+
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
31656
|
};
|
|
31338
31657
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
31339
31658
|
const path = options.path ?? "/ops-console";
|
|
31340
|
-
const routes = new
|
|
31659
|
+
const routes = new Elysia51({
|
|
31341
31660
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
31342
31661
|
});
|
|
31343
31662
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -31354,7 +31673,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
31354
31673
|
return routes;
|
|
31355
31674
|
};
|
|
31356
31675
|
// src/incidentBundle.ts
|
|
31357
|
-
import { Elysia as
|
|
31676
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
31358
31677
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
31359
31678
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
31360
31679
|
return false;
|
|
@@ -31555,7 +31874,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
31555
31874
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
31556
31875
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
31557
31876
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
31558
|
-
const routes = new
|
|
31877
|
+
const routes = new Elysia52({
|
|
31559
31878
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
31560
31879
|
});
|
|
31561
31880
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -31756,19 +32075,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
31756
32075
|
};
|
|
31757
32076
|
};
|
|
31758
32077
|
// src/opsStatusRoutes.ts
|
|
31759
|
-
import { Elysia as
|
|
31760
|
-
var
|
|
32078
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
32079
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31761
32080
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
31762
32081
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
31763
32082
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
31764
32083
|
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 ${
|
|
32084
|
+
return `<article class="surface ${escapeHtml49(surface.status)}"><span>${escapeHtml49(surface.status.toUpperCase())}</span><h2>${escapeHtml49(key)}</h2><strong>${escapeHtml49(value)}</strong></article>`;
|
|
31766
32085
|
}).join("");
|
|
31767
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32086
|
+
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
32087
|
};
|
|
31769
32088
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
31770
32089
|
const path = options.path ?? "/api/voice/ops-status";
|
|
31771
|
-
const routes = new
|
|
32090
|
+
const routes = new Elysia53({
|
|
31772
32091
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
31773
32092
|
});
|
|
31774
32093
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -32201,8 +32520,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
32201
32520
|
};
|
|
32202
32521
|
};
|
|
32203
32522
|
// src/traceDeliveryRoutes.ts
|
|
32204
|
-
import { Elysia as
|
|
32205
|
-
var
|
|
32523
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
32524
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32206
32525
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
32207
32526
|
var getNumber12 = (value) => {
|
|
32208
32527
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -32283,14 +32602,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
32283
32602
|
if (entries.length === 0) {
|
|
32284
32603
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
32285
32604
|
}
|
|
32286
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
32605
|
+
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
32606
|
};
|
|
32288
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
32607
|
+
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
32608
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
32290
32609
|
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>${
|
|
32610
|
+
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>`;
|
|
32611
|
+
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("");
|
|
32612
|
+
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
32613
|
};
|
|
32295
32614
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
32296
32615
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32310,7 +32629,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
32310
32629
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
32311
32630
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
32312
32631
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
32313
|
-
const routes = new
|
|
32632
|
+
const routes = new Elysia54({
|
|
32314
32633
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
32315
32634
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
32316
32635
|
if (htmlPath !== false) {
|
|
@@ -32407,7 +32726,7 @@ var createVoiceMemoryStore = () => {
|
|
|
32407
32726
|
return { get, getOrCreate, list, remove, set };
|
|
32408
32727
|
};
|
|
32409
32728
|
// src/opsWebhook.ts
|
|
32410
|
-
import { Elysia as
|
|
32729
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32411
32730
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
32412
32731
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
32413
32732
|
const encoder = new TextEncoder;
|
|
@@ -32537,7 +32856,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
32537
32856
|
};
|
|
32538
32857
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
32539
32858
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
32540
|
-
return new
|
|
32859
|
+
return new Elysia55().post(path, async ({ body, request, set }) => {
|
|
32541
32860
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
32542
32861
|
if (options.signingSecret) {
|
|
32543
32862
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -32992,7 +33311,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
32992
33311
|
};
|
|
32993
33312
|
};
|
|
32994
33313
|
// src/postCallAnalysis.ts
|
|
32995
|
-
import { Elysia as
|
|
33314
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32996
33315
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
32997
33316
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
32998
33317
|
var getPathValue3 = (source, path) => {
|
|
@@ -33171,7 +33490,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
33171
33490
|
};
|
|
33172
33491
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
33173
33492
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
33174
|
-
const routes = new
|
|
33493
|
+
const routes = new Elysia56({
|
|
33175
33494
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
33176
33495
|
});
|
|
33177
33496
|
routes.get(path, async ({ query }) => {
|
|
@@ -33196,7 +33515,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
33196
33515
|
return routes;
|
|
33197
33516
|
};
|
|
33198
33517
|
// src/guardrails.ts
|
|
33199
|
-
import { Elysia as
|
|
33518
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
33200
33519
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
33201
33520
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
33202
33521
|
var matchesRule = async (rule, input) => {
|
|
@@ -33498,7 +33817,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
33498
33817
|
};
|
|
33499
33818
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
33500
33819
|
const path = options.path ?? "/api/voice/guardrails";
|
|
33501
|
-
const routes = new
|
|
33820
|
+
const routes = new Elysia57({
|
|
33502
33821
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
33503
33822
|
});
|
|
33504
33823
|
routes.all(path, async ({ request }) => {
|
|
@@ -34022,6 +34341,8 @@ export {
|
|
|
34022
34341
|
renderVoiceScenarioEvalHTML,
|
|
34023
34342
|
renderVoiceResilienceHTML,
|
|
34024
34343
|
renderVoiceReconnectContractHTML,
|
|
34344
|
+
renderVoiceRealtimeChannelMarkdown,
|
|
34345
|
+
renderVoiceRealtimeChannelHTML,
|
|
34025
34346
|
renderVoiceQualityHTML,
|
|
34026
34347
|
renderVoiceProviderSloMarkdown,
|
|
34027
34348
|
renderVoiceProviderSloHTML,
|
|
@@ -34117,6 +34438,7 @@ export {
|
|
|
34117
34438
|
evaluateVoiceTelephonyWebhookNormalizationEvidence,
|
|
34118
34439
|
evaluateVoiceTelephonyContract,
|
|
34119
34440
|
evaluateVoiceSimulationSuiteEvidence,
|
|
34441
|
+
evaluateVoiceRealtimeChannelEvidence,
|
|
34120
34442
|
evaluateVoiceQuality,
|
|
34121
34443
|
evaluateVoiceProviderStackGaps,
|
|
34122
34444
|
evaluateVoiceProviderStackEvidence,
|
|
@@ -34246,6 +34568,7 @@ export {
|
|
|
34246
34568
|
createVoiceRedisPlivoWebhookNonceStore,
|
|
34247
34569
|
createVoiceRedisIdempotencyStore,
|
|
34248
34570
|
createVoiceReconnectContractRoutes,
|
|
34571
|
+
createVoiceRealtimeChannelRoutes,
|
|
34249
34572
|
createVoiceReadinessProfile,
|
|
34250
34573
|
createVoiceQualityRoutes,
|
|
34251
34574
|
createVoiceProviderSloRoutes,
|
|
@@ -34449,6 +34772,8 @@ export {
|
|
|
34449
34772
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
34450
34773
|
buildVoiceSloReadinessThresholdReport,
|
|
34451
34774
|
buildVoiceSloCalibrationReport,
|
|
34775
|
+
buildVoiceRealtimeChannelRuntimeSamplesFromTrace,
|
|
34776
|
+
buildVoiceRealtimeChannelReport,
|
|
34452
34777
|
buildVoiceProviderSloReport,
|
|
34453
34778
|
buildVoiceProviderOrchestrationReport,
|
|
34454
34779
|
buildVoiceProviderDecisionTraceReport,
|
|
@@ -34492,6 +34817,7 @@ export {
|
|
|
34492
34817
|
assertVoiceTelephonyWebhookNormalizationEvidence,
|
|
34493
34818
|
assertVoiceSloCalibration,
|
|
34494
34819
|
assertVoiceSimulationSuiteEvidence,
|
|
34820
|
+
assertVoiceRealtimeChannelEvidence,
|
|
34495
34821
|
assertVoiceProviderStackEvidence,
|
|
34496
34822
|
assertVoiceProviderSloEvidence,
|
|
34497
34823
|
assertVoiceProviderRoutingContractEvidence,
|