@absolutejs/voice 0.0.22-beta.151 → 0.0.22-beta.153

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.
@@ -2062,6 +2062,142 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
2062
2062
  }
2063
2063
  };
2064
2064
  };
2065
+ // src/client/deliveryRuntime.ts
2066
+ var getDefaultActionPath = (path, action, options) => {
2067
+ if (action === "tick") {
2068
+ return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
2069
+ }
2070
+ return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
2071
+ };
2072
+ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
2073
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2074
+ const response = await fetchImpl(path);
2075
+ if (!response.ok) {
2076
+ throw new Error(`Voice delivery runtime failed: HTTP ${response.status}`);
2077
+ }
2078
+ return await response.json();
2079
+ };
2080
+ var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
2081
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2082
+ const response = await fetchImpl(getDefaultActionPath(path, action, options), {
2083
+ method: "POST"
2084
+ });
2085
+ if (!response.ok) {
2086
+ throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
2087
+ }
2088
+ const body = await response.json();
2089
+ return {
2090
+ action,
2091
+ result: body.result,
2092
+ summary: body.summary,
2093
+ updatedAt: Date.now()
2094
+ };
2095
+ };
2096
+ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
2097
+ const listeners = new Set;
2098
+ let closed = false;
2099
+ let timer;
2100
+ let snapshot = {
2101
+ actionError: null,
2102
+ actionStatus: "idle",
2103
+ error: null,
2104
+ isLoading: false
2105
+ };
2106
+ const emit = () => {
2107
+ for (const listener of listeners) {
2108
+ listener();
2109
+ }
2110
+ };
2111
+ const refresh = async () => {
2112
+ if (closed) {
2113
+ return snapshot.report;
2114
+ }
2115
+ snapshot = {
2116
+ ...snapshot,
2117
+ error: null,
2118
+ isLoading: true
2119
+ };
2120
+ emit();
2121
+ try {
2122
+ const report = await fetchVoiceDeliveryRuntime(path, options);
2123
+ snapshot = {
2124
+ ...snapshot,
2125
+ error: null,
2126
+ isLoading: false,
2127
+ report,
2128
+ updatedAt: Date.now()
2129
+ };
2130
+ emit();
2131
+ return report;
2132
+ } catch (error) {
2133
+ snapshot = {
2134
+ ...snapshot,
2135
+ error: error instanceof Error ? error.message : String(error),
2136
+ isLoading: false
2137
+ };
2138
+ emit();
2139
+ throw error;
2140
+ }
2141
+ };
2142
+ const runAction = async (action) => {
2143
+ if (closed) {
2144
+ return snapshot.lastAction;
2145
+ }
2146
+ snapshot = {
2147
+ ...snapshot,
2148
+ actionError: null,
2149
+ actionStatus: "running"
2150
+ };
2151
+ emit();
2152
+ try {
2153
+ const result = await runVoiceDeliveryRuntimeAction(action, path, options);
2154
+ snapshot = {
2155
+ ...snapshot,
2156
+ actionError: null,
2157
+ actionStatus: "completed",
2158
+ lastAction: result
2159
+ };
2160
+ emit();
2161
+ await refresh();
2162
+ return result;
2163
+ } catch (error) {
2164
+ snapshot = {
2165
+ ...snapshot,
2166
+ actionError: error instanceof Error ? error.message : String(error),
2167
+ actionStatus: "failed"
2168
+ };
2169
+ emit();
2170
+ throw error;
2171
+ }
2172
+ };
2173
+ const close = () => {
2174
+ closed = true;
2175
+ if (timer) {
2176
+ clearInterval(timer);
2177
+ timer = undefined;
2178
+ }
2179
+ listeners.clear();
2180
+ };
2181
+ if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
2182
+ timer = setInterval(() => {
2183
+ refresh().catch(() => {});
2184
+ }, options.intervalMs);
2185
+ }
2186
+ return {
2187
+ close,
2188
+ getServerSnapshot: () => snapshot,
2189
+ getSnapshot: () => snapshot,
2190
+ requeueDeadLetters: () => runAction("requeue-dead-letters"),
2191
+ refresh,
2192
+ tick: () => runAction("tick"),
2193
+ subscribe: (listener) => {
2194
+ listeners.add(listener);
2195
+ return () => {
2196
+ listeners.delete(listener);
2197
+ };
2198
+ }
2199
+ };
2200
+ };
2065
2201
  // src/client/opsStatusWidget.ts
2066
2202
  var DEFAULT_TITLE = "Voice Ops Status";
2067
2203
  var DEFAULT_DESCRIPTION = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
@@ -2186,6 +2322,133 @@ var defineVoiceOpsStatusElement = (tagName = "absolute-voice-ops-status") => {
2186
2322
  }
2187
2323
  });
2188
2324
  };
2325
+ // src/client/deliveryRuntimeWidget.ts
2326
+ var DEFAULT_TITLE2 = "Voice Delivery Runtime";
2327
+ var DEFAULT_DESCRIPTION2 = "Audit and trace delivery worker health from your AbsoluteJS voice app.";
2328
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2329
+ var createSurface = (id, summary) => {
2330
+ if (!summary) {
2331
+ return {
2332
+ deadLettered: 0,
2333
+ detail: "Worker disabled",
2334
+ failed: 0,
2335
+ id,
2336
+ label: id === "audit" ? "Audit delivery" : "Trace delivery",
2337
+ pending: 0,
2338
+ status: "disabled",
2339
+ total: 0
2340
+ };
2341
+ }
2342
+ const blocked = summary.failed + summary.deadLettered;
2343
+ return {
2344
+ deadLettered: summary.deadLettered,
2345
+ detail: `${summary.delivered}/${summary.total} delivered, ${summary.pending} pending`,
2346
+ failed: summary.failed,
2347
+ id,
2348
+ label: id === "audit" ? "Audit delivery" : "Trace delivery",
2349
+ pending: summary.pending,
2350
+ status: blocked > 0 ? "warn" : "pass",
2351
+ total: summary.total
2352
+ };
2353
+ };
2354
+ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
2355
+ const report = snapshot.report;
2356
+ const surfaces = [
2357
+ createSurface("audit", report?.summary.audit),
2358
+ createSurface("trace", report?.summary.trace)
2359
+ ];
2360
+ const hasWarnings = surfaces.some((surface) => surface.status === "warn");
2361
+ return {
2362
+ description: options.description ?? DEFAULT_DESCRIPTION2,
2363
+ error: snapshot.error,
2364
+ actionError: snapshot.actionError,
2365
+ actionStatus: snapshot.actionStatus,
2366
+ isLoading: snapshot.isLoading,
2367
+ isRunning: Boolean(report?.isRunning),
2368
+ label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
2369
+ status: snapshot.error ? "error" : report ? hasWarnings ? "warn" : "pass" : "loading",
2370
+ surfaces,
2371
+ title: options.title ?? DEFAULT_TITLE2,
2372
+ updatedAt: snapshot.updatedAt
2373
+ };
2374
+ };
2375
+ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
2376
+ const model = createVoiceDeliveryRuntimeViewModel(snapshot, options);
2377
+ const surfaces = model.surfaces.map((surface) => `<li class="absolute-voice-delivery-runtime__surface absolute-voice-delivery-runtime__surface--${escapeHtml2(surface.status)}">
2378
+ <span>${escapeHtml2(surface.label)}</span>
2379
+ <strong>${escapeHtml2(surface.detail)}</strong>
2380
+ <small>${String(surface.failed)} failed &middot; ${String(surface.deadLettered)} dead-lettered</small>
2381
+ </li>`).join("");
2382
+ const actions = options.includeActions === false ? "" : `<div class="absolute-voice-delivery-runtime__actions">
2383
+ <button type="button" data-absolute-voice-delivery-runtime-action="tick">${model.actionStatus === "running" ? "Working..." : "Tick workers"}</button>
2384
+ <button type="button" data-absolute-voice-delivery-runtime-action="requeue-dead-letters"${model.surfaces.some((surface) => surface.deadLettered > 0) ? "" : " disabled"}>Requeue dead letters</button>
2385
+ </div>`;
2386
+ const actionError = model.actionError ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml2(model.actionError)}</p>` : "";
2387
+ return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml2(model.status)}">
2388
+ <header class="absolute-voice-delivery-runtime__header">
2389
+ <span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml2(model.title)}</span>
2390
+ <strong class="absolute-voice-delivery-runtime__label">${escapeHtml2(model.label)}</strong>
2391
+ </header>
2392
+ <p class="absolute-voice-delivery-runtime__description">${escapeHtml2(model.description)}</p>
2393
+ <ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
2394
+ ${actions}
2395
+ ${actionError}
2396
+ ${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml2(model.error)}</p>` : ""}
2397
+ </section>`;
2398
+ };
2399
+ var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-delivery-runtime__actions button{background:#134e2d;border:0;border-radius:999px;color:#f6fff9;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-delivery-runtime__actions button:disabled{cursor:not-allowed;opacity:.48}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
2400
+ var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
2401
+ const store = createVoiceDeliveryRuntimeStore(path, options);
2402
+ const render = () => {
2403
+ element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
2404
+ };
2405
+ const unsubscribe = store.subscribe(render);
2406
+ const handleClick = (event) => {
2407
+ const target = event.target;
2408
+ if (!(target instanceof Element)) {
2409
+ return;
2410
+ }
2411
+ const action = target.closest("[data-absolute-voice-delivery-runtime-action]");
2412
+ const actionName = action?.getAttribute("data-absolute-voice-delivery-runtime-action");
2413
+ if (actionName === "tick") {
2414
+ store.tick().catch(() => {});
2415
+ }
2416
+ if (actionName === "requeue-dead-letters") {
2417
+ store.requeueDeadLetters().catch(() => {});
2418
+ }
2419
+ };
2420
+ element.addEventListener?.("click", handleClick);
2421
+ render();
2422
+ store.refresh().catch(() => {});
2423
+ return {
2424
+ close: () => {
2425
+ element.removeEventListener?.("click", handleClick);
2426
+ unsubscribe();
2427
+ store.close();
2428
+ },
2429
+ refresh: store.refresh
2430
+ };
2431
+ };
2432
+ var defineVoiceDeliveryRuntimeElement = (tagName = "absolute-voice-delivery-runtime") => {
2433
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
2434
+ return;
2435
+ }
2436
+ customElements.define(tagName, class AbsoluteVoiceDeliveryRuntimeElement extends HTMLElement {
2437
+ mounted;
2438
+ connectedCallback() {
2439
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
2440
+ this.mounted = mountVoiceDeliveryRuntime(this, this.getAttribute("path") ?? "/api/voice-delivery-runtime", {
2441
+ description: this.getAttribute("description") ?? undefined,
2442
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
2443
+ title: this.getAttribute("title") ?? undefined
2444
+ });
2445
+ }
2446
+ disconnectedCallback() {
2447
+ this.mounted?.close();
2448
+ this.mounted = undefined;
2449
+ }
2450
+ });
2451
+ };
2189
2452
  // src/client/routingStatus.ts
2190
2453
  var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
2191
2454
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -2266,9 +2529,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
2266
2529
  };
2267
2530
  };
2268
2531
  // src/client/routingStatusWidget.ts
2269
- var DEFAULT_TITLE2 = "Voice Routing";
2270
- var DEFAULT_DESCRIPTION2 = "Latest provider routing decision from the self-hosted trace store.";
2271
- var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2532
+ var DEFAULT_TITLE3 = "Voice Routing";
2533
+ var DEFAULT_DESCRIPTION3 = "Latest provider routing decision from the self-hosted trace store.";
2534
+ var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2272
2535
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
2273
2536
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2274
2537
  const decision = snapshot.decision;
@@ -2292,30 +2555,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2292
2555
  ] : [];
2293
2556
  return {
2294
2557
  decision,
2295
- description: options.description ?? DEFAULT_DESCRIPTION2,
2558
+ description: options.description ?? DEFAULT_DESCRIPTION3,
2296
2559
  error: snapshot.error,
2297
2560
  isLoading: snapshot.isLoading,
2298
2561
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
2299
2562
  rows,
2300
2563
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
2301
- title: options.title ?? DEFAULT_TITLE2,
2564
+ title: options.title ?? DEFAULT_TITLE3,
2302
2565
  updatedAt: snapshot.updatedAt
2303
2566
  };
2304
2567
  };
2305
2568
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
2306
2569
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
2307
2570
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
2308
- <span>${escapeHtml2(row.label)}</span>
2309
- <strong>${escapeHtml2(row.value)}</strong>
2571
+ <span>${escapeHtml3(row.label)}</span>
2572
+ <strong>${escapeHtml3(row.value)}</strong>
2310
2573
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
2311
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml2(model.status)}">
2574
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml3(model.status)}">
2312
2575
  <header class="absolute-voice-routing-status__header">
2313
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml2(model.title)}</span>
2314
- <strong class="absolute-voice-routing-status__label">${escapeHtml2(model.label)}</strong>
2576
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml3(model.title)}</span>
2577
+ <strong class="absolute-voice-routing-status__label">${escapeHtml3(model.label)}</strong>
2315
2578
  </header>
2316
- <p class="absolute-voice-routing-status__description">${escapeHtml2(model.description)}</p>
2579
+ <p class="absolute-voice-routing-status__description">${escapeHtml3(model.description)}</p>
2317
2580
  ${rows}
2318
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml2(model.error)}</p>` : ""}
2581
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml3(model.error)}</p>` : ""}
2319
2582
  </section>`;
2320
2583
  };
2321
2584
  var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
@@ -2967,7 +3230,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
2967
3230
  };
2968
3231
  };
2969
3232
  // src/client/providerSimulationControlsWidget.ts
2970
- var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3233
+ var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2971
3234
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
2972
3235
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
2973
3236
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -2987,18 +3250,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
2987
3250
  };
2988
3251
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
2989
3252
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
2990
- const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml3(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml3(provider.provider)} ${escapeHtml3(formatKind(options.kind))} failure</button>`).join("");
2991
- const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml3(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml3(provider.provider)} recovered</button>`).join("");
3253
+ const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml4(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml4(provider.provider)} ${escapeHtml4(formatKind(options.kind))} failure</button>`).join("");
3254
+ const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml4(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml4(provider.provider)} recovered</button>`).join("");
2992
3255
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
2993
3256
  <header class="absolute-voice-provider-simulation__header">
2994
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
2995
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
3257
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml4(model.title)}</span>
3258
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml4(model.label)}</strong>
2996
3259
  </header>
2997
- <p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
2998
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
3260
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml4(model.description)}</p>
3261
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml4(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
2999
3262
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
3000
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
3001
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
3263
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml4(snapshot.error)}</p>` : ""}
3264
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml4(model.resultText)}</pre>` : ""}
3002
3265
  </section>`;
3003
3266
  };
3004
3267
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -3063,9 +3326,9 @@ var defineVoiceProviderSimulationControlsElement = (tagName = "absolute-voice-pr
3063
3326
  });
3064
3327
  };
3065
3328
  // src/client/providerStatusWidget.ts
3066
- var DEFAULT_TITLE3 = "Voice Providers";
3067
- var DEFAULT_DESCRIPTION3 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
3068
- var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3329
+ var DEFAULT_TITLE4 = "Voice Providers";
3330
+ var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
3331
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3069
3332
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
3070
3333
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
3071
3334
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -3109,37 +3372,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
3109
3372
  const warningCount = providers.filter((provider) => isWarningStatus(provider.status)).length;
3110
3373
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
3111
3374
  return {
3112
- description: options.description ?? DEFAULT_DESCRIPTION3,
3375
+ description: options.description ?? DEFAULT_DESCRIPTION4,
3113
3376
  error: snapshot.error,
3114
3377
  isLoading: snapshot.isLoading,
3115
3378
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
3116
3379
  providers,
3117
3380
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
3118
- title: options.title ?? DEFAULT_TITLE3,
3381
+ title: options.title ?? DEFAULT_TITLE4,
3119
3382
  updatedAt: snapshot.updatedAt
3120
3383
  };
3121
3384
  };
3122
3385
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
3123
3386
  const model = createVoiceProviderStatusViewModel(snapshot, options);
3124
- const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml4(provider.status)}">
3387
+ const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml5(provider.status)}">
3125
3388
  <header>
3126
- <strong>${escapeHtml4(provider.label)}</strong>
3127
- <span>${escapeHtml4(formatStatus(provider.status))}</span>
3389
+ <strong>${escapeHtml5(provider.label)}</strong>
3390
+ <span>${escapeHtml5(formatStatus(provider.status))}</span>
3128
3391
  </header>
3129
- <p>${escapeHtml4(provider.detail)}</p>
3392
+ <p>${escapeHtml5(provider.detail)}</p>
3130
3393
  <dl>${provider.rows.map((row) => `<div>
3131
- <dt>${escapeHtml4(row.label)}</dt>
3132
- <dd>${escapeHtml4(row.value)}</dd>
3394
+ <dt>${escapeHtml5(row.label)}</dt>
3395
+ <dd>${escapeHtml5(row.value)}</dd>
3133
3396
  </div>`).join("")}</dl>
3134
3397
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
3135
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml4(model.status)}">
3398
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
3136
3399
  <header class="absolute-voice-provider-status__header">
3137
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml4(model.title)}</span>
3138
- <strong class="absolute-voice-provider-status__label">${escapeHtml4(model.label)}</strong>
3400
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
3401
+ <strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
3139
3402
  </header>
3140
- <p class="absolute-voice-provider-status__description">${escapeHtml4(model.description)}</p>
3403
+ <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
3141
3404
  ${providers}
3142
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml4(model.error)}</p>` : ""}
3405
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
3143
3406
  </section>`;
3144
3407
  };
3145
3408
  var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
@@ -3180,9 +3443,9 @@ var defineVoiceProviderStatusElement = (tagName = "absolute-voice-provider-statu
3180
3443
  });
3181
3444
  };
3182
3445
  // src/client/providerCapabilitiesWidget.ts
3183
- var DEFAULT_TITLE4 = "Provider Capabilities";
3184
- var DEFAULT_DESCRIPTION4 = "Configured, selected, and healthy voice providers for this deployment.";
3185
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3446
+ var DEFAULT_TITLE5 = "Provider Capabilities";
3447
+ var DEFAULT_DESCRIPTION5 = "Configured, selected, and healthy voice providers for this deployment.";
3448
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3186
3449
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
3187
3450
  var formatKind2 = (kind) => kind.toUpperCase();
3188
3451
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -3226,36 +3489,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
3226
3489
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
3227
3490
  return {
3228
3491
  capabilities,
3229
- description: options.description ?? DEFAULT_DESCRIPTION4,
3492
+ description: options.description ?? DEFAULT_DESCRIPTION5,
3230
3493
  error: snapshot.error,
3231
3494
  isLoading: snapshot.isLoading,
3232
3495
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
3233
3496
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
3234
- title: options.title ?? DEFAULT_TITLE4,
3497
+ title: options.title ?? DEFAULT_TITLE5,
3235
3498
  updatedAt: snapshot.updatedAt
3236
3499
  };
3237
3500
  };
3238
3501
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
3239
3502
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
3240
- const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml5(capability.status)}">
3503
+ const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml6(capability.status)}">
3241
3504
  <header>
3242
- <strong>${escapeHtml5(capability.label)}</strong>
3243
- <span>${escapeHtml5(formatStatus2(capability.status))}</span>
3505
+ <strong>${escapeHtml6(capability.label)}</strong>
3506
+ <span>${escapeHtml6(formatStatus2(capability.status))}</span>
3244
3507
  </header>
3245
- <p>${escapeHtml5(capability.detail)}</p>
3508
+ <p>${escapeHtml6(capability.detail)}</p>
3246
3509
  <dl>${capability.rows.map((row) => `<div>
3247
- <dt>${escapeHtml5(row.label)}</dt>
3248
- <dd>${escapeHtml5(row.value)}</dd>
3510
+ <dt>${escapeHtml6(row.label)}</dt>
3511
+ <dd>${escapeHtml6(row.value)}</dd>
3249
3512
  </div>`).join("")}</dl>
3250
3513
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
3251
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml5(model.status)}">
3514
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml6(model.status)}">
3252
3515
  <header class="absolute-voice-provider-capabilities__header">
3253
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml5(model.title)}</span>
3254
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml5(model.label)}</strong>
3516
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml6(model.title)}</span>
3517
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml6(model.label)}</strong>
3255
3518
  </header>
3256
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml5(model.description)}</p>
3519
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml6(model.description)}</p>
3257
3520
  ${capabilities}
3258
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml5(model.error)}</p>` : ""}
3521
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml6(model.error)}</p>` : ""}
3259
3522
  </section>`;
3260
3523
  };
3261
3524
  var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
@@ -3296,9 +3559,9 @@ var defineVoiceProviderCapabilitiesElement = (tagName = "absolute-voice-provider
3296
3559
  });
3297
3560
  };
3298
3561
  // src/client/turnQualityWidget.ts
3299
- var DEFAULT_TITLE5 = "Turn Quality";
3300
- var DEFAULT_DESCRIPTION5 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
3301
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3562
+ var DEFAULT_TITLE6 = "Turn Quality";
3563
+ var DEFAULT_DESCRIPTION6 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
3564
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3302
3565
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
3303
3566
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
3304
3567
  var getTurnDetail = (turn) => {
@@ -3336,37 +3599,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
3336
3599
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
3337
3600
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
3338
3601
  return {
3339
- description: options.description ?? DEFAULT_DESCRIPTION5,
3602
+ description: options.description ?? DEFAULT_DESCRIPTION6,
3340
3603
  error: snapshot.error,
3341
3604
  isLoading: snapshot.isLoading,
3342
3605
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
3343
3606
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
3344
- title: options.title ?? DEFAULT_TITLE5,
3607
+ title: options.title ?? DEFAULT_TITLE6,
3345
3608
  turns,
3346
3609
  updatedAt: snapshot.updatedAt
3347
3610
  };
3348
3611
  };
3349
3612
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
3350
3613
  const model = createVoiceTurnQualityViewModel(snapshot, options);
3351
- const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml6(turn.status)}">
3614
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml7(turn.status)}">
3352
3615
  <header>
3353
- <strong>${escapeHtml6(turn.label)}</strong>
3354
- <span>${escapeHtml6(turn.status)}</span>
3616
+ <strong>${escapeHtml7(turn.label)}</strong>
3617
+ <span>${escapeHtml7(turn.status)}</span>
3355
3618
  </header>
3356
- <p>${escapeHtml6(turn.detail)}</p>
3619
+ <p>${escapeHtml7(turn.detail)}</p>
3357
3620
  <dl>${turn.rows.map((row) => `<div>
3358
- <dt>${escapeHtml6(row.label)}</dt>
3359
- <dd>${escapeHtml6(row.value)}</dd>
3621
+ <dt>${escapeHtml7(row.label)}</dt>
3622
+ <dd>${escapeHtml7(row.value)}</dd>
3360
3623
  </div>`).join("")}</dl>
3361
3624
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
3362
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml6(model.status)}">
3625
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml7(model.status)}">
3363
3626
  <header class="absolute-voice-turn-quality__header">
3364
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml6(model.title)}</span>
3365
- <strong class="absolute-voice-turn-quality__label">${escapeHtml6(model.label)}</strong>
3627
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml7(model.title)}</span>
3628
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml7(model.label)}</strong>
3366
3629
  </header>
3367
- <p class="absolute-voice-turn-quality__description">${escapeHtml6(model.description)}</p>
3630
+ <p class="absolute-voice-turn-quality__description">${escapeHtml7(model.description)}</p>
3368
3631
  ${turns}
3369
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml6(model.error)}</p>` : ""}
3632
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml7(model.error)}</p>` : ""}
3370
3633
  </section>`;
3371
3634
  };
3372
3635
  var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;
@@ -3407,10 +3670,10 @@ var defineVoiceTurnQualityElement = (tagName = "absolute-voice-turn-quality") =>
3407
3670
  });
3408
3671
  };
3409
3672
  // src/client/turnLatencyWidget.ts
3410
- var DEFAULT_TITLE6 = "Turn Latency";
3411
- var DEFAULT_DESCRIPTION6 = "Per-turn timing from first transcript to commit and assistant response start.";
3673
+ var DEFAULT_TITLE7 = "Turn Latency";
3674
+ var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
3412
3675
  var DEFAULT_PROOF_LABEL = "Run latency proof";
3413
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3676
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3414
3677
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
3415
3678
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
3416
3679
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -3424,39 +3687,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
3424
3687
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
3425
3688
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
3426
3689
  return {
3427
- description: options.description ?? DEFAULT_DESCRIPTION6,
3690
+ description: options.description ?? DEFAULT_DESCRIPTION7,
3428
3691
  error: snapshot.error,
3429
3692
  isLoading: snapshot.isLoading,
3430
3693
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
3431
3694
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
3432
3695
  showProofAction: Boolean(options.proofPath),
3433
3696
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
3434
- title: options.title ?? DEFAULT_TITLE6,
3697
+ title: options.title ?? DEFAULT_TITLE7,
3435
3698
  turns,
3436
3699
  updatedAt: snapshot.updatedAt
3437
3700
  };
3438
3701
  };
3439
3702
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
3440
3703
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
3441
- const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml7(turn.status)}">
3704
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml8(turn.status)}">
3442
3705
  <header>
3443
- <strong>${escapeHtml7(turn.label)}</strong>
3444
- <span>${escapeHtml7(turn.status)}</span>
3706
+ <strong>${escapeHtml8(turn.label)}</strong>
3707
+ <span>${escapeHtml8(turn.status)}</span>
3445
3708
  </header>
3446
3709
  <dl>${turn.rows.map((row) => `<div>
3447
- <dt>${escapeHtml7(row.label)}</dt>
3448
- <dd>${escapeHtml7(row.value)}</dd>
3710
+ <dt>${escapeHtml8(row.label)}</dt>
3711
+ <dd>${escapeHtml8(row.value)}</dd>
3449
3712
  </div>`).join("")}</dl>
3450
3713
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
3451
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml7(model.status)}">
3714
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
3452
3715
  <header class="absolute-voice-turn-latency__header">
3453
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml7(model.title)}</span>
3454
- <strong class="absolute-voice-turn-latency__label">${escapeHtml7(model.label)}</strong>
3716
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
3717
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
3455
3718
  </header>
3456
- <p class="absolute-voice-turn-latency__description">${escapeHtml7(model.description)}</p>
3457
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml7(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
3719
+ <p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
3720
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
3458
3721
  ${turns}
3459
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
3722
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
3460
3723
  </section>`;
3461
3724
  };
3462
3725
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -3506,9 +3769,9 @@ var defineVoiceTurnLatencyElement = (tagName = "absolute-voice-turn-latency") =>
3506
3769
  });
3507
3770
  };
3508
3771
  // src/client/traceTimelineWidget.ts
3509
- var DEFAULT_TITLE7 = "Voice Traces";
3510
- var DEFAULT_DESCRIPTION7 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
3511
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3772
+ var DEFAULT_TITLE8 = "Voice Traces";
3773
+ var DEFAULT_DESCRIPTION8 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
3774
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3512
3775
  var formatMs2 = (value) => typeof value === "number" ? `${value}ms` : "n/a";
3513
3776
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
3514
3777
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -3522,34 +3785,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
3522
3785
  const failed = sessions.filter((session) => session.status === "failed").length;
3523
3786
  const warnings = sessions.filter((session) => session.status === "warning").length;
3524
3787
  return {
3525
- description: options.description ?? DEFAULT_DESCRIPTION7,
3788
+ description: options.description ?? DEFAULT_DESCRIPTION8,
3526
3789
  error: snapshot.error,
3527
3790
  isLoading: snapshot.isLoading,
3528
3791
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
3529
3792
  sessions,
3530
3793
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
3531
- title: options.title ?? DEFAULT_TITLE7,
3794
+ title: options.title ?? DEFAULT_TITLE8,
3532
3795
  updatedAt: snapshot.updatedAt
3533
3796
  };
3534
3797
  };
3535
3798
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
3536
3799
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
3537
- const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml8(session.status)}">
3800
+ const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml9(session.status)}">
3538
3801
  <header>
3539
- <strong>${escapeHtml8(session.sessionId)}</strong>
3540
- <span>${escapeHtml8(session.status)}</span>
3802
+ <strong>${escapeHtml9(session.sessionId)}</strong>
3803
+ <span>${escapeHtml9(session.status)}</span>
3541
3804
  </header>
3542
- <p>${escapeHtml8(session.label)} \xB7 ${escapeHtml8(session.durationLabel)} \xB7 ${escapeHtml8(session.providerLabel)}</p>
3543
- <a href="${escapeHtml8(session.detailHref)}">Open timeline</a>
3805
+ <p>${escapeHtml9(session.label)} \xB7 ${escapeHtml9(session.durationLabel)} \xB7 ${escapeHtml9(session.providerLabel)}</p>
3806
+ <a href="${escapeHtml9(session.detailHref)}">Open timeline</a>
3544
3807
  </article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
3545
- return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml8(model.status)}">
3808
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml9(model.status)}">
3546
3809
  <header class="absolute-voice-trace-timeline__header">
3547
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml8(model.title)}</span>
3548
- <strong class="absolute-voice-trace-timeline__label">${escapeHtml8(model.label)}</strong>
3810
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml9(model.title)}</span>
3811
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml9(model.label)}</strong>
3549
3812
  </header>
3550
- <p class="absolute-voice-trace-timeline__description">${escapeHtml8(model.description)}</p>
3813
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml9(model.description)}</p>
3551
3814
  ${sessions}
3552
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml8(model.error)}</p>` : ""}
3815
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml9(model.error)}</p>` : ""}
3553
3816
  </section>`;
3554
3817
  };
3555
3818
  var getVoiceTraceTimelineCSS = () => `.absolute-voice-trace-timeline{border:1px solid #bad7d3;border-radius:20px;background:#f3fffb;color:#09201c;padding:18px;box-shadow:0 18px 40px rgba(9,32,28,.12);font-family:inherit}.absolute-voice-trace-timeline--error,.absolute-voice-trace-timeline--failed{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-trace-timeline--warning{border-color:#fbbf24;background:#fffaf0}.absolute-voice-trace-timeline__header,.absolute-voice-trace-timeline__session header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-trace-timeline__eyebrow{color:#17665b;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-trace-timeline__label{font-size:24px;line-height:1}.absolute-voice-trace-timeline__description,.absolute-voice-trace-timeline__session p,.absolute-voice-trace-timeline__empty{color:#35544f}.absolute-voice-trace-timeline__sessions{display:grid;gap:12px;margin-top:14px}.absolute-voice-trace-timeline__session{background:#fff;border:1px solid #cfe7e2;border-radius:16px;padding:14px}.absolute-voice-trace-timeline__session--failed{border-color:#f2a7a7}.absolute-voice-trace-timeline__session--warning{border-color:#fbbf24}.absolute-voice-trace-timeline__session p{margin:10px 0}.absolute-voice-trace-timeline__session a{color:#0f766e;font-weight:800}.absolute-voice-trace-timeline__empty{margin:14px 0 0}.absolute-voice-trace-timeline__error{color:#9f1239;font-weight:700}`;
@@ -3672,6 +3935,7 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
3672
3935
  };
3673
3936
  export {
3674
3937
  runVoiceTurnLatencyProof,
3938
+ runVoiceDeliveryRuntimeAction,
3675
3939
  runVoiceCampaignDialerProofAction,
3676
3940
  renderVoiceTurnQualityHTML,
3677
3941
  renderVoiceTurnLatencyHTML,
@@ -3681,6 +3945,7 @@ export {
3681
3945
  renderVoiceProviderSimulationControlsHTML,
3682
3946
  renderVoiceProviderCapabilitiesHTML,
3683
3947
  renderVoiceOpsStatusHTML,
3948
+ renderVoiceDeliveryRuntimeHTML,
3684
3949
  mountVoiceTurnQuality,
3685
3950
  mountVoiceTurnLatency,
3686
3951
  mountVoiceTraceTimeline,
@@ -3689,6 +3954,7 @@ export {
3689
3954
  mountVoiceProviderSimulationControls,
3690
3955
  mountVoiceProviderCapabilities,
3691
3956
  mountVoiceOpsStatus,
3957
+ mountVoiceDeliveryRuntime,
3692
3958
  getVoiceTurnQualityCSS,
3693
3959
  getVoiceTraceTimelineCSS,
3694
3960
  getVoiceRoutingStatusCSS,
@@ -3696,6 +3962,7 @@ export {
3696
3962
  getVoiceProviderCapabilitiesCSS,
3697
3963
  getVoiceOpsStatusLabel,
3698
3964
  getVoiceOpsStatusCSS,
3965
+ getVoiceDeliveryRuntimeCSS,
3699
3966
  fetchVoiceWorkflowStatus,
3700
3967
  fetchVoiceTurnQuality,
3701
3968
  fetchVoiceTurnLatency,
@@ -3704,6 +3971,7 @@ export {
3704
3971
  fetchVoiceProviderStatus,
3705
3972
  fetchVoiceProviderCapabilities,
3706
3973
  fetchVoiceOpsStatus,
3974
+ fetchVoiceDeliveryRuntime,
3707
3975
  fetchVoiceCampaignDialerProofStatus,
3708
3976
  defineVoiceTurnQualityElement,
3709
3977
  defineVoiceTurnLatencyElement,
@@ -3713,6 +3981,7 @@ export {
3713
3981
  defineVoiceProviderSimulationControlsElement,
3714
3982
  defineVoiceProviderCapabilitiesElement,
3715
3983
  defineVoiceOpsStatusElement,
3984
+ defineVoiceDeliveryRuntimeElement,
3716
3985
  decodeVoiceAudioChunk,
3717
3986
  createVoiceWorkflowStatusStore,
3718
3987
  createVoiceTurnQualityViewModel,
@@ -3734,6 +4003,8 @@ export {
3734
4003
  createVoiceOpsStatusStore,
3735
4004
  createVoiceLiveTurnLatencyMonitor,
3736
4005
  createVoiceDuplexController,
4006
+ createVoiceDeliveryRuntimeViewModel,
4007
+ createVoiceDeliveryRuntimeStore,
3737
4008
  createVoiceController,
3738
4009
  createVoiceConnection,
3739
4010
  createVoiceCampaignDialerProofStore,