@absolutejs/voice 0.0.22-beta.57 → 0.0.22-beta.59

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.
@@ -2,4 +2,5 @@ export { VoiceAppKitStatusService } from './voice-app-kit-status.service';
2
2
  export { VoiceStreamService } from './voice-stream.service';
3
3
  export { VoiceControllerService } from './voice-controller.service';
4
4
  export { VoiceProviderStatusService } from './voice-provider-status.service';
5
+ export { VoiceRoutingStatusService } from './voice-routing-status.service';
5
6
  export { VoiceWorkflowStatusService } from './voice-workflow-status.service';
@@ -1581,8 +1581,131 @@ VoiceProviderStatusService = __decorateElement(_init, 0, "VoiceProviderStatusSer
1581
1581
  __runInitializers(_init, 1, VoiceProviderStatusService);
1582
1582
  __decoratorMetadata(_init, VoiceProviderStatusService);
1583
1583
  let _VoiceProviderStatusService = VoiceProviderStatusService;
1584
+ // src/angular/voice-routing-status.service.ts
1585
+ import { Injectable as Injectable5, signal as signal5 } from "@angular/core";
1586
+
1587
+ // src/client/routingStatus.ts
1588
+ var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
1589
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1590
+ const response = await fetchImpl(path);
1591
+ if (!response.ok) {
1592
+ throw new Error(`Voice routing status failed: HTTP ${response.status}`);
1593
+ }
1594
+ return await response.json();
1595
+ };
1596
+ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {}) => {
1597
+ const listeners = new Set;
1598
+ let closed = false;
1599
+ let timer;
1600
+ let snapshot = {
1601
+ decision: null,
1602
+ error: null,
1603
+ isLoading: false
1604
+ };
1605
+ const emit = () => {
1606
+ for (const listener of listeners) {
1607
+ listener();
1608
+ }
1609
+ };
1610
+ const refresh = async () => {
1611
+ if (closed) {
1612
+ return snapshot.decision;
1613
+ }
1614
+ snapshot = {
1615
+ ...snapshot,
1616
+ error: null,
1617
+ isLoading: true
1618
+ };
1619
+ emit();
1620
+ try {
1621
+ const decision = await fetchVoiceRoutingStatus(path, options);
1622
+ snapshot = {
1623
+ decision,
1624
+ error: null,
1625
+ isLoading: false,
1626
+ updatedAt: Date.now()
1627
+ };
1628
+ emit();
1629
+ return decision;
1630
+ } catch (error) {
1631
+ snapshot = {
1632
+ ...snapshot,
1633
+ error: error instanceof Error ? error.message : String(error),
1634
+ isLoading: false
1635
+ };
1636
+ emit();
1637
+ throw error;
1638
+ }
1639
+ };
1640
+ const close = () => {
1641
+ closed = true;
1642
+ if (timer) {
1643
+ clearInterval(timer);
1644
+ timer = undefined;
1645
+ }
1646
+ listeners.clear();
1647
+ };
1648
+ if (options.intervalMs && options.intervalMs > 0) {
1649
+ timer = setInterval(() => {
1650
+ refresh().catch(() => {});
1651
+ }, options.intervalMs);
1652
+ }
1653
+ return {
1654
+ close,
1655
+ getServerSnapshot: () => snapshot,
1656
+ getSnapshot: () => snapshot,
1657
+ refresh,
1658
+ subscribe: (listener) => {
1659
+ listeners.add(listener);
1660
+ return () => {
1661
+ listeners.delete(listener);
1662
+ };
1663
+ }
1664
+ };
1665
+ };
1666
+
1667
+ // src/angular/voice-routing-status.service.ts
1668
+ var _dec = [
1669
+ Injectable5({ providedIn: "root" })
1670
+ ];
1671
+ var _init = __decoratorStart(undefined);
1672
+
1673
+ class VoiceRoutingStatusService {
1674
+ connect(path = "/api/routing/latest", options = {}) {
1675
+ const store = createVoiceRoutingStatusStore(path, options);
1676
+ const decisionSignal = signal5(null);
1677
+ const errorSignal = signal5(null);
1678
+ const isLoadingSignal = signal5(false);
1679
+ const updatedAtSignal = signal5(undefined);
1680
+ const sync = () => {
1681
+ const snapshot = store.getSnapshot();
1682
+ decisionSignal.set(snapshot.decision);
1683
+ errorSignal.set(snapshot.error);
1684
+ isLoadingSignal.set(snapshot.isLoading);
1685
+ updatedAtSignal.set(snapshot.updatedAt);
1686
+ };
1687
+ const unsubscribe = store.subscribe(sync);
1688
+ sync();
1689
+ store.refresh().catch(() => {});
1690
+ return {
1691
+ close: () => {
1692
+ unsubscribe();
1693
+ store.close();
1694
+ },
1695
+ decision: decisionSignal.asReadonly(),
1696
+ error: errorSignal.asReadonly(),
1697
+ isLoading: isLoadingSignal.asReadonly(),
1698
+ refresh: store.refresh,
1699
+ updatedAt: updatedAtSignal.asReadonly()
1700
+ };
1701
+ }
1702
+ }
1703
+ VoiceRoutingStatusService = __decorateElement(_init, 0, "VoiceRoutingStatusService", _dec, VoiceRoutingStatusService);
1704
+ __runInitializers(_init, 1, VoiceRoutingStatusService);
1705
+ __decoratorMetadata(_init, VoiceRoutingStatusService);
1706
+ let _VoiceRoutingStatusService = VoiceRoutingStatusService;
1584
1707
  // src/angular/voice-workflow-status.service.ts
1585
- import { computed as computed5, Injectable as Injectable5, signal as signal5 } from "@angular/core";
1708
+ import { computed as computed5, Injectable as Injectable6, signal as signal6 } from "@angular/core";
1586
1709
 
1587
1710
  // src/client/workflowStatus.ts
1588
1711
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
@@ -1665,17 +1788,17 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
1665
1788
 
1666
1789
  // src/angular/voice-workflow-status.service.ts
1667
1790
  var _dec = [
1668
- Injectable5({ providedIn: "root" })
1791
+ Injectable6({ providedIn: "root" })
1669
1792
  ];
1670
1793
  var _init = __decoratorStart(undefined);
1671
1794
 
1672
1795
  class VoiceWorkflowStatusService {
1673
1796
  connect(path = "/evals/scenarios/json", options = {}) {
1674
1797
  const store = createVoiceWorkflowStatusStore(path, options);
1675
- const errorSignal = signal5(null);
1676
- const isLoadingSignal = signal5(false);
1677
- const reportSignal = signal5(undefined);
1678
- const updatedAtSignal = signal5(undefined);
1798
+ const errorSignal = signal6(null);
1799
+ const isLoadingSignal = signal6(false);
1800
+ const reportSignal = signal6(undefined);
1801
+ const updatedAtSignal = signal6(undefined);
1679
1802
  const sync = () => {
1680
1803
  const snapshot = store.getSnapshot();
1681
1804
  errorSignal.set(snapshot.error);
@@ -1708,6 +1831,7 @@ let _VoiceWorkflowStatusService = VoiceWorkflowStatusService;
1708
1831
  export {
1709
1832
  VoiceWorkflowStatusService,
1710
1833
  VoiceStreamService,
1834
+ VoiceRoutingStatusService,
1711
1835
  VoiceProviderStatusService,
1712
1836
  VoiceControllerService,
1713
1837
  VoiceAppKitStatusService
@@ -0,0 +1,11 @@
1
+ import { type VoiceRoutingStatusClientOptions } from '../client/routingStatus';
2
+ export declare class VoiceRoutingStatusService {
3
+ connect(path?: string, options?: VoiceRoutingStatusClientOptions): {
4
+ close: () => void;
5
+ decision: import("@angular/core").Signal<import("..").VoiceRoutingEvent | null>;
6
+ error: import("@angular/core").Signal<string | null>;
7
+ isLoading: import("@angular/core").Signal<boolean>;
8
+ refresh: () => Promise<import("..").VoiceRoutingEvent | null>;
9
+ updatedAt: import("@angular/core").Signal<number | undefined>;
10
+ };
11
+ }
@@ -7,9 +7,13 @@ export { bindVoiceHTMX } from './htmx';
7
7
  export { createMicrophoneCapture } from './microphone';
8
8
  export { createVoiceAppKitStatusStore, fetchVoiceAppKitStatus } from './appKitStatus';
9
9
  export { createVoiceOpsStatusViewModel, defineVoiceOpsStatusElement, getVoiceOpsStatusCSS, getVoiceOpsStatusLabel, mountVoiceOpsStatus, renderVoiceOpsStatusHTML } from './opsStatusWidget';
10
+ export { createVoiceRoutingStatusStore, fetchVoiceRoutingStatus } from './routingStatus';
11
+ export { createVoiceRoutingStatusViewModel, defineVoiceRoutingStatusElement, getVoiceRoutingStatusCSS, mountVoiceRoutingStatus, renderVoiceRoutingStatusHTML } from './routingStatusWidget';
10
12
  export { createVoiceProviderStatusStore, fetchVoiceProviderStatus } from './providerStatus';
11
13
  export { createVoiceWorkflowStatusStore, fetchVoiceWorkflowStatus } from './workflowStatus';
12
14
  export type { VoiceAppKitStatusClientOptions, VoiceAppKitStatusSnapshot } from './appKitStatus';
13
15
  export type { VoiceOpsStatusSurfaceView, VoiceOpsStatusViewModel, VoiceOpsStatusWidgetOptions } from './opsStatusWidget';
16
+ export type { VoiceRoutingStatusClientOptions, VoiceRoutingStatusSnapshot } from './routingStatus';
17
+ export type { VoiceRoutingStatusViewModel, VoiceRoutingStatusWidgetOptions } from './routingStatusWidget';
14
18
  export type { VoiceProviderStatusClientOptions, VoiceProviderStatusSnapshot } from './providerStatus';
15
19
  export type { VoiceWorkflowStatusClientOptions, VoiceWorkflowStatusSnapshot } from './workflowStatus';
@@ -1825,6 +1825,175 @@ var defineVoiceOpsStatusElement = (tagName = "absolute-voice-ops-status") => {
1825
1825
  }
1826
1826
  });
1827
1827
  };
1828
+ // src/client/routingStatus.ts
1829
+ var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
1830
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1831
+ const response = await fetchImpl(path);
1832
+ if (!response.ok) {
1833
+ throw new Error(`Voice routing status failed: HTTP ${response.status}`);
1834
+ }
1835
+ return await response.json();
1836
+ };
1837
+ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {}) => {
1838
+ const listeners = new Set;
1839
+ let closed = false;
1840
+ let timer;
1841
+ let snapshot = {
1842
+ decision: null,
1843
+ error: null,
1844
+ isLoading: false
1845
+ };
1846
+ const emit = () => {
1847
+ for (const listener of listeners) {
1848
+ listener();
1849
+ }
1850
+ };
1851
+ const refresh = async () => {
1852
+ if (closed) {
1853
+ return snapshot.decision;
1854
+ }
1855
+ snapshot = {
1856
+ ...snapshot,
1857
+ error: null,
1858
+ isLoading: true
1859
+ };
1860
+ emit();
1861
+ try {
1862
+ const decision = await fetchVoiceRoutingStatus(path, options);
1863
+ snapshot = {
1864
+ decision,
1865
+ error: null,
1866
+ isLoading: false,
1867
+ updatedAt: Date.now()
1868
+ };
1869
+ emit();
1870
+ return decision;
1871
+ } catch (error) {
1872
+ snapshot = {
1873
+ ...snapshot,
1874
+ error: error instanceof Error ? error.message : String(error),
1875
+ isLoading: false
1876
+ };
1877
+ emit();
1878
+ throw error;
1879
+ }
1880
+ };
1881
+ const close = () => {
1882
+ closed = true;
1883
+ if (timer) {
1884
+ clearInterval(timer);
1885
+ timer = undefined;
1886
+ }
1887
+ listeners.clear();
1888
+ };
1889
+ if (options.intervalMs && options.intervalMs > 0) {
1890
+ timer = setInterval(() => {
1891
+ refresh().catch(() => {});
1892
+ }, options.intervalMs);
1893
+ }
1894
+ return {
1895
+ close,
1896
+ getServerSnapshot: () => snapshot,
1897
+ getSnapshot: () => snapshot,
1898
+ refresh,
1899
+ subscribe: (listener) => {
1900
+ listeners.add(listener);
1901
+ return () => {
1902
+ listeners.delete(listener);
1903
+ };
1904
+ }
1905
+ };
1906
+ };
1907
+ // src/client/routingStatusWidget.ts
1908
+ var DEFAULT_TITLE2 = "Voice Routing";
1909
+ var DEFAULT_DESCRIPTION2 = "Latest provider routing decision from the self-hosted trace store.";
1910
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1911
+ var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
1912
+ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1913
+ const decision = snapshot.decision;
1914
+ const rows = decision ? [
1915
+ { label: "Kind", value: decision.kind.toUpperCase() },
1916
+ { label: "Policy", value: formatValue(decision.routing, "Unknown") },
1917
+ { label: "Provider", value: formatValue(decision.provider, "Unknown") },
1918
+ {
1919
+ label: "Selected",
1920
+ value: formatValue(decision.selectedProvider, "Unknown")
1921
+ },
1922
+ {
1923
+ label: "Fallback",
1924
+ value: formatValue(decision.fallbackProvider)
1925
+ },
1926
+ { label: "Status", value: formatValue(decision.status, "unknown") },
1927
+ {
1928
+ label: "Latency budget",
1929
+ value: typeof decision.latencyBudgetMs === "number" ? `${decision.latencyBudgetMs}ms` : "None"
1930
+ }
1931
+ ] : [];
1932
+ return {
1933
+ decision,
1934
+ description: options.description ?? DEFAULT_DESCRIPTION2,
1935
+ error: snapshot.error,
1936
+ isLoading: snapshot.isLoading,
1937
+ label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
1938
+ rows,
1939
+ status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
1940
+ title: options.title ?? DEFAULT_TITLE2,
1941
+ updatedAt: snapshot.updatedAt
1942
+ };
1943
+ };
1944
+ var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
1945
+ const model = createVoiceRoutingStatusViewModel(snapshot, options);
1946
+ const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
1947
+ <span>${escapeHtml2(row.label)}</span>
1948
+ <strong>${escapeHtml2(row.value)}</strong>
1949
+ </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
1950
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml2(model.status)}">
1951
+ <header class="absolute-voice-routing-status__header">
1952
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml2(model.title)}</span>
1953
+ <strong class="absolute-voice-routing-status__label">${escapeHtml2(model.label)}</strong>
1954
+ </header>
1955
+ <p class="absolute-voice-routing-status__description">${escapeHtml2(model.description)}</p>
1956
+ ${rows}
1957
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml2(model.error)}</p>` : ""}
1958
+ </section>`;
1959
+ };
1960
+ 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}`;
1961
+ var mountVoiceRoutingStatus = (element, path = "/api/routing/latest", options = {}) => {
1962
+ const store = createVoiceRoutingStatusStore(path, options);
1963
+ const render = () => {
1964
+ element.innerHTML = renderVoiceRoutingStatusHTML(store.getSnapshot(), options);
1965
+ };
1966
+ const unsubscribe = store.subscribe(render);
1967
+ render();
1968
+ store.refresh().catch(() => {});
1969
+ return {
1970
+ close: () => {
1971
+ unsubscribe();
1972
+ store.close();
1973
+ },
1974
+ refresh: store.refresh
1975
+ };
1976
+ };
1977
+ var defineVoiceRoutingStatusElement = (tagName = "absolute-voice-routing-status") => {
1978
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
1979
+ return;
1980
+ }
1981
+ customElements.define(tagName, class AbsoluteVoiceRoutingStatusElement extends HTMLElement {
1982
+ mounted;
1983
+ connectedCallback() {
1984
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
1985
+ this.mounted = mountVoiceRoutingStatus(this, this.getAttribute("path") ?? "/api/routing/latest", {
1986
+ description: this.getAttribute("description") ?? undefined,
1987
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
1988
+ title: this.getAttribute("title") ?? undefined
1989
+ });
1990
+ }
1991
+ disconnectedCallback() {
1992
+ this.mounted?.close();
1993
+ this.mounted = undefined;
1994
+ }
1995
+ });
1996
+ };
1828
1997
  // src/client/providerStatus.ts
1829
1998
  var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
1830
1999
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -1983,17 +2152,24 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
1983
2152
  };
1984
2153
  };
1985
2154
  export {
2155
+ renderVoiceRoutingStatusHTML,
1986
2156
  renderVoiceOpsStatusHTML,
2157
+ mountVoiceRoutingStatus,
1987
2158
  mountVoiceOpsStatus,
2159
+ getVoiceRoutingStatusCSS,
1988
2160
  getVoiceOpsStatusLabel,
1989
2161
  getVoiceOpsStatusCSS,
1990
2162
  fetchVoiceWorkflowStatus,
2163
+ fetchVoiceRoutingStatus,
1991
2164
  fetchVoiceProviderStatus,
1992
2165
  fetchVoiceAppKitStatus,
2166
+ defineVoiceRoutingStatusElement,
1993
2167
  defineVoiceOpsStatusElement,
1994
2168
  decodeVoiceAudioChunk,
1995
2169
  createVoiceWorkflowStatusStore,
1996
2170
  createVoiceStream,
2171
+ createVoiceRoutingStatusViewModel,
2172
+ createVoiceRoutingStatusStore,
1997
2173
  createVoiceProviderStatusStore,
1998
2174
  createVoiceOpsStatusViewModel,
1999
2175
  createVoiceDuplexController,
@@ -0,0 +1,19 @@
1
+ import type { VoiceRoutingDecisionSummary } from '../resilienceRoutes';
2
+ export type VoiceRoutingStatusClientOptions = {
3
+ fetch?: typeof fetch;
4
+ intervalMs?: number;
5
+ };
6
+ export type VoiceRoutingStatusSnapshot = {
7
+ decision: VoiceRoutingDecisionSummary | null;
8
+ error: string | null;
9
+ isLoading: boolean;
10
+ updatedAt?: number;
11
+ };
12
+ export declare const fetchVoiceRoutingStatus: (path?: string, options?: Pick<VoiceRoutingStatusClientOptions, "fetch">) => Promise<import("..").VoiceRoutingEvent | null>;
13
+ export declare const createVoiceRoutingStatusStore: (path?: string, options?: VoiceRoutingStatusClientOptions) => {
14
+ close: () => void;
15
+ getServerSnapshot: () => VoiceRoutingStatusSnapshot;
16
+ getSnapshot: () => VoiceRoutingStatusSnapshot;
17
+ refresh: () => Promise<import("..").VoiceRoutingEvent | null>;
18
+ subscribe: (listener: () => void) => () => void;
19
+ };
@@ -0,0 +1,28 @@
1
+ import type { VoiceRoutingDecisionSummary } from '../resilienceRoutes';
2
+ import { type VoiceRoutingStatusClientOptions, type VoiceRoutingStatusSnapshot } from './routingStatus';
3
+ export type VoiceRoutingStatusViewModel = {
4
+ decision: VoiceRoutingDecisionSummary | null;
5
+ description: string;
6
+ error: string | null;
7
+ isLoading: boolean;
8
+ label: string;
9
+ rows: Array<{
10
+ label: string;
11
+ value: string;
12
+ }>;
13
+ status: 'empty' | 'error' | 'loading' | 'ready';
14
+ title: string;
15
+ updatedAt?: number;
16
+ };
17
+ export type VoiceRoutingStatusWidgetOptions = VoiceRoutingStatusClientOptions & {
18
+ description?: string;
19
+ title?: string;
20
+ };
21
+ export declare const createVoiceRoutingStatusViewModel: (snapshot: VoiceRoutingStatusSnapshot, options?: VoiceRoutingStatusWidgetOptions) => VoiceRoutingStatusViewModel;
22
+ export declare const renderVoiceRoutingStatusHTML: (snapshot: VoiceRoutingStatusSnapshot, options?: VoiceRoutingStatusWidgetOptions) => string;
23
+ export declare const getVoiceRoutingStatusCSS: () => string;
24
+ export declare const mountVoiceRoutingStatus: (element: Element, path?: string, options?: VoiceRoutingStatusWidgetOptions) => {
25
+ close: () => void;
26
+ refresh: () => Promise<import("..").VoiceRoutingEvent | null>;
27
+ };
28
+ export declare const defineVoiceRoutingStatusElement: (tagName?: string) => void;
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export { createAnthropicVoiceAssistantModel, createGeminiVoiceAssistantModel, cr
13
13
  export { createVoiceProviderHealthHTMLHandler, createVoiceProviderHealthJSONHandler, createVoiceProviderHealthRoutes, renderVoiceProviderHealthHTML, summarizeVoiceProviderHealth } from './providerHealth';
14
14
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
15
15
  export { createVoiceQualityRoutes, evaluateVoiceQuality, renderVoiceQualityHTML } from './qualityRoutes';
16
- export { createVoiceResilienceRoutes, listVoiceRoutingEvents, renderVoiceResilienceHTML } from './resilienceRoutes';
16
+ export { createVoiceResilienceRoutes, createVoiceRoutingDecisionSummary, listVoiceRoutingEvents, renderVoiceResilienceHTML, summarizeVoiceRoutingDecision } from './resilienceRoutes';
17
17
  export { createVoiceSTTProviderRouter, createVoiceTTSProviderRouter } from './providerAdapters';
18
18
  export { buildVoiceTraceReplay, createVoiceMemoryTraceSinkDeliveryStore, createVoiceTraceHTTPSink, createVoiceMemoryTraceEventStore, createVoiceTraceSinkDeliveryId, createVoiceTraceSinkDeliveryRecord, createVoiceTraceSinkStore, createVoiceTraceEvent, createVoiceTraceEventId, deliverVoiceTraceEventsToSinks, evaluateVoiceTrace, exportVoiceTrace, filterVoiceTraceEvents, pruneVoiceTraceEvents, redactVoiceTraceEvent, redactVoiceTraceEvents, redactVoiceTraceText, renderVoiceTraceHTML, renderVoiceTraceMarkdown, resolveVoiceTraceRedactionOptions, selectVoiceTraceEventsForPrune, summarizeVoiceTrace } from './trace';
19
19
  export { createVoiceSQLiteExternalObjectMapStore, createVoiceSQLiteIntegrationEventStore, createVoiceSQLiteReviewStore, createVoiceSQLiteRuntimeStorage, createVoiceSQLiteSessionStore, createVoiceSQLiteTaskStore, createVoiceSQLiteTraceSinkDeliveryStore, createVoiceSQLiteTraceEventStore } from './sqliteStore';
@@ -50,7 +50,7 @@ export type { AnthropicVoiceAssistantModelOptions, GeminiVoiceAssistantModelOpti
50
50
  export type { VoiceProviderHealthStatus, VoiceProviderHealthSummary, VoiceProviderHealthSummaryOptions } from './providerHealth';
51
51
  export type { VoiceOpsConsoleLink, VoiceOpsConsoleReport, VoiceOpsConsoleRoutesOptions } from './opsConsoleRoutes';
52
52
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
53
- export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingEvent, VoiceRoutingEventKind } from './resilienceRoutes';
53
+ export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind } from './resilienceRoutes';
54
54
  export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions } from './providerAdapters';
55
55
  export type { VoiceAgent, VoiceAgentMessage, VoiceAgentMessageRole, VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput, VoiceAgentOptions, VoiceAgentRunResult, VoiceAgentSquadOptions, VoiceAgentTool, VoiceAgentToolCall, VoiceAgentToolResult } from './agent';
56
56
  export type { VoiceOpsRuntime, VoiceOpsRuntimeConfig, VoiceOpsRuntimeSummary, VoiceOpsRuntimeSinkWorkerConfig, VoiceOpsRuntimeTaskWorkerConfig, VoiceOpsRuntimeTickResult, VoiceOpsRuntimeWebhookWorkerConfig } from './opsRuntime';
package/dist/index.js CHANGED
@@ -8493,15 +8493,37 @@ var listVoiceRoutingEvents = (events) => {
8493
8493
  latencyBudgetMs: getNumber4(event.payload.latencyBudgetMs),
8494
8494
  operation: getString7(event.payload.operation),
8495
8495
  provider,
8496
+ routing: getString7(event.payload.routing),
8496
8497
  selectedProvider: getString7(event.payload.selectedProvider),
8497
8498
  sessionId: event.sessionId,
8498
8499
  status: providerStatus,
8500
+ suppressionRemainingMs: getNumber4(event.payload.suppressionRemainingMs),
8499
8501
  timedOut: getBoolean2(event.payload.timedOut),
8500
8502
  turnId: event.turnId
8501
8503
  });
8502
8504
  }
8503
8505
  return routingEvents.sort((left, right) => right.at - left.at);
8504
8506
  };
8507
+ var summarizeVoiceRoutingDecision = (events, options = {}) => {
8508
+ const routingEvents = listVoiceRoutingEvents(events).filter((event) => {
8509
+ if (options.kind && event.kind !== options.kind) {
8510
+ return false;
8511
+ }
8512
+ if (options.sessionId && event.sessionId !== options.sessionId) {
8513
+ return false;
8514
+ }
8515
+ return true;
8516
+ });
8517
+ const limited = typeof options.limit === "number" && options.limit >= 0 ? routingEvents.slice(0, options.limit) : routingEvents;
8518
+ return limited[0] ?? null;
8519
+ };
8520
+ var createVoiceRoutingDecisionSummary = async (options) => {
8521
+ const events = await options.store.list({
8522
+ sessionId: options.sessionId,
8523
+ type: "session.error"
8524
+ });
8525
+ return summarizeVoiceRoutingDecision(events, options);
8526
+ };
8505
8527
  var summarizeRoutingEvents = (events) => {
8506
8528
  const byKind = new Map;
8507
8529
  let errors = 0;
@@ -14080,6 +14102,7 @@ export {
14080
14102
  summarizeVoiceTrace,
14081
14103
  summarizeVoiceSessions,
14082
14104
  summarizeVoiceSessionReplay,
14105
+ summarizeVoiceRoutingDecision,
14083
14106
  summarizeVoiceProviderHealth,
14084
14107
  summarizeVoiceOpsTasks,
14085
14108
  summarizeVoiceOpsTaskQueue,
@@ -14194,6 +14217,7 @@ export {
14194
14217
  createVoiceSQLiteIntegrationEventStore,
14195
14218
  createVoiceSQLiteExternalObjectMapStore,
14196
14219
  createVoiceS3ReviewStore,
14220
+ createVoiceRoutingDecisionSummary,
14197
14221
  createVoiceReviewSavedEvent,
14198
14222
  createVoiceResilienceRoutes,
14199
14223
  createVoiceRedisTaskLeaseCoordinator,
@@ -0,0 +1,6 @@
1
+ import { type VoiceRoutingStatusWidgetOptions } from '../client/routingStatusWidget';
2
+ export type VoiceRoutingStatusProps = VoiceRoutingStatusWidgetOptions & {
3
+ className?: string;
4
+ path?: string;
5
+ };
6
+ export declare const VoiceRoutingStatus: ({ className, path, ...options }: VoiceRoutingStatusProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,8 @@
1
1
  export { VoiceOpsStatus } from './VoiceOpsStatus';
2
+ export { VoiceRoutingStatus } from './VoiceRoutingStatus';
2
3
  export { useVoiceAppKitStatus } from './useVoiceAppKitStatus';
3
4
  export { useVoiceStream } from './useVoiceStream';
4
5
  export { useVoiceController } from './useVoiceController';
5
6
  export { useVoiceProviderStatus } from './useVoiceProviderStatus';
7
+ export { useVoiceRoutingStatus } from './useVoiceRoutingStatus';
6
8
  export { useVoiceWorkflowStatus } from './useVoiceWorkflowStatus';