@absolutejs/voice 0.0.22-beta.60 → 0.0.22-beta.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +2 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +192 -12
- package/dist/client/providerSimulationControls.d.ts +33 -0
- package/dist/client/providerSimulationControlsWidget.d.ts +20 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +228 -8
- package/dist/react/VoiceProviderSimulationControls.d.ts +5 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +341 -70
- package/dist/react/useVoiceProviderSimulationControls.d.ts +10 -0
- package/dist/svelte/createVoiceProviderSimulationControls.d.ts +11 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +207 -20
- package/dist/toolRuntime.d.ts +50 -0
- package/dist/vue/VoiceProviderSimulationControls.d.ts +88 -0
- package/dist/vue/index.d.ts +2 -0
- package/dist/vue/index.js +374 -82
- package/dist/vue/useVoiceProviderSimulationControls.d.ts +24 -0
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -387,8 +387,277 @@ var VoiceOpsStatus = ({
|
|
|
387
387
|
]
|
|
388
388
|
}, undefined, true, undefined, this);
|
|
389
389
|
};
|
|
390
|
-
// src/
|
|
390
|
+
// src/client/providerSimulationControls.ts
|
|
391
|
+
var postSimulation = async (pathPrefix, mode, provider, fetchImpl) => {
|
|
392
|
+
const response = await fetchImpl(`${pathPrefix}/${mode}?provider=${encodeURIComponent(provider)}`, { method: "POST" });
|
|
393
|
+
const body = await response.json().catch(() => null);
|
|
394
|
+
if (!response.ok) {
|
|
395
|
+
const message = body && typeof body === "object" && "error" in body ? String(body.error) : `Voice provider simulation failed: HTTP ${response.status}`;
|
|
396
|
+
throw new Error(message);
|
|
397
|
+
}
|
|
398
|
+
return body;
|
|
399
|
+
};
|
|
400
|
+
var createVoiceProviderSimulationControlsStore = (options) => {
|
|
401
|
+
const listeners = new Set;
|
|
402
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
403
|
+
const pathPrefix = options.pathPrefix ?? `/api/${options.kind ?? "stt"}-simulate`;
|
|
404
|
+
let closed = false;
|
|
405
|
+
let snapshot = {
|
|
406
|
+
error: null,
|
|
407
|
+
isRunning: false,
|
|
408
|
+
lastResult: null,
|
|
409
|
+
mode: null,
|
|
410
|
+
provider: null
|
|
411
|
+
};
|
|
412
|
+
const emit = () => {
|
|
413
|
+
for (const listener of listeners) {
|
|
414
|
+
listener();
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
const run = async (provider, mode) => {
|
|
418
|
+
if (closed) {
|
|
419
|
+
return snapshot.lastResult;
|
|
420
|
+
}
|
|
421
|
+
snapshot = {
|
|
422
|
+
...snapshot,
|
|
423
|
+
error: null,
|
|
424
|
+
isRunning: true,
|
|
425
|
+
mode,
|
|
426
|
+
provider
|
|
427
|
+
};
|
|
428
|
+
emit();
|
|
429
|
+
try {
|
|
430
|
+
const result = await postSimulation(pathPrefix, mode, provider, fetchImpl);
|
|
431
|
+
snapshot = {
|
|
432
|
+
error: null,
|
|
433
|
+
isRunning: false,
|
|
434
|
+
lastResult: result,
|
|
435
|
+
mode,
|
|
436
|
+
provider,
|
|
437
|
+
updatedAt: Date.now()
|
|
438
|
+
};
|
|
439
|
+
emit();
|
|
440
|
+
return result;
|
|
441
|
+
} catch (error) {
|
|
442
|
+
snapshot = {
|
|
443
|
+
...snapshot,
|
|
444
|
+
error: error instanceof Error ? error.message : String(error),
|
|
445
|
+
isRunning: false
|
|
446
|
+
};
|
|
447
|
+
emit();
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
const close = () => {
|
|
452
|
+
closed = true;
|
|
453
|
+
listeners.clear();
|
|
454
|
+
};
|
|
455
|
+
return {
|
|
456
|
+
close,
|
|
457
|
+
getServerSnapshot: () => snapshot,
|
|
458
|
+
getSnapshot: () => snapshot,
|
|
459
|
+
run,
|
|
460
|
+
subscribe: (listener) => {
|
|
461
|
+
listeners.add(listener);
|
|
462
|
+
return () => {
|
|
463
|
+
listeners.delete(listener);
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// src/client/providerSimulationControlsWidget.ts
|
|
470
|
+
var escapeHtml2 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
471
|
+
var formatKind = (kind) => (kind ?? "stt").toUpperCase();
|
|
472
|
+
var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
473
|
+
const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
|
|
474
|
+
const fallbackReady = !options.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === options.fallbackRequiredProvider);
|
|
475
|
+
const failureProviders = (options.failureProviders ? options.failureProviders.map((provider) => ({ provider })) : configuredProviders).filter((provider) => configuredProviders.some((entry) => entry.provider === provider.provider));
|
|
476
|
+
return {
|
|
477
|
+
canSimulateFailure: configuredProviders.length > 0 && fallbackReady,
|
|
478
|
+
description: options.failureMessage ?? `Simulate ${formatKind(options.kind)} provider failure and recovery without changing credentials.`,
|
|
479
|
+
error: snapshot.error,
|
|
480
|
+
failureProviders,
|
|
481
|
+
isRunning: snapshot.isRunning,
|
|
482
|
+
label: snapshot.isRunning ? `Running ${snapshot.mode ?? "simulation"}` : snapshot.lastResult ? `${snapshot.lastResult.provider} ${snapshot.lastResult.mode} simulated` : configuredProviders.length ? `${configuredProviders.length} configured` : "No configured providers",
|
|
483
|
+
providers: configuredProviders,
|
|
484
|
+
resultText: snapshot.lastResult ? JSON.stringify(snapshot.lastResult, null, 2) : null,
|
|
485
|
+
title: options.title ?? `${formatKind(options.kind)} Failure Simulation`
|
|
486
|
+
};
|
|
487
|
+
};
|
|
488
|
+
var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
|
|
489
|
+
const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
|
|
490
|
+
const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml2(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml2(provider.provider)} ${escapeHtml2(formatKind(options.kind))} failure</button>`).join("");
|
|
491
|
+
const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml2(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml2(provider.provider)} recovered</button>`).join("");
|
|
492
|
+
return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
|
|
493
|
+
<header class="absolute-voice-provider-simulation__header">
|
|
494
|
+
<span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml2(model.title)}</span>
|
|
495
|
+
<strong class="absolute-voice-provider-simulation__label">${escapeHtml2(model.label)}</strong>
|
|
496
|
+
</header>
|
|
497
|
+
<p class="absolute-voice-provider-simulation__description">${escapeHtml2(model.description)}</p>
|
|
498
|
+
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml2(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
|
|
499
|
+
<div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
|
|
500
|
+
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml2(snapshot.error)}</p>` : ""}
|
|
501
|
+
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml2(model.resultText)}</pre>` : ""}
|
|
502
|
+
</section>`;
|
|
503
|
+
};
|
|
504
|
+
var bindVoiceProviderSimulationControls = (element, store) => {
|
|
505
|
+
const onClick = (event) => {
|
|
506
|
+
const target = event.target;
|
|
507
|
+
if (!(target instanceof HTMLElement)) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const failProvider = target.getAttribute("data-voice-provider-fail");
|
|
511
|
+
const recoverProvider = target.getAttribute("data-voice-provider-recover");
|
|
512
|
+
if (failProvider) {
|
|
513
|
+
store.run(failProvider, "failure").catch(() => {});
|
|
514
|
+
}
|
|
515
|
+
if (recoverProvider) {
|
|
516
|
+
store.run(recoverProvider, "recovery").catch(() => {});
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
element.addEventListener("click", onClick);
|
|
520
|
+
return () => element.removeEventListener("click", onClick);
|
|
521
|
+
};
|
|
522
|
+
var mountVoiceProviderSimulationControls = (element, options) => {
|
|
523
|
+
const store = createVoiceProviderSimulationControlsStore(options);
|
|
524
|
+
const render = () => {
|
|
525
|
+
element.innerHTML = renderVoiceProviderSimulationControlsHTML(store.getSnapshot(), options);
|
|
526
|
+
};
|
|
527
|
+
const unsubscribeStore = store.subscribe(render);
|
|
528
|
+
const unsubscribeDom = bindVoiceProviderSimulationControls(element, store);
|
|
529
|
+
render();
|
|
530
|
+
return {
|
|
531
|
+
close: () => {
|
|
532
|
+
unsubscribeDom();
|
|
533
|
+
unsubscribeStore();
|
|
534
|
+
store.close();
|
|
535
|
+
},
|
|
536
|
+
run: store.run
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
var defineVoiceProviderSimulationControlsElement = (tagName = "absolute-voice-provider-simulation") => {
|
|
540
|
+
if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
customElements.define(tagName, class AbsoluteVoiceProviderSimulationElement extends HTMLElement {
|
|
544
|
+
mounted;
|
|
545
|
+
connectedCallback() {
|
|
546
|
+
const providers = (this.getAttribute("providers") ?? "").split(",").map((provider) => provider.trim()).filter(Boolean).map((provider) => ({ provider }));
|
|
547
|
+
const failureProviders = (this.getAttribute("failure-providers") ?? "").split(",").map((provider) => provider.trim()).filter(Boolean);
|
|
548
|
+
this.mounted = mountVoiceProviderSimulationControls(this, {
|
|
549
|
+
failureProviders: failureProviders.length ? failureProviders : undefined,
|
|
550
|
+
fallbackRequiredMessage: this.getAttribute("fallback-required-message") ?? undefined,
|
|
551
|
+
fallbackRequiredProvider: this.getAttribute("fallback-required-provider") ?? undefined,
|
|
552
|
+
failureMessage: this.getAttribute("failure-message") ?? undefined,
|
|
553
|
+
kind: this.getAttribute("kind") ?? "stt",
|
|
554
|
+
pathPrefix: this.getAttribute("path-prefix") ?? undefined,
|
|
555
|
+
providers,
|
|
556
|
+
title: this.getAttribute("title") ?? undefined
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
disconnectedCallback() {
|
|
560
|
+
this.mounted?.close();
|
|
561
|
+
this.mounted = undefined;
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// src/react/useVoiceProviderSimulationControls.tsx
|
|
391
567
|
import { useEffect as useEffect2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
568
|
+
var useVoiceProviderSimulationControls = (options) => {
|
|
569
|
+
const storeRef = useRef2(null);
|
|
570
|
+
if (!storeRef.current) {
|
|
571
|
+
storeRef.current = createVoiceProviderSimulationControlsStore(options);
|
|
572
|
+
}
|
|
573
|
+
const store = storeRef.current;
|
|
574
|
+
useEffect2(() => () => store.close(), [store]);
|
|
575
|
+
return {
|
|
576
|
+
...useSyncExternalStore2(store.subscribe, store.getSnapshot, store.getServerSnapshot),
|
|
577
|
+
run: store.run
|
|
578
|
+
};
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
// src/react/VoiceProviderSimulationControls.tsx
|
|
582
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
583
|
+
var VoiceProviderSimulationControls = ({
|
|
584
|
+
className,
|
|
585
|
+
...options
|
|
586
|
+
}) => {
|
|
587
|
+
const snapshot = useVoiceProviderSimulationControls(options);
|
|
588
|
+
const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
|
|
589
|
+
const run = (provider, mode) => {
|
|
590
|
+
snapshot.run(provider, mode).catch(() => {});
|
|
591
|
+
};
|
|
592
|
+
return /* @__PURE__ */ jsxDEV2("section", {
|
|
593
|
+
className: [
|
|
594
|
+
"absolute-voice-provider-simulation",
|
|
595
|
+
`absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}`,
|
|
596
|
+
className
|
|
597
|
+
].filter(Boolean).join(" "),
|
|
598
|
+
children: [
|
|
599
|
+
/* @__PURE__ */ jsxDEV2("header", {
|
|
600
|
+
className: "absolute-voice-provider-simulation__header",
|
|
601
|
+
children: [
|
|
602
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
603
|
+
className: "absolute-voice-provider-simulation__eyebrow",
|
|
604
|
+
children: model.title
|
|
605
|
+
}, undefined, false, undefined, this),
|
|
606
|
+
/* @__PURE__ */ jsxDEV2("strong", {
|
|
607
|
+
className: "absolute-voice-provider-simulation__label",
|
|
608
|
+
children: model.label
|
|
609
|
+
}, undefined, false, undefined, this)
|
|
610
|
+
]
|
|
611
|
+
}, undefined, true, undefined, this),
|
|
612
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
613
|
+
className: "absolute-voice-provider-simulation__description",
|
|
614
|
+
children: model.description
|
|
615
|
+
}, undefined, false, undefined, this),
|
|
616
|
+
model.canSimulateFailure ? null : /* @__PURE__ */ jsxDEV2("p", {
|
|
617
|
+
className: "absolute-voice-provider-simulation__empty",
|
|
618
|
+
children: options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure."
|
|
619
|
+
}, undefined, false, undefined, this),
|
|
620
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
621
|
+
className: "absolute-voice-provider-simulation__actions",
|
|
622
|
+
children: [
|
|
623
|
+
model.failureProviders.map((provider) => /* @__PURE__ */ jsxDEV2("button", {
|
|
624
|
+
disabled: !model.canSimulateFailure || snapshot.isRunning,
|
|
625
|
+
onClick: () => run(provider.provider, "failure"),
|
|
626
|
+
type: "button",
|
|
627
|
+
children: [
|
|
628
|
+
"Simulate ",
|
|
629
|
+
provider.provider,
|
|
630
|
+
" ",
|
|
631
|
+
(options.kind ?? "stt").toUpperCase(),
|
|
632
|
+
" ",
|
|
633
|
+
"failure"
|
|
634
|
+
]
|
|
635
|
+
}, `fail-${provider.provider}`, true, undefined, this)),
|
|
636
|
+
model.providers.map((provider) => /* @__PURE__ */ jsxDEV2("button", {
|
|
637
|
+
disabled: snapshot.isRunning,
|
|
638
|
+
onClick: () => run(provider.provider, "recovery"),
|
|
639
|
+
type: "button",
|
|
640
|
+
children: [
|
|
641
|
+
"Mark ",
|
|
642
|
+
provider.provider,
|
|
643
|
+
" recovered"
|
|
644
|
+
]
|
|
645
|
+
}, `recover-${provider.provider}`, true, undefined, this))
|
|
646
|
+
]
|
|
647
|
+
}, undefined, true, undefined, this),
|
|
648
|
+
snapshot.error ? /* @__PURE__ */ jsxDEV2("p", {
|
|
649
|
+
className: "absolute-voice-provider-simulation__error",
|
|
650
|
+
children: snapshot.error
|
|
651
|
+
}, undefined, false, undefined, this) : null,
|
|
652
|
+
model.resultText ? /* @__PURE__ */ jsxDEV2("pre", {
|
|
653
|
+
className: "absolute-voice-provider-simulation__result",
|
|
654
|
+
children: model.resultText
|
|
655
|
+
}, undefined, false, undefined, this) : null
|
|
656
|
+
]
|
|
657
|
+
}, undefined, true, undefined, this);
|
|
658
|
+
};
|
|
659
|
+
// src/react/useVoiceProviderStatus.tsx
|
|
660
|
+
import { useEffect as useEffect3, useRef as useRef3, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
392
661
|
|
|
393
662
|
// src/client/providerStatus.ts
|
|
394
663
|
var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
|
|
@@ -472,17 +741,17 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
472
741
|
|
|
473
742
|
// src/react/useVoiceProviderStatus.tsx
|
|
474
743
|
var useVoiceProviderStatus = (path = "/api/provider-status", options = {}) => {
|
|
475
|
-
const storeRef =
|
|
744
|
+
const storeRef = useRef3(null);
|
|
476
745
|
if (!storeRef.current) {
|
|
477
746
|
storeRef.current = createVoiceProviderStatusStore(path, options);
|
|
478
747
|
}
|
|
479
748
|
const store = storeRef.current;
|
|
480
|
-
|
|
749
|
+
useEffect3(() => {
|
|
481
750
|
store.refresh().catch(() => {});
|
|
482
751
|
return () => store.close();
|
|
483
752
|
}, [store]);
|
|
484
753
|
return {
|
|
485
|
-
...
|
|
754
|
+
...useSyncExternalStore3(store.subscribe, store.getSnapshot, store.getServerSnapshot),
|
|
486
755
|
refresh: store.refresh
|
|
487
756
|
};
|
|
488
757
|
};
|
|
@@ -490,7 +759,7 @@ var useVoiceProviderStatus = (path = "/api/provider-status", options = {}) => {
|
|
|
490
759
|
// src/client/providerStatusWidget.ts
|
|
491
760
|
var DEFAULT_TITLE2 = "Voice Providers";
|
|
492
761
|
var DEFAULT_DESCRIPTION2 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
|
|
493
|
-
var
|
|
762
|
+
var escapeHtml3 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
494
763
|
var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
495
764
|
var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
496
765
|
var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
|
|
@@ -546,25 +815,25 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
546
815
|
};
|
|
547
816
|
var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
|
|
548
817
|
const model = createVoiceProviderStatusViewModel(snapshot, options);
|
|
549
|
-
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--${
|
|
818
|
+
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--${escapeHtml3(provider.status)}">
|
|
550
819
|
<header>
|
|
551
|
-
<strong>${
|
|
552
|
-
<span>${
|
|
820
|
+
<strong>${escapeHtml3(provider.label)}</strong>
|
|
821
|
+
<span>${escapeHtml3(formatStatus(provider.status))}</span>
|
|
553
822
|
</header>
|
|
554
|
-
<p>${
|
|
823
|
+
<p>${escapeHtml3(provider.detail)}</p>
|
|
555
824
|
<dl>${provider.rows.map((row) => `<div>
|
|
556
|
-
<dt>${
|
|
557
|
-
<dd>${
|
|
825
|
+
<dt>${escapeHtml3(row.label)}</dt>
|
|
826
|
+
<dd>${escapeHtml3(row.value)}</dd>
|
|
558
827
|
</div>`).join("")}</dl>
|
|
559
828
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
|
|
560
|
-
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${
|
|
829
|
+
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml3(model.status)}">
|
|
561
830
|
<header class="absolute-voice-provider-status__header">
|
|
562
|
-
<span class="absolute-voice-provider-status__eyebrow">${
|
|
563
|
-
<strong class="absolute-voice-provider-status__label">${
|
|
831
|
+
<span class="absolute-voice-provider-status__eyebrow">${escapeHtml3(model.title)}</span>
|
|
832
|
+
<strong class="absolute-voice-provider-status__label">${escapeHtml3(model.label)}</strong>
|
|
564
833
|
</header>
|
|
565
|
-
<p class="absolute-voice-provider-status__description">${
|
|
834
|
+
<p class="absolute-voice-provider-status__description">${escapeHtml3(model.description)}</p>
|
|
566
835
|
${providers}
|
|
567
|
-
${model.error ? `<p class="absolute-voice-provider-status__error">${
|
|
836
|
+
${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml3(model.error)}</p>` : ""}
|
|
568
837
|
</section>`;
|
|
569
838
|
};
|
|
570
839
|
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}`;
|
|
@@ -606,7 +875,7 @@ var defineVoiceProviderStatusElement = (tagName = "absolute-voice-provider-statu
|
|
|
606
875
|
};
|
|
607
876
|
|
|
608
877
|
// src/react/VoiceProviderStatus.tsx
|
|
609
|
-
import { jsxDEV as
|
|
878
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
610
879
|
var VoiceProviderStatus = ({
|
|
611
880
|
className,
|
|
612
881
|
path = "/api/provider-status",
|
|
@@ -614,58 +883,58 @@ var VoiceProviderStatus = ({
|
|
|
614
883
|
}) => {
|
|
615
884
|
const snapshot = useVoiceProviderStatus(path, options);
|
|
616
885
|
const model = createVoiceProviderStatusViewModel(snapshot, options);
|
|
617
|
-
return /* @__PURE__ */
|
|
886
|
+
return /* @__PURE__ */ jsxDEV3("section", {
|
|
618
887
|
className: [
|
|
619
888
|
"absolute-voice-provider-status",
|
|
620
889
|
`absolute-voice-provider-status--${model.status}`,
|
|
621
890
|
className
|
|
622
891
|
].filter(Boolean).join(" "),
|
|
623
892
|
children: [
|
|
624
|
-
/* @__PURE__ */
|
|
893
|
+
/* @__PURE__ */ jsxDEV3("header", {
|
|
625
894
|
className: "absolute-voice-provider-status__header",
|
|
626
895
|
children: [
|
|
627
|
-
/* @__PURE__ */
|
|
896
|
+
/* @__PURE__ */ jsxDEV3("span", {
|
|
628
897
|
className: "absolute-voice-provider-status__eyebrow",
|
|
629
898
|
children: model.title
|
|
630
899
|
}, undefined, false, undefined, this),
|
|
631
|
-
/* @__PURE__ */
|
|
900
|
+
/* @__PURE__ */ jsxDEV3("strong", {
|
|
632
901
|
className: "absolute-voice-provider-status__label",
|
|
633
902
|
children: model.label
|
|
634
903
|
}, undefined, false, undefined, this)
|
|
635
904
|
]
|
|
636
905
|
}, undefined, true, undefined, this),
|
|
637
|
-
/* @__PURE__ */
|
|
906
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
638
907
|
className: "absolute-voice-provider-status__description",
|
|
639
908
|
children: model.description
|
|
640
909
|
}, undefined, false, undefined, this),
|
|
641
|
-
model.providers.length ? /* @__PURE__ */
|
|
910
|
+
model.providers.length ? /* @__PURE__ */ jsxDEV3("div", {
|
|
642
911
|
className: "absolute-voice-provider-status__providers",
|
|
643
|
-
children: model.providers.map((provider) => /* @__PURE__ */
|
|
912
|
+
children: model.providers.map((provider) => /* @__PURE__ */ jsxDEV3("article", {
|
|
644
913
|
className: [
|
|
645
914
|
"absolute-voice-provider-status__provider",
|
|
646
915
|
`absolute-voice-provider-status__provider--${provider.status}`
|
|
647
916
|
].join(" "),
|
|
648
917
|
children: [
|
|
649
|
-
/* @__PURE__ */
|
|
918
|
+
/* @__PURE__ */ jsxDEV3("header", {
|
|
650
919
|
children: [
|
|
651
|
-
/* @__PURE__ */
|
|
920
|
+
/* @__PURE__ */ jsxDEV3("strong", {
|
|
652
921
|
children: provider.label
|
|
653
922
|
}, undefined, false, undefined, this),
|
|
654
|
-
/* @__PURE__ */
|
|
923
|
+
/* @__PURE__ */ jsxDEV3("span", {
|
|
655
924
|
children: provider.status
|
|
656
925
|
}, undefined, false, undefined, this)
|
|
657
926
|
]
|
|
658
927
|
}, undefined, true, undefined, this),
|
|
659
|
-
/* @__PURE__ */
|
|
928
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
660
929
|
children: provider.detail
|
|
661
930
|
}, undefined, false, undefined, this),
|
|
662
|
-
/* @__PURE__ */
|
|
663
|
-
children: provider.rows.map((row) => /* @__PURE__ */
|
|
931
|
+
/* @__PURE__ */ jsxDEV3("dl", {
|
|
932
|
+
children: provider.rows.map((row) => /* @__PURE__ */ jsxDEV3("div", {
|
|
664
933
|
children: [
|
|
665
|
-
/* @__PURE__ */
|
|
934
|
+
/* @__PURE__ */ jsxDEV3("dt", {
|
|
666
935
|
children: row.label
|
|
667
936
|
}, undefined, false, undefined, this),
|
|
668
|
-
/* @__PURE__ */
|
|
937
|
+
/* @__PURE__ */ jsxDEV3("dd", {
|
|
669
938
|
children: row.value
|
|
670
939
|
}, undefined, false, undefined, this)
|
|
671
940
|
]
|
|
@@ -673,11 +942,11 @@ var VoiceProviderStatus = ({
|
|
|
673
942
|
}, undefined, false, undefined, this)
|
|
674
943
|
]
|
|
675
944
|
}, provider.provider, true, undefined, this))
|
|
676
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
945
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV3("p", {
|
|
677
946
|
className: "absolute-voice-provider-status__empty",
|
|
678
947
|
children: "Run voice traffic to see provider health."
|
|
679
948
|
}, undefined, false, undefined, this),
|
|
680
|
-
model.error ? /* @__PURE__ */
|
|
949
|
+
model.error ? /* @__PURE__ */ jsxDEV3("p", {
|
|
681
950
|
className: "absolute-voice-provider-status__error",
|
|
682
951
|
children: model.error
|
|
683
952
|
}, undefined, false, undefined, this) : null
|
|
@@ -685,7 +954,7 @@ var VoiceProviderStatus = ({
|
|
|
685
954
|
}, undefined, true, undefined, this);
|
|
686
955
|
};
|
|
687
956
|
// src/react/useVoiceRoutingStatus.tsx
|
|
688
|
-
import { useEffect as
|
|
957
|
+
import { useEffect as useEffect4, useRef as useRef4, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
689
958
|
|
|
690
959
|
// src/client/routingStatus.ts
|
|
691
960
|
var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
|
|
@@ -769,17 +1038,17 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
|
|
|
769
1038
|
|
|
770
1039
|
// src/react/useVoiceRoutingStatus.tsx
|
|
771
1040
|
var useVoiceRoutingStatus = (path = "/api/routing/latest", options = {}) => {
|
|
772
|
-
const storeRef =
|
|
1041
|
+
const storeRef = useRef4(null);
|
|
773
1042
|
if (!storeRef.current) {
|
|
774
1043
|
storeRef.current = createVoiceRoutingStatusStore(path, options);
|
|
775
1044
|
}
|
|
776
1045
|
const store = storeRef.current;
|
|
777
|
-
|
|
1046
|
+
useEffect4(() => {
|
|
778
1047
|
store.refresh().catch(() => {});
|
|
779
1048
|
return () => store.close();
|
|
780
1049
|
}, [store]);
|
|
781
1050
|
return {
|
|
782
|
-
...
|
|
1051
|
+
...useSyncExternalStore4(store.subscribe, store.getSnapshot, store.getServerSnapshot),
|
|
783
1052
|
refresh: store.refresh
|
|
784
1053
|
};
|
|
785
1054
|
};
|
|
@@ -787,7 +1056,7 @@ var useVoiceRoutingStatus = (path = "/api/routing/latest", options = {}) => {
|
|
|
787
1056
|
// src/client/routingStatusWidget.ts
|
|
788
1057
|
var DEFAULT_TITLE3 = "Voice Routing";
|
|
789
1058
|
var DEFAULT_DESCRIPTION3 = "Latest provider routing decision from the self-hosted trace store.";
|
|
790
|
-
var
|
|
1059
|
+
var escapeHtml4 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
791
1060
|
var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
|
|
792
1061
|
var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
793
1062
|
const decision = snapshot.decision;
|
|
@@ -824,17 +1093,17 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
|
824
1093
|
var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
|
|
825
1094
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
826
1095
|
const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
|
|
827
|
-
<span>${
|
|
828
|
-
<strong>${
|
|
1096
|
+
<span>${escapeHtml4(row.label)}</span>
|
|
1097
|
+
<strong>${escapeHtml4(row.value)}</strong>
|
|
829
1098
|
</div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
|
|
830
|
-
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${
|
|
1099
|
+
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml4(model.status)}">
|
|
831
1100
|
<header class="absolute-voice-routing-status__header">
|
|
832
|
-
<span class="absolute-voice-routing-status__eyebrow">${
|
|
833
|
-
<strong class="absolute-voice-routing-status__label">${
|
|
1101
|
+
<span class="absolute-voice-routing-status__eyebrow">${escapeHtml4(model.title)}</span>
|
|
1102
|
+
<strong class="absolute-voice-routing-status__label">${escapeHtml4(model.label)}</strong>
|
|
834
1103
|
</header>
|
|
835
|
-
<p class="absolute-voice-routing-status__description">${
|
|
1104
|
+
<p class="absolute-voice-routing-status__description">${escapeHtml4(model.description)}</p>
|
|
836
1105
|
${rows}
|
|
837
|
-
${model.error ? `<p class="absolute-voice-routing-status__error">${
|
|
1106
|
+
${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml4(model.error)}</p>` : ""}
|
|
838
1107
|
</section>`;
|
|
839
1108
|
};
|
|
840
1109
|
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}`;
|
|
@@ -876,7 +1145,7 @@ var defineVoiceRoutingStatusElement = (tagName = "absolute-voice-routing-status"
|
|
|
876
1145
|
};
|
|
877
1146
|
|
|
878
1147
|
// src/react/VoiceRoutingStatus.tsx
|
|
879
|
-
import { jsxDEV as
|
|
1148
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
880
1149
|
var VoiceRoutingStatus = ({
|
|
881
1150
|
className,
|
|
882
1151
|
path = "/api/routing/latest",
|
|
@@ -884,47 +1153,47 @@ var VoiceRoutingStatus = ({
|
|
|
884
1153
|
}) => {
|
|
885
1154
|
const snapshot = useVoiceRoutingStatus(path, options);
|
|
886
1155
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
887
|
-
return /* @__PURE__ */
|
|
1156
|
+
return /* @__PURE__ */ jsxDEV4("section", {
|
|
888
1157
|
className: [
|
|
889
1158
|
"absolute-voice-routing-status",
|
|
890
1159
|
`absolute-voice-routing-status--${model.status}`,
|
|
891
1160
|
className
|
|
892
1161
|
].filter(Boolean).join(" "),
|
|
893
1162
|
children: [
|
|
894
|
-
/* @__PURE__ */
|
|
1163
|
+
/* @__PURE__ */ jsxDEV4("header", {
|
|
895
1164
|
className: "absolute-voice-routing-status__header",
|
|
896
1165
|
children: [
|
|
897
|
-
/* @__PURE__ */
|
|
1166
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
898
1167
|
className: "absolute-voice-routing-status__eyebrow",
|
|
899
1168
|
children: model.title
|
|
900
1169
|
}, undefined, false, undefined, this),
|
|
901
|
-
/* @__PURE__ */
|
|
1170
|
+
/* @__PURE__ */ jsxDEV4("strong", {
|
|
902
1171
|
className: "absolute-voice-routing-status__label",
|
|
903
1172
|
children: model.label
|
|
904
1173
|
}, undefined, false, undefined, this)
|
|
905
1174
|
]
|
|
906
1175
|
}, undefined, true, undefined, this),
|
|
907
|
-
/* @__PURE__ */
|
|
1176
|
+
/* @__PURE__ */ jsxDEV4("p", {
|
|
908
1177
|
className: "absolute-voice-routing-status__description",
|
|
909
1178
|
children: model.description
|
|
910
1179
|
}, undefined, false, undefined, this),
|
|
911
|
-
model.rows.length ? /* @__PURE__ */
|
|
1180
|
+
model.rows.length ? /* @__PURE__ */ jsxDEV4("div", {
|
|
912
1181
|
className: "absolute-voice-routing-status__grid",
|
|
913
|
-
children: model.rows.map((row) => /* @__PURE__ */
|
|
1182
|
+
children: model.rows.map((row) => /* @__PURE__ */ jsxDEV4("div", {
|
|
914
1183
|
children: [
|
|
915
|
-
/* @__PURE__ */
|
|
1184
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
916
1185
|
children: row.label
|
|
917
1186
|
}, undefined, false, undefined, this),
|
|
918
|
-
/* @__PURE__ */
|
|
1187
|
+
/* @__PURE__ */ jsxDEV4("strong", {
|
|
919
1188
|
children: row.value
|
|
920
1189
|
}, undefined, false, undefined, this)
|
|
921
1190
|
]
|
|
922
1191
|
}, row.label, true, undefined, this))
|
|
923
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
1192
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4("p", {
|
|
924
1193
|
className: "absolute-voice-routing-status__empty",
|
|
925
1194
|
children: "Start a voice session to see the selected provider."
|
|
926
1195
|
}, undefined, false, undefined, this),
|
|
927
|
-
model.error ? /* @__PURE__ */
|
|
1196
|
+
model.error ? /* @__PURE__ */ jsxDEV4("p", {
|
|
928
1197
|
className: "absolute-voice-routing-status__error",
|
|
929
1198
|
children: model.error
|
|
930
1199
|
}, undefined, false, undefined, this) : null
|
|
@@ -932,7 +1201,7 @@ var VoiceRoutingStatus = ({
|
|
|
932
1201
|
}, undefined, true, undefined, this);
|
|
933
1202
|
};
|
|
934
1203
|
// src/react/useVoiceStream.tsx
|
|
935
|
-
import { useEffect as
|
|
1204
|
+
import { useEffect as useEffect5, useRef as useRef5, useSyncExternalStore as useSyncExternalStore5 } from "react";
|
|
936
1205
|
|
|
937
1206
|
// src/client/actions.ts
|
|
938
1207
|
var normalizeErrorMessage = (value) => {
|
|
@@ -1460,13 +1729,13 @@ var EMPTY_SNAPSHOT = {
|
|
|
1460
1729
|
turns: []
|
|
1461
1730
|
};
|
|
1462
1731
|
var useVoiceStream = (path, options = {}) => {
|
|
1463
|
-
const streamRef =
|
|
1732
|
+
const streamRef = useRef5(null);
|
|
1464
1733
|
if (!streamRef.current) {
|
|
1465
1734
|
streamRef.current = createVoiceStream(path, options);
|
|
1466
1735
|
}
|
|
1467
1736
|
const stream = streamRef.current;
|
|
1468
|
-
|
|
1469
|
-
const snapshot =
|
|
1737
|
+
useEffect5(() => () => stream.close(), [stream]);
|
|
1738
|
+
const snapshot = useSyncExternalStore5(stream.subscribe, stream.getSnapshot, stream.getServerSnapshot) ?? EMPTY_SNAPSHOT;
|
|
1470
1739
|
return {
|
|
1471
1740
|
...snapshot,
|
|
1472
1741
|
callControl: (message) => stream.callControl(message),
|
|
@@ -1476,7 +1745,7 @@ var useVoiceStream = (path, options = {}) => {
|
|
|
1476
1745
|
};
|
|
1477
1746
|
};
|
|
1478
1747
|
// src/react/useVoiceController.tsx
|
|
1479
|
-
import { useEffect as
|
|
1748
|
+
import { useEffect as useEffect6, useRef as useRef6, useSyncExternalStore as useSyncExternalStore6 } from "react";
|
|
1480
1749
|
|
|
1481
1750
|
// src/client/htmx.ts
|
|
1482
1751
|
var DEFAULT_EVENT_NAME = "voice-refresh";
|
|
@@ -2123,13 +2392,13 @@ var EMPTY_SNAPSHOT2 = {
|
|
|
2123
2392
|
turns: []
|
|
2124
2393
|
};
|
|
2125
2394
|
var useVoiceController = (path, options = {}) => {
|
|
2126
|
-
const controllerRef =
|
|
2395
|
+
const controllerRef = useRef6(null);
|
|
2127
2396
|
if (!controllerRef.current) {
|
|
2128
2397
|
controllerRef.current = createVoiceController(path, options);
|
|
2129
2398
|
}
|
|
2130
2399
|
const controller = controllerRef.current;
|
|
2131
|
-
|
|
2132
|
-
const snapshot =
|
|
2400
|
+
useEffect6(() => () => controller.close(), [controller]);
|
|
2401
|
+
const snapshot = useSyncExternalStore6(controller.subscribe, controller.getSnapshot, controller.getServerSnapshot) ?? EMPTY_SNAPSHOT2;
|
|
2133
2402
|
return {
|
|
2134
2403
|
...snapshot,
|
|
2135
2404
|
bindHTMX: controller.bindHTMX,
|
|
@@ -2143,7 +2412,7 @@ var useVoiceController = (path, options = {}) => {
|
|
|
2143
2412
|
};
|
|
2144
2413
|
};
|
|
2145
2414
|
// src/react/useVoiceWorkflowStatus.tsx
|
|
2146
|
-
import { useEffect as
|
|
2415
|
+
import { useEffect as useEffect7, useRef as useRef7, useSyncExternalStore as useSyncExternalStore7 } from "react";
|
|
2147
2416
|
|
|
2148
2417
|
// src/client/workflowStatus.ts
|
|
2149
2418
|
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
@@ -2226,17 +2495,17 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
|
|
|
2226
2495
|
|
|
2227
2496
|
// src/react/useVoiceWorkflowStatus.tsx
|
|
2228
2497
|
var useVoiceWorkflowStatus = (path = "/evals/scenarios/json", options = {}) => {
|
|
2229
|
-
const storeRef =
|
|
2498
|
+
const storeRef = useRef7(null);
|
|
2230
2499
|
if (!storeRef.current) {
|
|
2231
2500
|
storeRef.current = createVoiceWorkflowStatusStore(path, options);
|
|
2232
2501
|
}
|
|
2233
2502
|
const store = storeRef.current;
|
|
2234
|
-
|
|
2503
|
+
useEffect7(() => {
|
|
2235
2504
|
store.refresh().catch(() => {});
|
|
2236
2505
|
return () => store.close();
|
|
2237
2506
|
}, [store]);
|
|
2238
2507
|
return {
|
|
2239
|
-
...
|
|
2508
|
+
...useSyncExternalStore7(store.subscribe, store.getSnapshot, store.getServerSnapshot),
|
|
2240
2509
|
refresh: store.refresh
|
|
2241
2510
|
};
|
|
2242
2511
|
};
|
|
@@ -2245,9 +2514,11 @@ export {
|
|
|
2245
2514
|
useVoiceStream,
|
|
2246
2515
|
useVoiceRoutingStatus,
|
|
2247
2516
|
useVoiceProviderStatus,
|
|
2517
|
+
useVoiceProviderSimulationControls,
|
|
2248
2518
|
useVoiceController,
|
|
2249
2519
|
useVoiceAppKitStatus,
|
|
2250
2520
|
VoiceRoutingStatus,
|
|
2251
2521
|
VoiceProviderStatus,
|
|
2522
|
+
VoiceProviderSimulationControls,
|
|
2252
2523
|
VoiceOpsStatus
|
|
2253
2524
|
};
|