@absolutejs/voice 0.0.22-beta.527 → 0.0.22-beta.529
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/angular/index.js +3 -1
- package/dist/client/htmxBootstrap.js +3 -1
- package/dist/client/index.js +290 -304
- package/dist/embed/index.js +3 -1
- package/dist/embed/voice-widget.js +7 -7
- package/dist/index.d.ts +4 -6
- package/dist/index.js +525 -905
- package/dist/internal/html.d.ts +6 -0
- package/dist/internal/status.d.ts +9 -0
- package/dist/react/index.js +287 -300
- package/dist/svelte/index.js +181 -198
- package/dist/testing/index.js +69 -69
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/index.js +231 -239
- package/package.json +2 -3
- package/dist/generated/htmxBootstrapBundle.d.ts +0 -1
- package/fixtures/README.md +0 -57
- package/fixtures/manifest.json +0 -358
- package/fixtures/pcm/dialogue-three-clean.pcm +0 -0
- package/fixtures/pcm/dialogue-three-mixed.pcm +0 -0
- package/fixtures/pcm/dialogue-two-clean.pcm +0 -0
- package/fixtures/pcm/dialogue-two-noisy.pcm +0 -0
- package/fixtures/pcm/multiturn-three-mixed.pcm +0 -0
- package/fixtures/pcm/multiturn-two-clean.pcm +0 -0
- package/fixtures/pcm/quietly-alone-clean.pcm +0 -0
- package/fixtures/pcm/rainstorms-noisy.pcm +0 -0
- package/fixtures/pcm/stella-bulgaria-bulgarian20.pcm +0 -0
- package/fixtures/pcm/stella-ghana-english507.pcm +0 -0
- package/fixtures/pcm/stella-india-english37.pcm +0 -0
- package/fixtures/pcm/stella-jamaica-jamaican-creole-english1.pcm +0 -0
- package/fixtures/pcm/stella-liberia-liberian-pidgin-english2.pcm +0 -0
- package/fixtures/pcm/stella-pakistan-english519.pcm +0 -0
- package/fixtures/pcm/stella-sierra-leone-krio5.pcm +0 -0
- package/fixtures/pcm/stella-singapore-english655.pcm +0 -0
- package/fixtures/pcm/traveled-back-route-clean.pcm +0 -0
package/dist/testing/index.js
CHANGED
|
@@ -3557,22 +3557,27 @@ var DEFAULT_AUDIO_FORMAT = {
|
|
|
3557
3557
|
};
|
|
3558
3558
|
var DEFAULT_TELEPHONY_SAMPLE_RATE_HZ = 8000;
|
|
3559
3559
|
var DEFAULT_MULTI_SPEAKER_SILENCE_MS = 350;
|
|
3560
|
-
var FIXTURE_DIR_CANDIDATES = [
|
|
3561
|
-
resolve(import.meta.dir, "..", "..", "fixtures"),
|
|
3562
|
-
resolve(import.meta.dir, "..", "..", "..", "fixtures"),
|
|
3563
|
-
resolve(import.meta.dir, "..", "..", "..", "..", "fixtures")
|
|
3564
|
-
];
|
|
3565
3560
|
var EXTERNAL_FIXTURE_ENV_KEYS = [
|
|
3566
3561
|
"VOICE_FIXTURE_DIR",
|
|
3567
3562
|
"VOICE_FIXTURE_DIRS"
|
|
3568
3563
|
];
|
|
3564
|
+
var resolveDefaultFixtureCandidates = () => {
|
|
3565
|
+
const envDirs = EXTERNAL_FIXTURE_ENV_KEYS.flatMap((key) => (process.env[key] ?? "").split(/[\n,]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0));
|
|
3566
|
+
return [
|
|
3567
|
+
...envDirs.map((dir) => resolve(dir)),
|
|
3568
|
+
resolve(process.cwd(), "fixtures"),
|
|
3569
|
+
resolve(process.cwd(), "test", "fixtures", "audio"),
|
|
3570
|
+
resolve(import.meta.dir, "..", "..", "test", "fixtures", "audio"),
|
|
3571
|
+
resolve(import.meta.dir, "..", "..", "..", "test", "fixtures", "audio")
|
|
3572
|
+
];
|
|
3573
|
+
};
|
|
3569
3574
|
var resolveFixtureDirectory = async () => {
|
|
3570
|
-
for (const candidate of
|
|
3575
|
+
for (const candidate of resolveDefaultFixtureCandidates()) {
|
|
3571
3576
|
if (await Bun.file(resolve(candidate, "manifest.json")).exists()) {
|
|
3572
3577
|
return candidate;
|
|
3573
3578
|
}
|
|
3574
3579
|
}
|
|
3575
|
-
throw new Error("Unable to locate
|
|
3580
|
+
throw new Error("Unable to locate voice test fixtures. Set VOICE_FIXTURE_DIR/VOICE_FIXTURE_DIRS, or provide a fixtures/ directory (with manifest.json) in the working directory.");
|
|
3576
3581
|
};
|
|
3577
3582
|
var getVoiceFixtureDirectory = async () => resolveFixtureDirectory();
|
|
3578
3583
|
var toUniqueDirectories = (directories) => directories.filter((directory, index, list) => directory.trim().length > 0 && list.indexOf(directory) === index);
|
|
@@ -7862,6 +7867,9 @@ var runVoiceResilienceBenchmark = async () => {
|
|
|
7862
7867
|
}
|
|
7863
7868
|
};
|
|
7864
7869
|
};
|
|
7870
|
+
// src/internal/html.ts
|
|
7871
|
+
var escapeHtml = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
7872
|
+
|
|
7865
7873
|
// src/testing/review.ts
|
|
7866
7874
|
var roundMetric4 = (value) => typeof value === "number" ? Math.round(value * 100) / 100 : undefined;
|
|
7867
7875
|
var formatMetric = (label, value, unit = "ms") => typeof value === "number" ? `${label}: ${roundMetric4(value)}${unit}` : undefined;
|
|
@@ -8307,7 +8315,6 @@ var renderVoiceCallReviewMarkdown = (artifact) => {
|
|
|
8307
8315
|
].filter((value) => typeof value === "string").join(`
|
|
8308
8316
|
`);
|
|
8309
8317
|
};
|
|
8310
|
-
var escapeHtml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
8311
8318
|
var renderVoiceCallReviewHTML = (artifact) => {
|
|
8312
8319
|
const notes = artifact.notes.map((note) => `<li>${escapeHtml(note)}</li>`).join("");
|
|
8313
8320
|
const latency = artifact.latencyBreakdown.map((entry) => `<li><strong>${escapeHtml(entry.label)}:</strong> ${roundMetric4(entry.valueMs)}ms</li>`).join("");
|
|
@@ -9511,7 +9518,6 @@ var exportVoiceTrace = async (input) => {
|
|
|
9511
9518
|
};
|
|
9512
9519
|
};
|
|
9513
9520
|
var toNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
9514
|
-
var escapeHtml2 = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
9515
9521
|
var formatTraceValue = (value) => {
|
|
9516
9522
|
if (value === undefined || value === null) {
|
|
9517
9523
|
return "";
|
|
@@ -9795,10 +9801,10 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9795
9801
|
const offset = summary.startedAt === undefined ? event.at : Math.max(0, event.at - summary.startedAt);
|
|
9796
9802
|
return [
|
|
9797
9803
|
"<tr>",
|
|
9798
|
-
`<td>${
|
|
9799
|
-
`<td>${
|
|
9800
|
-
`<td>${
|
|
9801
|
-
`<td><code>${
|
|
9804
|
+
`<td>${escapeHtml(String(offset))}</td>`,
|
|
9805
|
+
`<td>${escapeHtml(event.type)}</td>`,
|
|
9806
|
+
`<td>${escapeHtml(event.turnId ?? "")}</td>`,
|
|
9807
|
+
`<td><code>${escapeHtml(JSON.stringify(event.payload))}</code></td>`,
|
|
9802
9808
|
"</tr>"
|
|
9803
9809
|
].join("");
|
|
9804
9810
|
}).join(`
|
|
@@ -9809,7 +9815,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9809
9815
|
"<head>",
|
|
9810
9816
|
'<meta charset="utf-8" />',
|
|
9811
9817
|
'<meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
9812
|
-
`<title>${
|
|
9818
|
+
`<title>${escapeHtml(options.title ?? "Voice Trace")}</title>`,
|
|
9813
9819
|
"<style>",
|
|
9814
9820
|
"body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}",
|
|
9815
9821
|
"main{max-width:1100px;margin:auto}",
|
|
@@ -9823,7 +9829,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9823
9829
|
"</style>",
|
|
9824
9830
|
"</head>",
|
|
9825
9831
|
"<body><main>",
|
|
9826
|
-
`<h1>${
|
|
9832
|
+
`<h1>${escapeHtml(options.title ?? `Voice Trace ${summary.sessionId ?? ""}`.trim())}</h1>`,
|
|
9827
9833
|
`<p class="${evaluation.pass ? "pass" : "fail"}">QA: ${evaluation.pass ? "pass" : "fail"}</p>`,
|
|
9828
9834
|
'<section class="summary">',
|
|
9829
9835
|
`<div class="card"><strong>Events</strong><br>${summary.eventCount}</div>`,
|
|
@@ -9837,7 +9843,7 @@ var renderVoiceTraceHTML = (events, options = {}) => {
|
|
|
9837
9843
|
eventRows,
|
|
9838
9844
|
"</tbody></table>",
|
|
9839
9845
|
"<h2>Markdown Export</h2>",
|
|
9840
|
-
`<pre>${
|
|
9846
|
+
`<pre>${escapeHtml(markdown)}</pre>`,
|
|
9841
9847
|
"</main></body></html>"
|
|
9842
9848
|
].join(`
|
|
9843
9849
|
`);
|
|
@@ -9851,7 +9857,6 @@ var buildVoiceTraceReplay = (events, options = {}) => ({
|
|
|
9851
9857
|
|
|
9852
9858
|
// src/auditRoutes.ts
|
|
9853
9859
|
import { Elysia } from "elysia";
|
|
9854
|
-
var escapeHtml3 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
9855
9860
|
var getString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
9856
9861
|
var getNumber = (value) => {
|
|
9857
9862
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -9949,14 +9954,14 @@ var buildVoiceAuditTrailReport = async (options) => {
|
|
|
9949
9954
|
};
|
|
9950
9955
|
var renderVoiceAuditTrailHTML = (report, options = {}) => {
|
|
9951
9956
|
const title = options.title ?? "AbsoluteJS Voice Audit Trail";
|
|
9952
|
-
const chips = report.summary.byType.map(([type, count]) => `<span>${
|
|
9957
|
+
const chips = report.summary.byType.map(([type, count]) => `<span>${escapeHtml(type)} <strong>${count}</strong></span>`).join("");
|
|
9953
9958
|
const rows = report.events.map((event) => {
|
|
9954
9959
|
const actor = event.actor ? `${event.actor.kind}:${event.actor.id}` : "unknown";
|
|
9955
9960
|
const resource = event.resource ? `${event.resource.type}${event.resource.id ? `:${event.resource.id}` : ""}` : "";
|
|
9956
9961
|
const payload = event.payload ? JSON.stringify(event.payload, null, 2) : "";
|
|
9957
|
-
return `<article class="event ${
|
|
9962
|
+
return `<article class="event ${escapeHtml(event.outcome ?? "unknown")}"><div><span>${escapeHtml(event.type)}</span><h2>${escapeHtml(event.action)}</h2><p>${escapeHtml(new Date(event.at).toLocaleString())}</p><p>Actor: ${escapeHtml(actor)}${resource ? ` \xB7 Resource: ${escapeHtml(resource)}` : ""}</p>${event.sessionId ? `<p>Session: ${escapeHtml(event.sessionId)}</p>` : ""}</div><strong>${escapeHtml(event.outcome ?? "recorded")}</strong>${payload ? `<pre>${escapeHtml(payload)}</pre>` : ""}</article>`;
|
|
9958
9963
|
}).join("");
|
|
9959
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
9964
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{background:#11140f;color:#f7f1df;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,.18),rgba(245,158,11,.12));border:1px solid #2c3327;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#facc15;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}.chips{display:flex;flex-wrap:wrap;gap:10px}.chips span{border:1px solid #46513b;border-radius:999px;padding:8px 12px}.events{display:grid;gap:14px}.event{background:#181d15;border:1px solid #2c3327;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto;padding:18px}.event.error{border-color:rgba(239,68,68,.75)}.event.skipped{border-color:rgba(245,158,11,.7)}.event.success{border-color:rgba(34,197,94,.55)}.event span{color:#facc15;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.event h2{margin:.2rem 0}.event p{color:#c8ccb8;margin:.2rem 0}.event strong{text-transform:uppercase}pre{background:#0c0f0a;border-radius:14px;grid-column:1/-1;overflow:auto;padding:14px;white-space:pre-wrap}@media(max-width:760px){main{padding:20px}.event{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted evidence</p><h1>${escapeHtml(title)}</h1><p>${report.summary.total} event(s), ${report.summary.errors} error(s). Latest ${report.summary.latestAt ? escapeHtml(new Date(report.summary.latestAt).toLocaleString()) : "never"}.</p><div class="chips">${chips}</div></section><section class="events">${rows || "<p>No audit events match this filter.</p>"}</section></main></body></html>`;
|
|
9960
9965
|
};
|
|
9961
9966
|
var createVoiceAuditTrailRoutes = (options) => {
|
|
9962
9967
|
const path = options.path ?? "/api/voice-audit";
|
|
@@ -10048,7 +10053,6 @@ var createVoiceAuditTrailRoutes = (options) => {
|
|
|
10048
10053
|
};
|
|
10049
10054
|
|
|
10050
10055
|
// src/auditExport.ts
|
|
10051
|
-
var escapeHtml4 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10052
10056
|
var normalizeRedactionKey2 = (key) => key.trim().toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
10053
10057
|
var resolveReplacement2 = (input) => typeof input.options.replacement === "function" ? input.options.replacement({
|
|
10054
10058
|
key: input.key,
|
|
@@ -10166,8 +10170,8 @@ var renderVoiceAuditHTML = (events, options = {}) => {
|
|
|
10166
10170
|
const markdown = renderVoiceAuditMarkdown(events, options);
|
|
10167
10171
|
const renderEvents = options.redact ? redactVoiceAuditEvents(events, options.redact) : events;
|
|
10168
10172
|
const summary = summarizeVoiceAuditTrail(renderEvents);
|
|
10169
|
-
const rows = renderEvents.map((event) => `<tr><td>${
|
|
10170
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10173
|
+
const rows = renderEvents.map((event) => `<tr><td>${escapeHtml(new Date(event.at).toISOString())}</td><td>${escapeHtml(event.type)}</td><td>${escapeHtml(event.action)}</td><td>${escapeHtml(event.outcome ?? "")}</td><td><code>${escapeHtml(JSON.stringify(event.payload ?? {}))}</code></td></tr>`).join("");
|
|
10174
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;line-height:1.45;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;margin:1rem 0}.card{background:white;border:1px solid #ded9cc;border-radius:12px;padding:1rem}table{border-collapse:collapse;width:100%;background:white;border:1px solid #ded9cc}th,td{border-bottom:1px solid #eee8dc;padding:.65rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}pre{background:#181713;color:#f8f7f2;padding:1rem;border-radius:12px;overflow:auto}</style></head><body><main><h1>${escapeHtml(title)}</h1><section class="summary"><div class="card"><strong>Events</strong><br>${summary.total}</div><div class="card"><strong>Errors</strong><br>${summary.errors}</div><div class="card"><strong>Latest</strong><br>${summary.latestAt ? escapeHtml(new Date(summary.latestAt).toLocaleString()) : "never"}</div></section><table><thead><tr><th>At</th><th>Type</th><th>Action</th><th>Outcome</th><th>Payload</th></tr></thead><tbody>${rows}</tbody></table><h2>Markdown Export</h2><pre>${escapeHtml(markdown)}</pre></main></body></html>`;
|
|
10171
10175
|
};
|
|
10172
10176
|
var buildVoiceAuditExport = (events, options = {}) => {
|
|
10173
10177
|
const exportEvents = options.redact ? redactVoiceAuditEvents(events, options.redact) : events;
|
|
@@ -10182,7 +10186,6 @@ var buildVoiceAuditExport = (events, options = {}) => {
|
|
|
10182
10186
|
// src/sessionReplay.ts
|
|
10183
10187
|
import { Elysia as Elysia2 } from "elysia";
|
|
10184
10188
|
var getString2 = (value) => typeof value === "string" ? value : undefined;
|
|
10185
|
-
var escapeHtml5 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10186
10189
|
var increment2 = (record, key) => {
|
|
10187
10190
|
record[key] = (record[key] ?? 0) + 1;
|
|
10188
10191
|
};
|
|
@@ -10379,10 +10382,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
10379
10382
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
10380
10383
|
'<div class="voice-sessions-list">',
|
|
10381
10384
|
...sessions.map((session) => [
|
|
10382
|
-
`<article class="voice-session-card ${
|
|
10385
|
+
`<article class="voice-session-card ${escapeHtml(session.status)}">`,
|
|
10383
10386
|
'<div class="voice-session-card-header">',
|
|
10384
|
-
`<strong>${
|
|
10385
|
-
`<span>${
|
|
10387
|
+
`<strong>${escapeHtml(session.sessionId)}</strong>`,
|
|
10388
|
+
`<span>${escapeHtml(session.status)}</span>`,
|
|
10386
10389
|
"</div>",
|
|
10387
10390
|
"<dl>",
|
|
10388
10391
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -10390,9 +10393,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
10390
10393
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
10391
10394
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
10392
10395
|
"</dl>",
|
|
10393
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
10394
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
10395
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
10396
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml(session.latestOutcome)}</p>` : "",
|
|
10397
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml).join(", ")}</p>` : "",
|
|
10398
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml(session.replayHref)}">Open replay</a></p>` : "",
|
|
10396
10399
|
"</article>"
|
|
10397
10400
|
].join("")),
|
|
10398
10401
|
"</div>"
|
|
@@ -10462,7 +10465,6 @@ var createVoiceSessionReplayRoutes = (options) => {
|
|
|
10462
10465
|
|
|
10463
10466
|
// src/traceTimeline.ts
|
|
10464
10467
|
import { Elysia as Elysia3 } from "elysia";
|
|
10465
|
-
var escapeHtml6 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
10466
10468
|
var getString3 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
10467
10469
|
var getNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
10468
10470
|
var firstString = (payload, keys) => {
|
|
@@ -10648,17 +10650,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
10648
10650
|
};
|
|
10649
10651
|
};
|
|
10650
10652
|
var formatMs = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
10651
|
-
var renderProviderCards = (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>${
|
|
10653
|
+
var renderProviderCards = (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>${escapeHtml(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs(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>`;
|
|
10652
10654
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
10653
|
-
const events = session.events.map((event) => `<tr class="${
|
|
10654
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
10655
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
10656
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10655
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml(event.type)}</td><td>${escapeHtml(event.label)}</td><td>${escapeHtml(event.provider ?? "")}</td><td>${escapeHtml(event.status ?? "")}</td><td>${formatMs(event.elapsedMs)}</td></tr>`).join("");
|
|
10656
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml(issue.severity)}">${escapeHtml(issue.code)}: ${escapeHtml(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
10657
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
10658
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(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>${escapeHtml(session.sessionId)}</h1><p class="status ${escapeHtml(session.status)}">${escapeHtml(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>${formatMs(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards(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>`;
|
|
10657
10659
|
};
|
|
10658
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
10660
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml(session.operationsRecordHref)}">${escapeHtml(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml(session.sessionId)}</a>`}</td><td>${escapeHtml(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
10659
10661
|
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}}";
|
|
10660
10662
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
10661
|
-
const snippet =
|
|
10663
|
+
const snippet = escapeHtml(`const traceStore = createVoiceTraceSinkStore({
|
|
10662
10664
|
store: runtimeStorage.traces,
|
|
10663
10665
|
sinks: [
|
|
10664
10666
|
createVoiceTraceHTTPSink({
|
|
@@ -10684,7 +10686,7 @@ app.use(
|
|
|
10684
10686
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
10685
10687
|
})
|
|
10686
10688
|
);`);
|
|
10687
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
10689
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(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>${escapeHtml(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>`;
|
|
10688
10690
|
};
|
|
10689
10691
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
10690
10692
|
const path = options.path ?? "/api/voice-traces";
|
|
@@ -11354,7 +11356,6 @@ var renderVoiceFailureReplayMarkdown = (report) => {
|
|
|
11354
11356
|
].join(`
|
|
11355
11357
|
`);
|
|
11356
11358
|
};
|
|
11357
|
-
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
11358
11359
|
var formatMs2 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
11359
11360
|
var outcomeLabels = (outcome) => [
|
|
11360
11361
|
outcome.complete ? "complete" : undefined,
|
|
@@ -11480,18 +11481,18 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
11480
11481
|
`);
|
|
11481
11482
|
};
|
|
11482
11483
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
11483
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
11484
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
11485
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
11484
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs2(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
11485
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
11486
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml(decision.status ?? decision.type)}</span> ${formatMs2(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
11486
11487
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
11487
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
11488
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
11489
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
11490
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
11491
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
11488
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml(handoff.status ?? "")}</span><p>${escapeHtml(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
11489
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml(tool.toolName ?? "tool")}</strong> <span>${escapeHtml(tool.status ?? "")}</span> ${formatMs2(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
11490
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml(review.title)}</strong> <span>${escapeHtml(review.summary.outcome ?? "")}</span><p>${escapeHtml(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
11491
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml(task.title)}</strong> <span>${escapeHtml(task.status)}</span><p>${escapeHtml(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
11492
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml(event.type)}</strong> <span>${escapeHtml(event.deliveryStatus ?? "local")}</span><p>${escapeHtml(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
11492
11493
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
11493
11494
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
11494
|
-
return `<li><strong>assistant.guardrail ${
|
|
11495
|
+
return `<li><strong>assistant.guardrail ${escapeHtml(decision.stage ?? "unknown")}</strong> <span>${escapeHtml(decision.status ?? "")}</span><p>Allowed: ${escapeHtml(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml(decision.turnId)}` : ""}</p><p>${escapeHtml(findings)}</p></li>`;
|
|
11495
11496
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
11496
11497
|
const telephonyMedia = record.telephonyMedia.events.length ? record.telephonyMedia.events.slice(0, 50).map((event) => {
|
|
11497
11498
|
const details = [
|
|
@@ -11502,12 +11503,12 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
11502
11503
|
event.sequenceNumber ? `Seq: ${event.sequenceNumber}` : undefined,
|
|
11503
11504
|
`Audio bytes: ${String(event.audioBytes)}`
|
|
11504
11505
|
].filter((detail) => typeof detail === "string");
|
|
11505
|
-
return `<li><strong>${
|
|
11506
|
+
return `<li><strong>${escapeHtml(event.event)}</strong> <span>${escapeHtml(new Date(event.at).toLocaleString())}</span><p>${escapeHtml(details.join(" \xB7 "))}</p></li>`;
|
|
11506
11507
|
}).join("") : "<li>No telephony media trace events recorded.</li>";
|
|
11507
|
-
const mediaPipelineSection = record.mediaPipeline ? `<section id="media-pipeline"><h2>Media Pipeline</h2><p class="muted">Surface: ${
|
|
11508
|
-
const mediaPipelineCard = record.mediaPipeline ? `<div class="card"><span>Media pipeline</span><strong>${
|
|
11508
|
+
const mediaPipelineSection = record.mediaPipeline ? `<section id="media-pipeline"><h2>Media Pipeline</h2><p class="muted">Surface: ${escapeHtml(record.mediaPipeline.surface)} \xB7 Status: ${escapeHtml(record.mediaPipeline.status)} \xB7 Quality: ${escapeHtml(record.mediaPipeline.qualityStatus)} \xB7 Transport: ${escapeHtml(record.mediaPipeline.transportStatus ?? "n/a")} \xB7 Graph: ${escapeHtml(record.mediaPipeline.processorGraphStatus ?? "n/a")} \xB7 Frames: ${String(record.mediaPipeline.frames)} \xB7 Jitter: ${record.mediaPipeline.jitterMs === undefined ? "n/a" : `${String(record.mediaPipeline.jitterMs)}ms`}</p><ul>${record.mediaPipeline.issueCodes.length ? record.mediaPipeline.issueCodes.map((code) => `<li><strong>${escapeHtml(code)}</strong></li>`).join("") : "<li>No media pipeline issue codes.</li>"}</ul></section>` : "";
|
|
11509
|
+
const mediaPipelineCard = record.mediaPipeline ? `<div class="card"><span>Media pipeline</span><strong>${escapeHtml(record.mediaPipeline.status)}</strong><span>${String(record.mediaPipeline.issueCodes.length)} issue code(s)</span></div>` : "";
|
|
11509
11510
|
const mediaPipelineNavLink = record.mediaPipeline ? '<a href="#media-pipeline">Media pipeline</a>' : "";
|
|
11510
|
-
const snippet =
|
|
11511
|
+
const snippet = escapeHtml(`app.use(
|
|
11511
11512
|
createVoiceOperationsRecordRoutes({
|
|
11512
11513
|
audit: auditStore,
|
|
11513
11514
|
integrationEvents: opsEvents,
|
|
@@ -11521,9 +11522,9 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
11521
11522
|
tasks: opsTasks
|
|
11522
11523
|
})
|
|
11523
11524
|
);`);
|
|
11524
|
-
const incidentMarkdown =
|
|
11525
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
11526
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
11525
|
+
const incidentMarkdown = escapeHtml(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
11526
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml(options.incidentHref)}">Download incident.md</a>` : "";
|
|
11527
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml(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>${escapeHtml(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml(record.status)}">${escapeHtml(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#telephony-media">Telephony media</a>${mediaPipelineNavLink}<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>${formatMs2(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Telephony media</span><strong>${String(record.telephonyMedia.media)}</strong><span>${String(record.telephonyMedia.inbound)} inbound / ${String(record.telephonyMedia.outbound)} outbound / ${String(record.telephonyMedia.clears)} clears</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>${mediaPipelineCard}</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="telephony-media"><h2>Telephony Media</h2><p class="muted">Live <code>client.telephony_media</code> stream lifecycle evidence attached to this session. Carriers: ${escapeHtml(record.telephonyMedia.carriers.join(", ") || "none")}. Streams: ${escapeHtml(record.telephonyMedia.streamIds.join(", ") || "none")}. Inbound: ${String(record.telephonyMedia.inbound)}. Outbound: ${String(record.telephonyMedia.outbound)}. Marks: ${String(record.telephonyMedia.marks)}. Clears: ${String(record.telephonyMedia.clears)}.</p><ul>${telephonyMedia}</ul></section>${mediaPipelineSection}<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, media streams, 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>`;
|
|
11527
11528
|
};
|
|
11528
11529
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
11529
11530
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -12414,7 +12415,6 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
12414
12415
|
return parameters;
|
|
12415
12416
|
};
|
|
12416
12417
|
var joinUrlPath = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
12417
|
-
var escapeHtml8 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
12418
12418
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
12419
12419
|
if (!webhook?.verificationUrl) {
|
|
12420
12420
|
return;
|
|
@@ -12459,23 +12459,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
12459
12459
|
};
|
|
12460
12460
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
12461
12461
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
12462
|
-
<h1>${
|
|
12462
|
+
<h1>${escapeHtml(title)}</h1>
|
|
12463
12463
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
12464
12464
|
<section>
|
|
12465
12465
|
<h2>URLs</h2>
|
|
12466
12466
|
<ul>
|
|
12467
|
-
<li><strong>TwiML:</strong> <code>${
|
|
12468
|
-
<li><strong>Media stream:</strong> <code>${
|
|
12469
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
12467
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml(status.urls.twiml)}</code></li>
|
|
12468
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml(status.urls.stream)}</code></li>
|
|
12469
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml(status.urls.webhook)}</code></li>
|
|
12470
12470
|
</ul>
|
|
12471
12471
|
</section>
|
|
12472
12472
|
<section>
|
|
12473
12473
|
<h2>Signing</h2>
|
|
12474
12474
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
12475
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
12475
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml(status.signing.verificationUrl)}</code></p>` : ""}
|
|
12476
12476
|
</section>
|
|
12477
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
12478
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
12477
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
12478
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
12479
12479
|
</main>`;
|
|
12480
12480
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
12481
12481
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -12486,20 +12486,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
12486
12486
|
});
|
|
12487
12487
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
12488
12488
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
12489
|
-
<h1>${
|
|
12489
|
+
<h1>${escapeHtml(title)}</h1>
|
|
12490
12490
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
12491
12491
|
<section>
|
|
12492
12492
|
<h2>Checks</h2>
|
|
12493
12493
|
<ul>
|
|
12494
|
-
${report.checks.map((check) => `<li><strong>${
|
|
12494
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml(check.name)}</strong>: ${escapeHtml(check.status)}${check.message ? ` - ${escapeHtml(check.message)}` : ""}</li>`).join("")}
|
|
12495
12495
|
</ul>
|
|
12496
12496
|
</section>
|
|
12497
12497
|
<section>
|
|
12498
12498
|
<h2>Observed URLs</h2>
|
|
12499
12499
|
<ul>
|
|
12500
|
-
<li><strong>TwiML:</strong> <code>${
|
|
12501
|
-
<li><strong>Stream:</strong> <code>${
|
|
12502
|
-
<li><strong>Webhook:</strong> <code>${
|
|
12500
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml(report.setup.urls.twiml)}</code></li>
|
|
12501
|
+
<li><strong>Stream:</strong> <code>${escapeHtml(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
12502
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml(report.setup.urls.webhook)}</code></li>
|
|
12503
12503
|
</ul>
|
|
12504
12504
|
</section>
|
|
12505
12505
|
</main>`;
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export { VoiceCostDashboard } from "./VoiceCostDashboard";
|
|
|
37
37
|
export { VoiceLiveAgentConsole } from "./VoiceLiveAgentConsole";
|
|
38
38
|
export { VoiceLiveCallViewer } from "./VoiceLiveCallViewer";
|
|
39
39
|
export { VoiceReplayTimeline } from "./VoiceReplayTimeline";
|
|
40
|
-
export type { VoiceWidgetLabels, VoiceWidgetTheme
|
|
40
|
+
export type { VoiceWidgetLabels, VoiceWidgetTheme } from "./VoiceWidget";
|
|
41
41
|
export { useVoiceProviderStatus } from "./useVoiceProviderStatus";
|
|
42
42
|
export { useVoiceProviderCapabilities } from "./useVoiceProviderCapabilities";
|
|
43
43
|
export { useVoiceProviderContracts } from "./useVoiceProviderContracts";
|