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

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.
@@ -1,6 +1,7 @@
1
1
  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
+ export { VoiceProviderCapabilitiesService } from './voice-provider-capabilities.service';
4
5
  export { VoiceProviderStatusService } from './voice-provider-status.service';
5
6
  export { VoiceRoutingStatusService } from './voice-routing-status.service';
6
7
  export { VoiceWorkflowStatusService } from './voice-workflow-status.service';
@@ -1458,9 +1458,131 @@ VoiceControllerService = __decorateElement(_init, 0, "VoiceControllerService", _
1458
1458
  __runInitializers(_init, 1, VoiceControllerService);
1459
1459
  __decoratorMetadata(_init, VoiceControllerService);
1460
1460
  let _VoiceControllerService = VoiceControllerService;
1461
- // src/angular/voice-provider-status.service.ts
1461
+ // src/angular/voice-provider-capabilities.service.ts
1462
1462
  import { computed as computed4, Injectable as Injectable4, signal as signal4 } from "@angular/core";
1463
1463
 
1464
+ // src/client/providerCapabilities.ts
1465
+ var fetchVoiceProviderCapabilities = async (path = "/api/provider-capabilities", options = {}) => {
1466
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1467
+ const response = await fetchImpl(path);
1468
+ if (!response.ok) {
1469
+ throw new Error(`Voice provider capabilities failed: HTTP ${response.status}`);
1470
+ }
1471
+ return await response.json();
1472
+ };
1473
+ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities", options = {}) => {
1474
+ const listeners = new Set;
1475
+ let closed = false;
1476
+ let timer;
1477
+ let snapshot = {
1478
+ error: null,
1479
+ isLoading: false
1480
+ };
1481
+ const emit = () => {
1482
+ for (const listener of listeners) {
1483
+ listener();
1484
+ }
1485
+ };
1486
+ const refresh = async () => {
1487
+ if (closed) {
1488
+ return snapshot.report;
1489
+ }
1490
+ snapshot = {
1491
+ ...snapshot,
1492
+ error: null,
1493
+ isLoading: true
1494
+ };
1495
+ emit();
1496
+ try {
1497
+ const report = await fetchVoiceProviderCapabilities(path, options);
1498
+ snapshot = {
1499
+ error: null,
1500
+ isLoading: false,
1501
+ report,
1502
+ updatedAt: Date.now()
1503
+ };
1504
+ emit();
1505
+ return report;
1506
+ } catch (error) {
1507
+ snapshot = {
1508
+ ...snapshot,
1509
+ error: error instanceof Error ? error.message : String(error),
1510
+ isLoading: false
1511
+ };
1512
+ emit();
1513
+ throw error;
1514
+ }
1515
+ };
1516
+ const close = () => {
1517
+ closed = true;
1518
+ if (timer) {
1519
+ clearInterval(timer);
1520
+ timer = undefined;
1521
+ }
1522
+ listeners.clear();
1523
+ };
1524
+ if (options.intervalMs && options.intervalMs > 0) {
1525
+ timer = setInterval(() => {
1526
+ refresh().catch(() => {});
1527
+ }, options.intervalMs);
1528
+ }
1529
+ return {
1530
+ close,
1531
+ getServerSnapshot: () => snapshot,
1532
+ getSnapshot: () => snapshot,
1533
+ refresh,
1534
+ subscribe: (listener) => {
1535
+ listeners.add(listener);
1536
+ return () => {
1537
+ listeners.delete(listener);
1538
+ };
1539
+ }
1540
+ };
1541
+ };
1542
+
1543
+ // src/angular/voice-provider-capabilities.service.ts
1544
+ var _dec = [
1545
+ Injectable4({ providedIn: "root" })
1546
+ ];
1547
+ var _init = __decoratorStart(undefined);
1548
+
1549
+ class VoiceProviderCapabilitiesService {
1550
+ connect(path = "/api/provider-capabilities", options = {}) {
1551
+ const store = createVoiceProviderCapabilitiesStore(path, options);
1552
+ const errorSignal = signal4(null);
1553
+ const isLoadingSignal = signal4(false);
1554
+ const reportSignal = signal4(undefined);
1555
+ const updatedAtSignal = signal4(undefined);
1556
+ const sync = () => {
1557
+ const snapshot = store.getSnapshot();
1558
+ errorSignal.set(snapshot.error);
1559
+ isLoadingSignal.set(snapshot.isLoading);
1560
+ reportSignal.set(snapshot.report);
1561
+ updatedAtSignal.set(snapshot.updatedAt);
1562
+ };
1563
+ const unsubscribe = store.subscribe(sync);
1564
+ sync();
1565
+ store.refresh().catch(() => {});
1566
+ return {
1567
+ close: () => {
1568
+ unsubscribe();
1569
+ store.close();
1570
+ },
1571
+ error: computed4(() => errorSignal()),
1572
+ isLoading: computed4(() => isLoadingSignal()),
1573
+ refresh: store.refresh,
1574
+ report: computed4(() => reportSignal()),
1575
+ updatedAt: computed4(() => updatedAtSignal())
1576
+ };
1577
+ }
1578
+ }
1579
+ VoiceProviderCapabilitiesService = __decorateElement(_init, 0, "VoiceProviderCapabilitiesService", _dec, VoiceProviderCapabilitiesService);
1580
+ __runInitializers(_init, 1, VoiceProviderCapabilitiesService);
1581
+ __decoratorMetadata(_init, VoiceProviderCapabilitiesService);
1582
+ let _VoiceProviderCapabilitiesService = VoiceProviderCapabilitiesService;
1583
+ // src/angular/voice-provider-status.service.ts
1584
+ import { computed as computed5, Injectable as Injectable5, signal as signal5 } from "@angular/core";
1585
+
1464
1586
  // src/client/providerStatus.ts
1465
1587
  var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
1466
1588
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -1543,17 +1665,17 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1543
1665
 
1544
1666
  // src/angular/voice-provider-status.service.ts
1545
1667
  var _dec = [
1546
- Injectable4({ providedIn: "root" })
1668
+ Injectable5({ providedIn: "root" })
1547
1669
  ];
1548
1670
  var _init = __decoratorStart(undefined);
1549
1671
 
1550
1672
  class VoiceProviderStatusService {
1551
1673
  connect(path = "/api/provider-status", options = {}) {
1552
1674
  const store = createVoiceProviderStatusStore(path, options);
1553
- const errorSignal = signal4(null);
1554
- const isLoadingSignal = signal4(false);
1555
- const providersSignal = signal4([]);
1556
- const updatedAtSignal = signal4(undefined);
1675
+ const errorSignal = signal5(null);
1676
+ const isLoadingSignal = signal5(false);
1677
+ const providersSignal = signal5([]);
1678
+ const updatedAtSignal = signal5(undefined);
1557
1679
  const sync = () => {
1558
1680
  const snapshot = store.getSnapshot();
1559
1681
  errorSignal.set(snapshot.error);
@@ -1569,11 +1691,11 @@ class VoiceProviderStatusService {
1569
1691
  unsubscribe();
1570
1692
  store.close();
1571
1693
  },
1572
- error: computed4(() => errorSignal()),
1573
- isLoading: computed4(() => isLoadingSignal()),
1574
- providers: computed4(() => providersSignal()),
1694
+ error: computed5(() => errorSignal()),
1695
+ isLoading: computed5(() => isLoadingSignal()),
1696
+ providers: computed5(() => providersSignal()),
1575
1697
  refresh: store.refresh,
1576
- updatedAt: computed4(() => updatedAtSignal())
1698
+ updatedAt: computed5(() => updatedAtSignal())
1577
1699
  };
1578
1700
  }
1579
1701
  }
@@ -1582,7 +1704,7 @@ __runInitializers(_init, 1, VoiceProviderStatusService);
1582
1704
  __decoratorMetadata(_init, VoiceProviderStatusService);
1583
1705
  let _VoiceProviderStatusService = VoiceProviderStatusService;
1584
1706
  // src/angular/voice-routing-status.service.ts
1585
- import { Injectable as Injectable5, signal as signal5 } from "@angular/core";
1707
+ import { Injectable as Injectable6, signal as signal6 } from "@angular/core";
1586
1708
 
1587
1709
  // src/client/routingStatus.ts
1588
1710
  var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
@@ -1666,17 +1788,17 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
1666
1788
 
1667
1789
  // src/angular/voice-routing-status.service.ts
1668
1790
  var _dec = [
1669
- Injectable5({ providedIn: "root" })
1791
+ Injectable6({ providedIn: "root" })
1670
1792
  ];
1671
1793
  var _init = __decoratorStart(undefined);
1672
1794
 
1673
1795
  class VoiceRoutingStatusService {
1674
1796
  connect(path = "/api/routing/latest", options = {}) {
1675
1797
  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);
1798
+ const decisionSignal = signal6(null);
1799
+ const errorSignal = signal6(null);
1800
+ const isLoadingSignal = signal6(false);
1801
+ const updatedAtSignal = signal6(undefined);
1680
1802
  const sync = () => {
1681
1803
  const snapshot = store.getSnapshot();
1682
1804
  decisionSignal.set(snapshot.decision);
@@ -1705,7 +1827,7 @@ __runInitializers(_init, 1, VoiceRoutingStatusService);
1705
1827
  __decoratorMetadata(_init, VoiceRoutingStatusService);
1706
1828
  let _VoiceRoutingStatusService = VoiceRoutingStatusService;
1707
1829
  // src/angular/voice-workflow-status.service.ts
1708
- import { computed as computed5, Injectable as Injectable6, signal as signal6 } from "@angular/core";
1830
+ import { computed as computed6, Injectable as Injectable7, signal as signal7 } from "@angular/core";
1709
1831
 
1710
1832
  // src/client/workflowStatus.ts
1711
1833
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
@@ -1788,17 +1910,17 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
1788
1910
 
1789
1911
  // src/angular/voice-workflow-status.service.ts
1790
1912
  var _dec = [
1791
- Injectable6({ providedIn: "root" })
1913
+ Injectable7({ providedIn: "root" })
1792
1914
  ];
1793
1915
  var _init = __decoratorStart(undefined);
1794
1916
 
1795
1917
  class VoiceWorkflowStatusService {
1796
1918
  connect(path = "/evals/scenarios/json", options = {}) {
1797
1919
  const store = createVoiceWorkflowStatusStore(path, options);
1798
- const errorSignal = signal6(null);
1799
- const isLoadingSignal = signal6(false);
1800
- const reportSignal = signal6(undefined);
1801
- const updatedAtSignal = signal6(undefined);
1920
+ const errorSignal = signal7(null);
1921
+ const isLoadingSignal = signal7(false);
1922
+ const reportSignal = signal7(undefined);
1923
+ const updatedAtSignal = signal7(undefined);
1802
1924
  const sync = () => {
1803
1925
  const snapshot = store.getSnapshot();
1804
1926
  errorSignal.set(snapshot.error);
@@ -1816,11 +1938,11 @@ class VoiceWorkflowStatusService {
1816
1938
  unsubscribe();
1817
1939
  store.close();
1818
1940
  },
1819
- error: computed5(() => errorSignal()),
1820
- isLoading: computed5(() => isLoadingSignal()),
1941
+ error: computed6(() => errorSignal()),
1942
+ isLoading: computed6(() => isLoadingSignal()),
1821
1943
  refresh: store.refresh,
1822
- report: computed5(() => reportSignal()),
1823
- updatedAt: computed5(() => updatedAtSignal())
1944
+ report: computed6(() => reportSignal()),
1945
+ updatedAt: computed6(() => updatedAtSignal())
1824
1946
  };
1825
1947
  }
1826
1948
  }
@@ -1833,6 +1955,7 @@ export {
1833
1955
  VoiceStreamService,
1834
1956
  VoiceRoutingStatusService,
1835
1957
  VoiceProviderStatusService,
1958
+ VoiceProviderCapabilitiesService,
1836
1959
  VoiceControllerService,
1837
1960
  VoiceAppKitStatusService
1838
1961
  };
@@ -0,0 +1,12 @@
1
+ import { type VoiceProviderCapabilitiesClientOptions } from '../client/providerCapabilities';
2
+ import type { VoiceProviderCapabilityReport } from '../providerCapabilities';
3
+ export declare class VoiceProviderCapabilitiesService {
4
+ connect<TProvider extends string = string>(path?: string, options?: VoiceProviderCapabilitiesClientOptions): {
5
+ close: () => void;
6
+ error: import("@angular/core").Signal<string | null>;
7
+ isLoading: import("@angular/core").Signal<boolean>;
8
+ refresh: () => Promise<VoiceProviderCapabilityReport<TProvider> | undefined>;
9
+ report: import("@angular/core").Signal<VoiceProviderCapabilityReport<TProvider> | undefined>;
10
+ updatedAt: import("@angular/core").Signal<number | undefined>;
11
+ };
12
+ }
@@ -10,16 +10,20 @@ export { createVoiceOpsStatusViewModel, defineVoiceOpsStatusElement, getVoiceOps
10
10
  export { createVoiceRoutingStatusStore, fetchVoiceRoutingStatus } from './routingStatus';
11
11
  export { createVoiceRoutingStatusViewModel, defineVoiceRoutingStatusElement, getVoiceRoutingStatusCSS, mountVoiceRoutingStatus, renderVoiceRoutingStatusHTML } from './routingStatusWidget';
12
12
  export { createVoiceProviderStatusStore, fetchVoiceProviderStatus } from './providerStatus';
13
+ export { createVoiceProviderCapabilitiesStore, fetchVoiceProviderCapabilities } from './providerCapabilities';
13
14
  export { createVoiceProviderSimulationControlsStore } from './providerSimulationControls';
14
15
  export { bindVoiceProviderSimulationControls, createVoiceProviderSimulationControlsViewModel, defineVoiceProviderSimulationControlsElement, mountVoiceProviderSimulationControls, renderVoiceProviderSimulationControlsHTML } from './providerSimulationControlsWidget';
15
16
  export { createVoiceProviderStatusViewModel, defineVoiceProviderStatusElement, getVoiceProviderStatusCSS, mountVoiceProviderStatus, renderVoiceProviderStatusHTML } from './providerStatusWidget';
17
+ export { createVoiceProviderCapabilitiesViewModel, defineVoiceProviderCapabilitiesElement, getVoiceProviderCapabilitiesCSS, mountVoiceProviderCapabilities, renderVoiceProviderCapabilitiesHTML } from './providerCapabilitiesWidget';
16
18
  export { createVoiceWorkflowStatusStore, fetchVoiceWorkflowStatus } from './workflowStatus';
17
19
  export type { VoiceAppKitStatusClientOptions, VoiceAppKitStatusSnapshot } from './appKitStatus';
18
20
  export type { VoiceOpsStatusSurfaceView, VoiceOpsStatusViewModel, VoiceOpsStatusWidgetOptions } from './opsStatusWidget';
19
21
  export type { VoiceRoutingStatusClientOptions, VoiceRoutingStatusSnapshot } from './routingStatus';
20
22
  export type { VoiceRoutingStatusViewModel, VoiceRoutingStatusWidgetOptions } from './routingStatusWidget';
21
23
  export type { VoiceProviderStatusClientOptions, VoiceProviderStatusSnapshot } from './providerStatus';
24
+ export type { VoiceProviderCapabilitiesClientOptions, VoiceProviderCapabilitiesSnapshot } from './providerCapabilities';
22
25
  export type { VoiceProviderSimulationControlsOptions, VoiceProviderSimulationControlsSnapshot, VoiceProviderSimulationProvider } from './providerSimulationControls';
23
26
  export type { VoiceProviderSimulationControlsViewModel } from './providerSimulationControlsWidget';
24
27
  export type { VoiceProviderStatusCardView, VoiceProviderStatusViewModel, VoiceProviderStatusWidgetOptions } from './providerStatusWidget';
28
+ export type { VoiceProviderCapabilitiesViewModel, VoiceProviderCapabilitiesWidgetOptions, VoiceProviderCapabilityCardView } from './providerCapabilitiesWidget';
25
29
  export type { VoiceWorkflowStatusClientOptions, VoiceWorkflowStatusSnapshot } from './workflowStatus';
@@ -2073,6 +2073,84 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
2073
2073
  }
2074
2074
  };
2075
2075
  };
2076
+ // src/client/providerCapabilities.ts
2077
+ var fetchVoiceProviderCapabilities = async (path = "/api/provider-capabilities", options = {}) => {
2078
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2079
+ const response = await fetchImpl(path);
2080
+ if (!response.ok) {
2081
+ throw new Error(`Voice provider capabilities failed: HTTP ${response.status}`);
2082
+ }
2083
+ return await response.json();
2084
+ };
2085
+ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities", options = {}) => {
2086
+ const listeners = new Set;
2087
+ let closed = false;
2088
+ let timer;
2089
+ let snapshot = {
2090
+ error: null,
2091
+ isLoading: false
2092
+ };
2093
+ const emit = () => {
2094
+ for (const listener of listeners) {
2095
+ listener();
2096
+ }
2097
+ };
2098
+ const refresh = async () => {
2099
+ if (closed) {
2100
+ return snapshot.report;
2101
+ }
2102
+ snapshot = {
2103
+ ...snapshot,
2104
+ error: null,
2105
+ isLoading: true
2106
+ };
2107
+ emit();
2108
+ try {
2109
+ const report = await fetchVoiceProviderCapabilities(path, options);
2110
+ snapshot = {
2111
+ error: null,
2112
+ isLoading: false,
2113
+ report,
2114
+ updatedAt: Date.now()
2115
+ };
2116
+ emit();
2117
+ return report;
2118
+ } catch (error) {
2119
+ snapshot = {
2120
+ ...snapshot,
2121
+ error: error instanceof Error ? error.message : String(error),
2122
+ isLoading: false
2123
+ };
2124
+ emit();
2125
+ throw error;
2126
+ }
2127
+ };
2128
+ const close = () => {
2129
+ closed = true;
2130
+ if (timer) {
2131
+ clearInterval(timer);
2132
+ timer = undefined;
2133
+ }
2134
+ listeners.clear();
2135
+ };
2136
+ if (options.intervalMs && options.intervalMs > 0) {
2137
+ timer = setInterval(() => {
2138
+ refresh().catch(() => {});
2139
+ }, options.intervalMs);
2140
+ }
2141
+ return {
2142
+ close,
2143
+ getServerSnapshot: () => snapshot,
2144
+ getSnapshot: () => snapshot,
2145
+ refresh,
2146
+ subscribe: (listener) => {
2147
+ listeners.add(listener);
2148
+ return () => {
2149
+ listeners.delete(listener);
2150
+ };
2151
+ }
2152
+ };
2153
+ };
2076
2154
  // src/client/providerSimulationControls.ts
2077
2155
  var postSimulation = async (pathPrefix, mode, provider, fetchImpl) => {
2078
2156
  const response = await fetchImpl(`${pathPrefix}/${mode}?provider=${encodeURIComponent(provider)}`, { method: "POST" });
@@ -2364,6 +2442,122 @@ var defineVoiceProviderStatusElement = (tagName = "absolute-voice-provider-statu
2364
2442
  }
2365
2443
  });
2366
2444
  };
2445
+ // src/client/providerCapabilitiesWidget.ts
2446
+ var DEFAULT_TITLE4 = "Provider Capabilities";
2447
+ var DEFAULT_DESCRIPTION4 = "Configured, selected, and healthy voice providers for this deployment.";
2448
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2449
+ var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2450
+ var formatKind2 = (kind) => kind.toUpperCase();
2451
+ var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
2452
+ var getCapabilityDetail = (capability) => {
2453
+ if (!capability.configured) {
2454
+ return "Not configured in this deployment.";
2455
+ }
2456
+ if (capability.selected) {
2457
+ return `Selected ${capability.kind.toUpperCase()} provider for new sessions.`;
2458
+ }
2459
+ if (capability.health?.status === "healthy") {
2460
+ return "Configured and healthy fallback candidate.";
2461
+ }
2462
+ if (capability.health?.status === "idle") {
2463
+ return "Configured; no traffic observed yet.";
2464
+ }
2465
+ if (capability.health?.lastError) {
2466
+ return capability.health.lastError;
2467
+ }
2468
+ return "Configured and available.";
2469
+ };
2470
+ var isWarningStatus2 = (status) => status === "degraded" || status === "rate-limited" || status === "suppressed" || status === "unconfigured";
2471
+ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
2472
+ const capabilities = (snapshot.report?.capabilities ?? []).map((capability) => ({
2473
+ ...capability,
2474
+ detail: getCapabilityDetail(capability),
2475
+ label: `${formatProvider2(capability.provider)} ${formatKind2(capability.kind)}`,
2476
+ rows: [
2477
+ { label: "Status", value: formatStatus2(capability.status) },
2478
+ { label: "Selected", value: capability.selected ? "Yes" : "No" },
2479
+ { label: "Model", value: capability.model ?? "Default" },
2480
+ {
2481
+ label: "Features",
2482
+ value: capability.features?.join(", ") || "Not specified"
2483
+ },
2484
+ { label: "Runs", value: String(capability.health?.runCount ?? 0) },
2485
+ { label: "Errors", value: String(capability.health?.errorCount ?? 0) }
2486
+ ]
2487
+ }));
2488
+ const warningCount = capabilities.filter((capability) => isWarningStatus2(capability.status)).length;
2489
+ const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
2490
+ return {
2491
+ capabilities,
2492
+ description: options.description ?? DEFAULT_DESCRIPTION4,
2493
+ error: snapshot.error,
2494
+ isLoading: snapshot.isLoading,
2495
+ label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
2496
+ status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2497
+ title: options.title ?? DEFAULT_TITLE4,
2498
+ updatedAt: snapshot.updatedAt
2499
+ };
2500
+ };
2501
+ var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
2502
+ const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
2503
+ 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)}">
2504
+ <header>
2505
+ <strong>${escapeHtml5(capability.label)}</strong>
2506
+ <span>${escapeHtml5(formatStatus2(capability.status))}</span>
2507
+ </header>
2508
+ <p>${escapeHtml5(capability.detail)}</p>
2509
+ <dl>${capability.rows.map((row) => `<div>
2510
+ <dt>${escapeHtml5(row.label)}</dt>
2511
+ <dd>${escapeHtml5(row.value)}</dd>
2512
+ </div>`).join("")}</dl>
2513
+ </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
2514
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml5(model.status)}">
2515
+ <header class="absolute-voice-provider-capabilities__header">
2516
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml5(model.title)}</span>
2517
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml5(model.label)}</strong>
2518
+ </header>
2519
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml5(model.description)}</p>
2520
+ ${capabilities}
2521
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml5(model.error)}</p>` : ""}
2522
+ </section>`;
2523
+ };
2524
+ 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}`;
2525
+ var mountVoiceProviderCapabilities = (element, path = "/api/provider-capabilities", options = {}) => {
2526
+ const store = createVoiceProviderCapabilitiesStore(path, options);
2527
+ const render = () => {
2528
+ element.innerHTML = renderVoiceProviderCapabilitiesHTML(store.getSnapshot(), options);
2529
+ };
2530
+ const unsubscribe = store.subscribe(render);
2531
+ render();
2532
+ store.refresh().catch(() => {});
2533
+ return {
2534
+ close: () => {
2535
+ unsubscribe();
2536
+ store.close();
2537
+ },
2538
+ refresh: store.refresh
2539
+ };
2540
+ };
2541
+ var defineVoiceProviderCapabilitiesElement = (tagName = "absolute-voice-provider-capabilities") => {
2542
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
2543
+ return;
2544
+ }
2545
+ customElements.define(tagName, class AbsoluteVoiceProviderCapabilitiesElement extends HTMLElement {
2546
+ mounted;
2547
+ connectedCallback() {
2548
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
2549
+ this.mounted = mountVoiceProviderCapabilities(this, this.getAttribute("path") ?? "/api/provider-capabilities", {
2550
+ description: this.getAttribute("description") ?? undefined,
2551
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
2552
+ title: this.getAttribute("title") ?? undefined
2553
+ });
2554
+ }
2555
+ disconnectedCallback() {
2556
+ this.mounted?.close();
2557
+ this.mounted = undefined;
2558
+ }
2559
+ });
2560
+ };
2367
2561
  // src/client/workflowStatus.ts
2368
2562
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
2369
2563
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -2446,22 +2640,27 @@ export {
2446
2640
  renderVoiceRoutingStatusHTML,
2447
2641
  renderVoiceProviderStatusHTML,
2448
2642
  renderVoiceProviderSimulationControlsHTML,
2643
+ renderVoiceProviderCapabilitiesHTML,
2449
2644
  renderVoiceOpsStatusHTML,
2450
2645
  mountVoiceRoutingStatus,
2451
2646
  mountVoiceProviderStatus,
2452
2647
  mountVoiceProviderSimulationControls,
2648
+ mountVoiceProviderCapabilities,
2453
2649
  mountVoiceOpsStatus,
2454
2650
  getVoiceRoutingStatusCSS,
2455
2651
  getVoiceProviderStatusCSS,
2652
+ getVoiceProviderCapabilitiesCSS,
2456
2653
  getVoiceOpsStatusLabel,
2457
2654
  getVoiceOpsStatusCSS,
2458
2655
  fetchVoiceWorkflowStatus,
2459
2656
  fetchVoiceRoutingStatus,
2460
2657
  fetchVoiceProviderStatus,
2658
+ fetchVoiceProviderCapabilities,
2461
2659
  fetchVoiceAppKitStatus,
2462
2660
  defineVoiceRoutingStatusElement,
2463
2661
  defineVoiceProviderStatusElement,
2464
2662
  defineVoiceProviderSimulationControlsElement,
2663
+ defineVoiceProviderCapabilitiesElement,
2465
2664
  defineVoiceOpsStatusElement,
2466
2665
  decodeVoiceAudioChunk,
2467
2666
  createVoiceWorkflowStatusStore,
@@ -2472,6 +2671,8 @@ export {
2472
2671
  createVoiceProviderStatusStore,
2473
2672
  createVoiceProviderSimulationControlsViewModel,
2474
2673
  createVoiceProviderSimulationControlsStore,
2674
+ createVoiceProviderCapabilitiesViewModel,
2675
+ createVoiceProviderCapabilitiesStore,
2475
2676
  createVoiceOpsStatusViewModel,
2476
2677
  createVoiceDuplexController,
2477
2678
  createVoiceController,
@@ -0,0 +1,19 @@
1
+ import type { VoiceProviderCapabilityReport } from '../providerCapabilities';
2
+ export type VoiceProviderCapabilitiesClientOptions = {
3
+ fetch?: typeof fetch;
4
+ intervalMs?: number;
5
+ };
6
+ export type VoiceProviderCapabilitiesSnapshot<TProvider extends string = string> = {
7
+ error: string | null;
8
+ isLoading: boolean;
9
+ report?: VoiceProviderCapabilityReport<TProvider>;
10
+ updatedAt?: number;
11
+ };
12
+ export declare const fetchVoiceProviderCapabilities: <TProvider extends string = string>(path?: string, options?: Pick<VoiceProviderCapabilitiesClientOptions, "fetch">) => Promise<VoiceProviderCapabilityReport<TProvider>>;
13
+ export declare const createVoiceProviderCapabilitiesStore: <TProvider extends string = string>(path?: string, options?: VoiceProviderCapabilitiesClientOptions) => {
14
+ close: () => void;
15
+ getServerSnapshot: () => VoiceProviderCapabilitiesSnapshot<TProvider>;
16
+ getSnapshot: () => VoiceProviderCapabilitiesSnapshot<TProvider>;
17
+ refresh: () => Promise<VoiceProviderCapabilityReport<TProvider> | undefined>;
18
+ subscribe: (listener: () => void) => () => void;
19
+ };
@@ -0,0 +1,32 @@
1
+ import type { VoiceProviderCapabilitySummary } from '../providerCapabilities';
2
+ import { type VoiceProviderCapabilitiesClientOptions, type VoiceProviderCapabilitiesSnapshot } from './providerCapabilities';
3
+ export type VoiceProviderCapabilityCardView<TProvider extends string = string> = VoiceProviderCapabilitySummary<TProvider> & {
4
+ detail: string;
5
+ label: string;
6
+ rows: Array<{
7
+ label: string;
8
+ value: string;
9
+ }>;
10
+ };
11
+ export type VoiceProviderCapabilitiesViewModel<TProvider extends string = string> = {
12
+ capabilities: VoiceProviderCapabilityCardView<TProvider>[];
13
+ description: string;
14
+ error: string | null;
15
+ isLoading: boolean;
16
+ label: string;
17
+ status: 'empty' | 'error' | 'loading' | 'ready' | 'warning';
18
+ title: string;
19
+ updatedAt?: number;
20
+ };
21
+ export type VoiceProviderCapabilitiesWidgetOptions = VoiceProviderCapabilitiesClientOptions & {
22
+ description?: string;
23
+ title?: string;
24
+ };
25
+ export declare const createVoiceProviderCapabilitiesViewModel: <TProvider extends string = string>(snapshot: VoiceProviderCapabilitiesSnapshot<TProvider>, options?: VoiceProviderCapabilitiesWidgetOptions) => VoiceProviderCapabilitiesViewModel<TProvider>;
26
+ export declare const renderVoiceProviderCapabilitiesHTML: <TProvider extends string = string>(snapshot: VoiceProviderCapabilitiesSnapshot<TProvider>, options?: VoiceProviderCapabilitiesWidgetOptions) => string;
27
+ export declare const getVoiceProviderCapabilitiesCSS: () => string;
28
+ export declare const mountVoiceProviderCapabilities: <TProvider extends string = string>(element: Element, path?: string, options?: VoiceProviderCapabilitiesWidgetOptions) => {
29
+ close: () => void;
30
+ refresh: () => Promise<import("..").VoiceProviderCapabilityReport<TProvider> | undefined>;
31
+ };
32
+ export declare const defineVoiceProviderCapabilitiesElement: (tagName?: string) => void;
@@ -0,0 +1,6 @@
1
+ import { type VoiceProviderCapabilitiesWidgetOptions } from '../client/providerCapabilitiesWidget';
2
+ export type VoiceProviderCapabilitiesProps = VoiceProviderCapabilitiesWidgetOptions & {
3
+ className?: string;
4
+ path?: string;
5
+ };
6
+ export declare const VoiceProviderCapabilities: ({ className, path, ...options }: VoiceProviderCapabilitiesProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,11 +1,13 @@
1
1
  export { VoiceOpsStatus } from './VoiceOpsStatus';
2
2
  export { VoiceProviderSimulationControls } from './VoiceProviderSimulationControls';
3
+ export { VoiceProviderCapabilities } from './VoiceProviderCapabilities';
3
4
  export { VoiceProviderStatus } from './VoiceProviderStatus';
4
5
  export { VoiceRoutingStatus } from './VoiceRoutingStatus';
5
6
  export { useVoiceAppKitStatus } from './useVoiceAppKitStatus';
6
7
  export { useVoiceStream } from './useVoiceStream';
7
8
  export { useVoiceController } from './useVoiceController';
8
9
  export { useVoiceProviderStatus } from './useVoiceProviderStatus';
10
+ export { useVoiceProviderCapabilities } from './useVoiceProviderCapabilities';
9
11
  export { useVoiceProviderSimulationControls } from './useVoiceProviderSimulationControls';
10
12
  export { useVoiceRoutingStatus } from './useVoiceRoutingStatus';
11
13
  export { useVoiceWorkflowStatus } from './useVoiceWorkflowStatus';