@absolutejs/voice 0.0.22-beta.66 → 0.0.22-beta.67

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.
@@ -4,4 +4,5 @@ export { VoiceControllerService } from './voice-controller.service';
4
4
  export { VoiceProviderCapabilitiesService } from './voice-provider-capabilities.service';
5
5
  export { VoiceProviderStatusService } from './voice-provider-status.service';
6
6
  export { VoiceRoutingStatusService } from './voice-routing-status.service';
7
+ export { VoiceTurnQualityService } from './voice-turn-quality.service';
7
8
  export { VoiceWorkflowStatusService } from './voice-workflow-status.service';
@@ -1826,9 +1826,131 @@ VoiceRoutingStatusService = __decorateElement(_init, 0, "VoiceRoutingStatusServi
1826
1826
  __runInitializers(_init, 1, VoiceRoutingStatusService);
1827
1827
  __decoratorMetadata(_init, VoiceRoutingStatusService);
1828
1828
  let _VoiceRoutingStatusService = VoiceRoutingStatusService;
1829
- // src/angular/voice-workflow-status.service.ts
1829
+ // src/angular/voice-turn-quality.service.ts
1830
1830
  import { computed as computed6, Injectable as Injectable7, signal as signal7 } from "@angular/core";
1831
1831
 
1832
+ // src/client/turnQuality.ts
1833
+ var fetchVoiceTurnQuality = async (path = "/api/turn-quality", options = {}) => {
1834
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1835
+ const response = await fetchImpl(path);
1836
+ if (!response.ok) {
1837
+ throw new Error(`Voice turn quality failed: HTTP ${response.status}`);
1838
+ }
1839
+ return await response.json();
1840
+ };
1841
+ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) => {
1842
+ const listeners = new Set;
1843
+ let closed = false;
1844
+ let timer;
1845
+ let snapshot = {
1846
+ error: null,
1847
+ isLoading: false
1848
+ };
1849
+ const emit = () => {
1850
+ for (const listener of listeners) {
1851
+ listener();
1852
+ }
1853
+ };
1854
+ const refresh = async () => {
1855
+ if (closed) {
1856
+ return snapshot.report;
1857
+ }
1858
+ snapshot = {
1859
+ ...snapshot,
1860
+ error: null,
1861
+ isLoading: true
1862
+ };
1863
+ emit();
1864
+ try {
1865
+ const report = await fetchVoiceTurnQuality(path, options);
1866
+ snapshot = {
1867
+ error: null,
1868
+ isLoading: false,
1869
+ report,
1870
+ updatedAt: Date.now()
1871
+ };
1872
+ emit();
1873
+ return report;
1874
+ } catch (error) {
1875
+ snapshot = {
1876
+ ...snapshot,
1877
+ error: error instanceof Error ? error.message : String(error),
1878
+ isLoading: false
1879
+ };
1880
+ emit();
1881
+ throw error;
1882
+ }
1883
+ };
1884
+ const close = () => {
1885
+ closed = true;
1886
+ if (timer) {
1887
+ clearInterval(timer);
1888
+ timer = undefined;
1889
+ }
1890
+ listeners.clear();
1891
+ };
1892
+ if (options.intervalMs && options.intervalMs > 0) {
1893
+ timer = setInterval(() => {
1894
+ refresh().catch(() => {});
1895
+ }, options.intervalMs);
1896
+ }
1897
+ return {
1898
+ close,
1899
+ getServerSnapshot: () => snapshot,
1900
+ getSnapshot: () => snapshot,
1901
+ refresh,
1902
+ subscribe: (listener) => {
1903
+ listeners.add(listener);
1904
+ return () => {
1905
+ listeners.delete(listener);
1906
+ };
1907
+ }
1908
+ };
1909
+ };
1910
+
1911
+ // src/angular/voice-turn-quality.service.ts
1912
+ var _dec = [
1913
+ Injectable7({ providedIn: "root" })
1914
+ ];
1915
+ var _init = __decoratorStart(undefined);
1916
+
1917
+ class VoiceTurnQualityService {
1918
+ connect(path = "/api/turn-quality", options = {}) {
1919
+ const store = createVoiceTurnQualityStore(path, options);
1920
+ const errorSignal = signal7(null);
1921
+ const isLoadingSignal = signal7(false);
1922
+ const reportSignal = signal7(undefined);
1923
+ const updatedAtSignal = signal7(undefined);
1924
+ const sync = () => {
1925
+ const snapshot = store.getSnapshot();
1926
+ errorSignal.set(snapshot.error);
1927
+ isLoadingSignal.set(snapshot.isLoading);
1928
+ reportSignal.set(snapshot.report);
1929
+ updatedAtSignal.set(snapshot.updatedAt);
1930
+ };
1931
+ const unsubscribe = store.subscribe(sync);
1932
+ sync();
1933
+ store.refresh().catch(() => {});
1934
+ return {
1935
+ close: () => {
1936
+ unsubscribe();
1937
+ store.close();
1938
+ },
1939
+ error: computed6(() => errorSignal()),
1940
+ isLoading: computed6(() => isLoadingSignal()),
1941
+ refresh: store.refresh,
1942
+ report: computed6(() => reportSignal()),
1943
+ updatedAt: computed6(() => updatedAtSignal())
1944
+ };
1945
+ }
1946
+ }
1947
+ VoiceTurnQualityService = __decorateElement(_init, 0, "VoiceTurnQualityService", _dec, VoiceTurnQualityService);
1948
+ __runInitializers(_init, 1, VoiceTurnQualityService);
1949
+ __decoratorMetadata(_init, VoiceTurnQualityService);
1950
+ let _VoiceTurnQualityService = VoiceTurnQualityService;
1951
+ // src/angular/voice-workflow-status.service.ts
1952
+ import { computed as computed7, Injectable as Injectable8, signal as signal8 } from "@angular/core";
1953
+
1832
1954
  // src/client/workflowStatus.ts
1833
1955
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
1834
1956
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -1910,17 +2032,17 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
1910
2032
 
1911
2033
  // src/angular/voice-workflow-status.service.ts
1912
2034
  var _dec = [
1913
- Injectable7({ providedIn: "root" })
2035
+ Injectable8({ providedIn: "root" })
1914
2036
  ];
1915
2037
  var _init = __decoratorStart(undefined);
1916
2038
 
1917
2039
  class VoiceWorkflowStatusService {
1918
2040
  connect(path = "/evals/scenarios/json", options = {}) {
1919
2041
  const store = createVoiceWorkflowStatusStore(path, options);
1920
- const errorSignal = signal7(null);
1921
- const isLoadingSignal = signal7(false);
1922
- const reportSignal = signal7(undefined);
1923
- const updatedAtSignal = signal7(undefined);
2042
+ const errorSignal = signal8(null);
2043
+ const isLoadingSignal = signal8(false);
2044
+ const reportSignal = signal8(undefined);
2045
+ const updatedAtSignal = signal8(undefined);
1924
2046
  const sync = () => {
1925
2047
  const snapshot = store.getSnapshot();
1926
2048
  errorSignal.set(snapshot.error);
@@ -1938,11 +2060,11 @@ class VoiceWorkflowStatusService {
1938
2060
  unsubscribe();
1939
2061
  store.close();
1940
2062
  },
1941
- error: computed6(() => errorSignal()),
1942
- isLoading: computed6(() => isLoadingSignal()),
2063
+ error: computed7(() => errorSignal()),
2064
+ isLoading: computed7(() => isLoadingSignal()),
1943
2065
  refresh: store.refresh,
1944
- report: computed6(() => reportSignal()),
1945
- updatedAt: computed6(() => updatedAtSignal())
2066
+ report: computed7(() => reportSignal()),
2067
+ updatedAt: computed7(() => updatedAtSignal())
1946
2068
  };
1947
2069
  }
1948
2070
  }
@@ -1952,6 +2074,7 @@ __decoratorMetadata(_init, VoiceWorkflowStatusService);
1952
2074
  let _VoiceWorkflowStatusService = VoiceWorkflowStatusService;
1953
2075
  export {
1954
2076
  VoiceWorkflowStatusService,
2077
+ VoiceTurnQualityService,
1955
2078
  VoiceStreamService,
1956
2079
  VoiceRoutingStatusService,
1957
2080
  VoiceProviderStatusService,
@@ -0,0 +1,12 @@
1
+ import { type VoiceTurnQualityClientOptions } from '../client/turnQuality';
2
+ import type { VoiceTurnQualityReport } from '../turnQuality';
3
+ export declare class VoiceTurnQualityService {
4
+ connect(path?: string, options?: VoiceTurnQualityClientOptions): {
5
+ close: () => void;
6
+ error: import("@angular/core").Signal<string | null>;
7
+ isLoading: import("@angular/core").Signal<boolean>;
8
+ refresh: () => Promise<VoiceTurnQualityReport | undefined>;
9
+ report: import("@angular/core").Signal<VoiceTurnQualityReport | undefined>;
10
+ updatedAt: import("@angular/core").Signal<number | undefined>;
11
+ };
12
+ }
@@ -11,10 +11,12 @@ export { createVoiceRoutingStatusStore, fetchVoiceRoutingStatus } from './routin
11
11
  export { createVoiceRoutingStatusViewModel, defineVoiceRoutingStatusElement, getVoiceRoutingStatusCSS, mountVoiceRoutingStatus, renderVoiceRoutingStatusHTML } from './routingStatusWidget';
12
12
  export { createVoiceProviderStatusStore, fetchVoiceProviderStatus } from './providerStatus';
13
13
  export { createVoiceProviderCapabilitiesStore, fetchVoiceProviderCapabilities } from './providerCapabilities';
14
+ export { createVoiceTurnQualityStore, fetchVoiceTurnQuality } from './turnQuality';
14
15
  export { createVoiceProviderSimulationControlsStore } from './providerSimulationControls';
15
16
  export { bindVoiceProviderSimulationControls, createVoiceProviderSimulationControlsViewModel, defineVoiceProviderSimulationControlsElement, mountVoiceProviderSimulationControls, renderVoiceProviderSimulationControlsHTML } from './providerSimulationControlsWidget';
16
17
  export { createVoiceProviderStatusViewModel, defineVoiceProviderStatusElement, getVoiceProviderStatusCSS, mountVoiceProviderStatus, renderVoiceProviderStatusHTML } from './providerStatusWidget';
17
18
  export { createVoiceProviderCapabilitiesViewModel, defineVoiceProviderCapabilitiesElement, getVoiceProviderCapabilitiesCSS, mountVoiceProviderCapabilities, renderVoiceProviderCapabilitiesHTML } from './providerCapabilitiesWidget';
19
+ export { createVoiceTurnQualityViewModel, defineVoiceTurnQualityElement, getVoiceTurnQualityCSS, mountVoiceTurnQuality, renderVoiceTurnQualityHTML } from './turnQualityWidget';
18
20
  export { createVoiceWorkflowStatusStore, fetchVoiceWorkflowStatus } from './workflowStatus';
19
21
  export type { VoiceAppKitStatusClientOptions, VoiceAppKitStatusSnapshot } from './appKitStatus';
20
22
  export type { VoiceOpsStatusSurfaceView, VoiceOpsStatusViewModel, VoiceOpsStatusWidgetOptions } from './opsStatusWidget';
@@ -22,8 +24,10 @@ export type { VoiceRoutingStatusClientOptions, VoiceRoutingStatusSnapshot } from
22
24
  export type { VoiceRoutingStatusViewModel, VoiceRoutingStatusWidgetOptions } from './routingStatusWidget';
23
25
  export type { VoiceProviderStatusClientOptions, VoiceProviderStatusSnapshot } from './providerStatus';
24
26
  export type { VoiceProviderCapabilitiesClientOptions, VoiceProviderCapabilitiesSnapshot } from './providerCapabilities';
27
+ export type { VoiceTurnQualityClientOptions, VoiceTurnQualitySnapshot } from './turnQuality';
25
28
  export type { VoiceProviderSimulationControlsOptions, VoiceProviderSimulationControlsSnapshot, VoiceProviderSimulationProvider } from './providerSimulationControls';
26
29
  export type { VoiceProviderSimulationControlsViewModel } from './providerSimulationControlsWidget';
27
30
  export type { VoiceProviderStatusCardView, VoiceProviderStatusViewModel, VoiceProviderStatusWidgetOptions } from './providerStatusWidget';
28
31
  export type { VoiceProviderCapabilitiesViewModel, VoiceProviderCapabilitiesWidgetOptions, VoiceProviderCapabilityCardView } from './providerCapabilitiesWidget';
32
+ export type { VoiceTurnQualityCardView, VoiceTurnQualityViewModel, VoiceTurnQualityWidgetOptions } from './turnQualityWidget';
29
33
  export type { VoiceWorkflowStatusClientOptions, VoiceWorkflowStatusSnapshot } from './workflowStatus';
@@ -2151,6 +2151,84 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
2151
2151
  }
2152
2152
  };
2153
2153
  };
2154
+ // src/client/turnQuality.ts
2155
+ var fetchVoiceTurnQuality = async (path = "/api/turn-quality", options = {}) => {
2156
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2157
+ const response = await fetchImpl(path);
2158
+ if (!response.ok) {
2159
+ throw new Error(`Voice turn quality failed: HTTP ${response.status}`);
2160
+ }
2161
+ return await response.json();
2162
+ };
2163
+ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) => {
2164
+ const listeners = new Set;
2165
+ let closed = false;
2166
+ let timer;
2167
+ let snapshot = {
2168
+ error: null,
2169
+ isLoading: false
2170
+ };
2171
+ const emit = () => {
2172
+ for (const listener of listeners) {
2173
+ listener();
2174
+ }
2175
+ };
2176
+ const refresh = async () => {
2177
+ if (closed) {
2178
+ return snapshot.report;
2179
+ }
2180
+ snapshot = {
2181
+ ...snapshot,
2182
+ error: null,
2183
+ isLoading: true
2184
+ };
2185
+ emit();
2186
+ try {
2187
+ const report = await fetchVoiceTurnQuality(path, options);
2188
+ snapshot = {
2189
+ error: null,
2190
+ isLoading: false,
2191
+ report,
2192
+ updatedAt: Date.now()
2193
+ };
2194
+ emit();
2195
+ return report;
2196
+ } catch (error) {
2197
+ snapshot = {
2198
+ ...snapshot,
2199
+ error: error instanceof Error ? error.message : String(error),
2200
+ isLoading: false
2201
+ };
2202
+ emit();
2203
+ throw error;
2204
+ }
2205
+ };
2206
+ const close = () => {
2207
+ closed = true;
2208
+ if (timer) {
2209
+ clearInterval(timer);
2210
+ timer = undefined;
2211
+ }
2212
+ listeners.clear();
2213
+ };
2214
+ if (options.intervalMs && options.intervalMs > 0) {
2215
+ timer = setInterval(() => {
2216
+ refresh().catch(() => {});
2217
+ }, options.intervalMs);
2218
+ }
2219
+ return {
2220
+ close,
2221
+ getServerSnapshot: () => snapshot,
2222
+ getSnapshot: () => snapshot,
2223
+ refresh,
2224
+ subscribe: (listener) => {
2225
+ listeners.add(listener);
2226
+ return () => {
2227
+ listeners.delete(listener);
2228
+ };
2229
+ }
2230
+ };
2231
+ };
2154
2232
  // src/client/providerSimulationControls.ts
2155
2233
  var postSimulation = async (pathPrefix, mode, provider, fetchImpl) => {
2156
2234
  const response = await fetchImpl(`${pathPrefix}/${mode}?provider=${encodeURIComponent(provider)}`, { method: "POST" });
@@ -2558,6 +2636,117 @@ var defineVoiceProviderCapabilitiesElement = (tagName = "absolute-voice-provider
2558
2636
  }
2559
2637
  });
2560
2638
  };
2639
+ // src/client/turnQualityWidget.ts
2640
+ var DEFAULT_TITLE5 = "Turn Quality";
2641
+ var DEFAULT_DESCRIPTION5 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2642
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2643
+ var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2644
+ var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2645
+ var getTurnDetail = (turn) => {
2646
+ if (turn.status === "fail") {
2647
+ return "Empty or unusable committed turn; inspect transcripts and adapter events.";
2648
+ }
2649
+ if (turn.fallbackUsed) {
2650
+ return `Fallback STT selected${turn.fallbackSelectionReason ? ` by ${turn.fallbackSelectionReason}` : ""}.`;
2651
+ }
2652
+ if (turn.correctionChanged) {
2653
+ return `Correction changed the turn${turn.correctionProvider ? ` via ${turn.correctionProvider}` : ""}.`;
2654
+ }
2655
+ if (turn.status === "warn") {
2656
+ return "Turn completed with quality warnings.";
2657
+ }
2658
+ if (turn.status === "unknown") {
2659
+ return "No quality diagnostics were recorded for this turn.";
2660
+ }
2661
+ return "Turn quality looks healthy.";
2662
+ };
2663
+ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2664
+ const turns = (snapshot.report?.turns ?? []).map((turn) => ({
2665
+ ...turn,
2666
+ detail: getTurnDetail(turn),
2667
+ label: turn.text || "Empty turn",
2668
+ rows: [
2669
+ { label: "Source", value: turn.source ?? "unknown" },
2670
+ { label: "Confidence", value: formatConfidence(turn.averageConfidence) },
2671
+ { label: "Fallback", value: turn.fallbackUsed ? "Yes" : "No" },
2672
+ { label: "Correction", value: turn.correctionChanged ? "Changed" : "None" },
2673
+ { label: "Transcripts", value: `${turn.selectedTranscriptCount} selected` },
2674
+ { label: "Cost", value: formatMaybe(turn.costUnits) }
2675
+ ]
2676
+ }));
2677
+ const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2678
+ const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2679
+ return {
2680
+ description: options.description ?? DEFAULT_DESCRIPTION5,
2681
+ error: snapshot.error,
2682
+ isLoading: snapshot.isLoading,
2683
+ label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2684
+ status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2685
+ title: options.title ?? DEFAULT_TITLE5,
2686
+ turns,
2687
+ updatedAt: snapshot.updatedAt
2688
+ };
2689
+ };
2690
+ var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2691
+ const model = createVoiceTurnQualityViewModel(snapshot, options);
2692
+ 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)}">
2693
+ <header>
2694
+ <strong>${escapeHtml6(turn.label)}</strong>
2695
+ <span>${escapeHtml6(turn.status)}</span>
2696
+ </header>
2697
+ <p>${escapeHtml6(turn.detail)}</p>
2698
+ <dl>${turn.rows.map((row) => `<div>
2699
+ <dt>${escapeHtml6(row.label)}</dt>
2700
+ <dd>${escapeHtml6(row.value)}</dd>
2701
+ </div>`).join("")}</dl>
2702
+ </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2703
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml6(model.status)}">
2704
+ <header class="absolute-voice-turn-quality__header">
2705
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml6(model.title)}</span>
2706
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml6(model.label)}</strong>
2707
+ </header>
2708
+ <p class="absolute-voice-turn-quality__description">${escapeHtml6(model.description)}</p>
2709
+ ${turns}
2710
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml6(model.error)}</p>` : ""}
2711
+ </section>`;
2712
+ };
2713
+ 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}`;
2714
+ var mountVoiceTurnQuality = (element, path = "/api/turn-quality", options = {}) => {
2715
+ const store = createVoiceTurnQualityStore(path, options);
2716
+ const render = () => {
2717
+ element.innerHTML = renderVoiceTurnQualityHTML(store.getSnapshot(), options);
2718
+ };
2719
+ const unsubscribe = store.subscribe(render);
2720
+ render();
2721
+ store.refresh().catch(() => {});
2722
+ return {
2723
+ close: () => {
2724
+ unsubscribe();
2725
+ store.close();
2726
+ },
2727
+ refresh: store.refresh
2728
+ };
2729
+ };
2730
+ var defineVoiceTurnQualityElement = (tagName = "absolute-voice-turn-quality") => {
2731
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
2732
+ return;
2733
+ }
2734
+ customElements.define(tagName, class AbsoluteVoiceTurnQualityElement extends HTMLElement {
2735
+ mounted;
2736
+ connectedCallback() {
2737
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
2738
+ this.mounted = mountVoiceTurnQuality(this, this.getAttribute("path") ?? "/api/turn-quality", {
2739
+ description: this.getAttribute("description") ?? undefined,
2740
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
2741
+ title: this.getAttribute("title") ?? undefined
2742
+ });
2743
+ }
2744
+ disconnectedCallback() {
2745
+ this.mounted?.close();
2746
+ this.mounted = undefined;
2747
+ }
2748
+ });
2749
+ };
2561
2750
  // src/client/workflowStatus.ts
2562
2751
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
2563
2752
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -2637,26 +2826,31 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
2637
2826
  };
2638
2827
  };
2639
2828
  export {
2829
+ renderVoiceTurnQualityHTML,
2640
2830
  renderVoiceRoutingStatusHTML,
2641
2831
  renderVoiceProviderStatusHTML,
2642
2832
  renderVoiceProviderSimulationControlsHTML,
2643
2833
  renderVoiceProviderCapabilitiesHTML,
2644
2834
  renderVoiceOpsStatusHTML,
2835
+ mountVoiceTurnQuality,
2645
2836
  mountVoiceRoutingStatus,
2646
2837
  mountVoiceProviderStatus,
2647
2838
  mountVoiceProviderSimulationControls,
2648
2839
  mountVoiceProviderCapabilities,
2649
2840
  mountVoiceOpsStatus,
2841
+ getVoiceTurnQualityCSS,
2650
2842
  getVoiceRoutingStatusCSS,
2651
2843
  getVoiceProviderStatusCSS,
2652
2844
  getVoiceProviderCapabilitiesCSS,
2653
2845
  getVoiceOpsStatusLabel,
2654
2846
  getVoiceOpsStatusCSS,
2655
2847
  fetchVoiceWorkflowStatus,
2848
+ fetchVoiceTurnQuality,
2656
2849
  fetchVoiceRoutingStatus,
2657
2850
  fetchVoiceProviderStatus,
2658
2851
  fetchVoiceProviderCapabilities,
2659
2852
  fetchVoiceAppKitStatus,
2853
+ defineVoiceTurnQualityElement,
2660
2854
  defineVoiceRoutingStatusElement,
2661
2855
  defineVoiceProviderStatusElement,
2662
2856
  defineVoiceProviderSimulationControlsElement,
@@ -2664,6 +2858,8 @@ export {
2664
2858
  defineVoiceOpsStatusElement,
2665
2859
  decodeVoiceAudioChunk,
2666
2860
  createVoiceWorkflowStatusStore,
2861
+ createVoiceTurnQualityViewModel,
2862
+ createVoiceTurnQualityStore,
2667
2863
  createVoiceStream,
2668
2864
  createVoiceRoutingStatusViewModel,
2669
2865
  createVoiceRoutingStatusStore,
@@ -0,0 +1,19 @@
1
+ import type { VoiceTurnQualityReport } from '../turnQuality';
2
+ export type VoiceTurnQualityClientOptions = {
3
+ fetch?: typeof fetch;
4
+ intervalMs?: number;
5
+ };
6
+ export type VoiceTurnQualitySnapshot = {
7
+ error: string | null;
8
+ isLoading: boolean;
9
+ report?: VoiceTurnQualityReport;
10
+ updatedAt?: number;
11
+ };
12
+ export declare const fetchVoiceTurnQuality: (path?: string, options?: Pick<VoiceTurnQualityClientOptions, "fetch">) => Promise<VoiceTurnQualityReport>;
13
+ export declare const createVoiceTurnQualityStore: (path?: string, options?: VoiceTurnQualityClientOptions) => {
14
+ close: () => void;
15
+ getServerSnapshot: () => VoiceTurnQualitySnapshot;
16
+ getSnapshot: () => VoiceTurnQualitySnapshot;
17
+ refresh: () => Promise<VoiceTurnQualityReport | undefined>;
18
+ subscribe: (listener: () => void) => () => void;
19
+ };
@@ -0,0 +1,32 @@
1
+ import type { VoiceTurnQualityItem } from '../turnQuality';
2
+ import { type VoiceTurnQualityClientOptions, type VoiceTurnQualitySnapshot } from './turnQuality';
3
+ export type VoiceTurnQualityCardView = VoiceTurnQualityItem & {
4
+ detail: string;
5
+ label: string;
6
+ rows: Array<{
7
+ label: string;
8
+ value: string;
9
+ }>;
10
+ };
11
+ export type VoiceTurnQualityViewModel = {
12
+ description: string;
13
+ error: string | null;
14
+ isLoading: boolean;
15
+ label: string;
16
+ status: 'empty' | 'error' | 'loading' | 'ready' | 'warning';
17
+ title: string;
18
+ turns: VoiceTurnQualityCardView[];
19
+ updatedAt?: number;
20
+ };
21
+ export type VoiceTurnQualityWidgetOptions = VoiceTurnQualityClientOptions & {
22
+ description?: string;
23
+ title?: string;
24
+ };
25
+ export declare const createVoiceTurnQualityViewModel: (snapshot: VoiceTurnQualitySnapshot, options?: VoiceTurnQualityWidgetOptions) => VoiceTurnQualityViewModel;
26
+ export declare const renderVoiceTurnQualityHTML: (snapshot: VoiceTurnQualitySnapshot, options?: VoiceTurnQualityWidgetOptions) => string;
27
+ export declare const getVoiceTurnQualityCSS: () => string;
28
+ export declare const mountVoiceTurnQuality: (element: Element, path?: string, options?: VoiceTurnQualityWidgetOptions) => {
29
+ close: () => void;
30
+ refresh: () => Promise<import("..").VoiceTurnQualityReport | undefined>;
31
+ };
32
+ export declare const defineVoiceTurnQualityElement: (tagName?: string) => void;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export { createVoiceSessionListRoutes, createVoiceSessionReplayHTMLHandler, crea
9
9
  export { createVoiceAgent, createVoiceAgentSquad, createVoiceAgentTool } from './agent';
10
10
  export { createVoiceToolIdempotencyKey, createVoiceToolRuntime } from './toolRuntime';
11
11
  export { createVoiceToolContract, createVoiceToolContractHTMLHandler, createVoiceToolContractJSONHandler, createVoiceToolContractRoutes, createVoiceToolRuntimeContractDefaults, renderVoiceToolContractHTML, runVoiceToolContractSuite, runVoiceToolContract } from './toolContract';
12
+ export { createVoiceTurnQualityHTMLHandler, createVoiceTurnQualityJSONHandler, createVoiceTurnQualityRoutes, renderVoiceTurnQualityHTML, summarizeVoiceTurnQuality } from './turnQuality';
12
13
  export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileExternalObjectMapStore, createVoiceFileAssistantMemoryStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
13
14
  export { createVoiceAssistantMemoryHandle, createVoiceAssistantMemoryRecord, createVoiceMemoryAssistantMemoryStore, resolveVoiceAssistantMemoryNamespace } from './assistantMemory';
14
15
  export { createAnthropicVoiceAssistantModel, createGeminiVoiceAssistantModel, createJSONVoiceAssistantModel, createOpenAIVoiceAssistantModel, resolveVoiceProviderRoutingPolicyPreset, createVoiceProviderRouter } from './modelAdapters';
@@ -52,6 +53,7 @@ export type { VoiceSessionListHTMLHandlerOptions, VoiceSessionListItem, VoiceSes
52
53
  export type { AnthropicVoiceAssistantModelOptions, GeminiVoiceAssistantModelOptions, OpenAIVoiceAssistantModelOptions, VoiceProviderRouterEvent, VoiceProviderRouterFallbackMode, VoiceProviderRouterHealthOptions, VoiceProviderRouterOptions, VoiceProviderRouterPolicy, VoiceProviderRouterPolicyPreset, VoiceProviderRouterPolicyWeights, VoiceProviderRouterProviderHealth, VoiceProviderRouterProviderProfile, VoiceProviderRouterStrategy, VoiceJSONAssistantModelHandler, VoiceJSONAssistantModelOptions } from './modelAdapters';
53
54
  export type { VoiceProviderHealthStatus, VoiceProviderHealthSummary, VoiceProviderHealthSummaryOptions } from './providerHealth';
54
55
  export type { VoiceProviderCapabilityDefinition, VoiceProviderCapabilityHandlerOptions, VoiceProviderCapabilityHTMLHandlerOptions, VoiceProviderCapabilityKind, VoiceProviderCapabilityOptions, VoiceProviderCapabilityReport, VoiceProviderCapabilityRoutesOptions, VoiceProviderCapabilitySummary } from './providerCapabilities';
56
+ export type { VoiceTurnQualityHTMLHandlerOptions, VoiceTurnQualityItem, VoiceTurnQualityOptions, VoiceTurnQualityReport, VoiceTurnQualityRoutesOptions, VoiceTurnQualityStatus } from './turnQuality';
55
57
  export type { VoiceOpsConsoleLink, VoiceOpsConsoleReport, VoiceOpsConsoleRoutesOptions } from './opsConsoleRoutes';
56
58
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
57
59
  export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind } from './resilienceRoutes';