@absolutejs/voice 0.0.22-beta.492 → 0.0.22-beta.494
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/index.d.ts +2 -0
- package/dist/index.js +61 -0
- package/dist/oauth2TokenSource.d.ts +21 -0
- package/dist/react/VoiceWidget.d.ts +33 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +232 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,8 @@ export type { VoiceAgentUIInput, VoiceAgentUIState, } from "./agentState";
|
|
|
86
86
|
export { createInMemoryDNCList, isPhoneOnDNC, isWithinCampaignWindow, normalizePhoneNumber, shouldRetryCampaignAttempt, summarizeVoiceCampaignDispositions, } from "./campaignControls";
|
|
87
87
|
export type { VoiceCampaignDisposition, VoiceCampaignDispositionRetryPolicy, VoiceCampaignDispositionRetryRule, VoiceCampaignDispositionSummary, VoiceCampaignWindowCheckInput, VoiceDNCList, } from "./campaignControls";
|
|
88
88
|
export { createVoiceBackchannelDriver } from "./backchannel";
|
|
89
|
+
export { createVoiceOAuth2TokenSource } from "./oauth2TokenSource";
|
|
90
|
+
export type { CreateVoiceOAuth2TokenSourceOptions, VoiceOAuth2TokenResponse, VoiceOAuth2TokenSource, } from "./oauth2TokenSource";
|
|
89
91
|
export type { VoiceBackchannelCue, VoiceBackchannelDriver, VoiceBackchannelDriverOptions, } from "./backchannel";
|
|
90
92
|
export { createVoiceIVRSession, describeVoiceIVRPlan, evaluateVoiceIVRPlan, } from "./ivrPlan";
|
|
91
93
|
export type { VoiceIVRBranch, VoiceIVRDecision, VoiceIVRInput, VoiceIVRMatch, VoiceIVRPlan, VoiceIVRSession, } from "./ivrPlan";
|
package/dist/index.js
CHANGED
|
@@ -35663,6 +35663,66 @@ var createVoiceBackchannelDriver = (options) => {
|
|
|
35663
35663
|
}
|
|
35664
35664
|
};
|
|
35665
35665
|
};
|
|
35666
|
+
// src/oauth2TokenSource.ts
|
|
35667
|
+
var createVoiceOAuth2TokenSource = (options) => {
|
|
35668
|
+
const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
35669
|
+
const refreshSkewMs = (options.refreshSkewSeconds ?? 60) * 1000;
|
|
35670
|
+
let cached;
|
|
35671
|
+
let pending;
|
|
35672
|
+
const fetchToken = async () => {
|
|
35673
|
+
const body = new URLSearchParams;
|
|
35674
|
+
body.set("grant_type", options.grantType ?? "client_credentials");
|
|
35675
|
+
body.set("client_id", options.clientId);
|
|
35676
|
+
body.set("client_secret", options.clientSecret);
|
|
35677
|
+
if (options.scope) {
|
|
35678
|
+
body.set("scope", options.scope);
|
|
35679
|
+
}
|
|
35680
|
+
if (options.audience) {
|
|
35681
|
+
body.set("audience", options.audience);
|
|
35682
|
+
}
|
|
35683
|
+
const response = await fetchImpl(options.tokenUrl, {
|
|
35684
|
+
body: body.toString(),
|
|
35685
|
+
headers: {
|
|
35686
|
+
accept: "application/json",
|
|
35687
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
35688
|
+
},
|
|
35689
|
+
method: "POST"
|
|
35690
|
+
});
|
|
35691
|
+
if (!response.ok) {
|
|
35692
|
+
const text = await response.text().catch(() => "");
|
|
35693
|
+
throw new Error(`OAuth2 token request failed: ${response.status} ${response.statusText}${text ? ` \u2014 ${text.slice(0, 200)}` : ""}`);
|
|
35694
|
+
}
|
|
35695
|
+
const json = await response.json();
|
|
35696
|
+
if (!json.access_token) {
|
|
35697
|
+
throw new Error("OAuth2 token response missing access_token");
|
|
35698
|
+
}
|
|
35699
|
+
const ttlMs = typeof json.expires_in === "number" && json.expires_in > 0 ? json.expires_in * 1000 : 5 * 60 * 1000;
|
|
35700
|
+
cached = {
|
|
35701
|
+
expiresAt: Date.now() + ttlMs,
|
|
35702
|
+
value: json.access_token
|
|
35703
|
+
};
|
|
35704
|
+
return json.access_token;
|
|
35705
|
+
};
|
|
35706
|
+
return {
|
|
35707
|
+
invalidate: () => {
|
|
35708
|
+
cached = undefined;
|
|
35709
|
+
pending = undefined;
|
|
35710
|
+
},
|
|
35711
|
+
token: async () => {
|
|
35712
|
+
const now = Date.now();
|
|
35713
|
+
if (cached && cached.expiresAt - refreshSkewMs > now) {
|
|
35714
|
+
return cached.value;
|
|
35715
|
+
}
|
|
35716
|
+
if (pending) {
|
|
35717
|
+
return pending;
|
|
35718
|
+
}
|
|
35719
|
+
pending = fetchToken().finally(() => {
|
|
35720
|
+
pending = undefined;
|
|
35721
|
+
});
|
|
35722
|
+
return pending;
|
|
35723
|
+
}
|
|
35724
|
+
};
|
|
35725
|
+
};
|
|
35666
35726
|
// src/ivrPlan.ts
|
|
35667
35727
|
var speechMatchesPattern = (pattern, speech) => {
|
|
35668
35728
|
const normalized = speech.toLowerCase().trim();
|
|
@@ -47075,6 +47135,7 @@ export {
|
|
|
47075
47135
|
createVoiceObservabilityExportRoutes,
|
|
47076
47136
|
createVoiceObservabilityExportReplayRoutes,
|
|
47077
47137
|
createVoiceOTELHTTPExporter,
|
|
47138
|
+
createVoiceOAuth2TokenSource,
|
|
47078
47139
|
createVoiceMonitorWebhookNotifier,
|
|
47079
47140
|
createVoiceMonitorSession,
|
|
47080
47141
|
createVoiceMonitorRuntimeBinding,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type VoiceOAuth2TokenResponse = {
|
|
2
|
+
access_token: string;
|
|
3
|
+
expires_in?: number;
|
|
4
|
+
token_type?: string;
|
|
5
|
+
};
|
|
6
|
+
export type VoiceOAuth2TokenSource = {
|
|
7
|
+
invalidate: () => void;
|
|
8
|
+
token: () => Promise<string>;
|
|
9
|
+
};
|
|
10
|
+
export type CreateVoiceOAuth2TokenSourceOptions = {
|
|
11
|
+
audience?: string;
|
|
12
|
+
clientId: string;
|
|
13
|
+
clientSecret: string;
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
grantType?: "client_credentials";
|
|
16
|
+
/** seconds remaining before expiry to refresh proactively, default 60 */
|
|
17
|
+
refreshSkewSeconds?: number;
|
|
18
|
+
scope?: string;
|
|
19
|
+
tokenUrl: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const createVoiceOAuth2TokenSource: (options: CreateVoiceOAuth2TokenSourceOptions) => VoiceOAuth2TokenSource;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { VoiceControllerOptions } from "../types";
|
|
2
|
+
export type VoiceWidgetTheme = {
|
|
3
|
+
accent?: string;
|
|
4
|
+
background?: string;
|
|
5
|
+
errorAccent?: string;
|
|
6
|
+
fontFamily?: string;
|
|
7
|
+
foreground?: string;
|
|
8
|
+
radius?: number | string;
|
|
9
|
+
};
|
|
10
|
+
export type VoiceWidgetLabels = {
|
|
11
|
+
callEnded?: string;
|
|
12
|
+
connecting?: string;
|
|
13
|
+
endCall?: string;
|
|
14
|
+
idle?: string;
|
|
15
|
+
listening?: string;
|
|
16
|
+
mute?: string;
|
|
17
|
+
speaking?: string;
|
|
18
|
+
startCall?: string;
|
|
19
|
+
thinking?: string;
|
|
20
|
+
unmute?: string;
|
|
21
|
+
};
|
|
22
|
+
export type VoiceWidgetProps = {
|
|
23
|
+
className?: string;
|
|
24
|
+
controllerOptions?: VoiceControllerOptions;
|
|
25
|
+
labels?: VoiceWidgetLabels;
|
|
26
|
+
/** Voice runtime URL. Default '/voice'. */
|
|
27
|
+
path?: string;
|
|
28
|
+
/** Optional callback for diagnostic events surfaced by the controller. */
|
|
29
|
+
onError?: (error: string) => void;
|
|
30
|
+
theme?: VoiceWidgetTheme;
|
|
31
|
+
title?: string;
|
|
32
|
+
};
|
|
33
|
+
export declare const VoiceWidget: ({ className, controllerOptions, labels: labelsOverride, onError, path, theme: themeOverride, title, }: VoiceWidgetProps) => import("react/jsx-runtime").JSX.Element;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export { useVoiceDeliveryRuntime } from "./useVoiceDeliveryRuntime";
|
|
|
35
35
|
export { useVoiceCampaignDialerProof } from "./useVoiceCampaignDialerProof";
|
|
36
36
|
export { useVoiceStream } from "./useVoiceStream";
|
|
37
37
|
export { useVoiceController } from "./useVoiceController";
|
|
38
|
+
export { VoiceWidget } from "./VoiceWidget";
|
|
39
|
+
export type { VoiceWidgetLabels, VoiceWidgetProps, VoiceWidgetTheme, } from "./VoiceWidget";
|
|
38
40
|
export { useVoiceProviderStatus } from "./useVoiceProviderStatus";
|
|
39
41
|
export { useVoiceProviderCapabilities } from "./useVoiceProviderCapabilities";
|
|
40
42
|
export { useVoiceProviderContracts } from "./useVoiceProviderContracts";
|
package/dist/react/index.js
CHANGED
|
@@ -12450,8 +12450,237 @@ var useVoiceController = (path, options = {}) => {
|
|
|
12450
12450
|
toggleRecording: () => controller.toggleRecording()
|
|
12451
12451
|
};
|
|
12452
12452
|
};
|
|
12453
|
+
// src/react/VoiceWidget.tsx
|
|
12454
|
+
import { useMemo, useRef as useRef26 } from "react";
|
|
12455
|
+
|
|
12456
|
+
// src/agentState.ts
|
|
12457
|
+
var deriveVoiceAgentUIState = (input) => {
|
|
12458
|
+
if (!input.isConnected) {
|
|
12459
|
+
return "idle";
|
|
12460
|
+
}
|
|
12461
|
+
if (input.isPlaying) {
|
|
12462
|
+
return "speaking";
|
|
12463
|
+
}
|
|
12464
|
+
if (input.isRecording && input.hasActivePartial) {
|
|
12465
|
+
return "listening";
|
|
12466
|
+
}
|
|
12467
|
+
if (input.isRecording) {
|
|
12468
|
+
return "listening";
|
|
12469
|
+
}
|
|
12470
|
+
if (input.lastTranscriptAt && !input.lastAssistantAt) {
|
|
12471
|
+
return "thinking";
|
|
12472
|
+
}
|
|
12473
|
+
if (input.lastTranscriptAt && input.lastAssistantAt && input.lastTranscriptAt > input.lastAssistantAt) {
|
|
12474
|
+
return "thinking";
|
|
12475
|
+
}
|
|
12476
|
+
return "idle";
|
|
12477
|
+
};
|
|
12478
|
+
var describeVoiceAgentUIState = (state) => {
|
|
12479
|
+
switch (state) {
|
|
12480
|
+
case "idle":
|
|
12481
|
+
return "Idle";
|
|
12482
|
+
case "listening":
|
|
12483
|
+
return "Listening";
|
|
12484
|
+
case "speaking":
|
|
12485
|
+
return "Speaking";
|
|
12486
|
+
case "thinking":
|
|
12487
|
+
return "Thinking";
|
|
12488
|
+
}
|
|
12489
|
+
};
|
|
12490
|
+
var voiceAgentUIStateOrder = [
|
|
12491
|
+
"idle",
|
|
12492
|
+
"listening",
|
|
12493
|
+
"thinking",
|
|
12494
|
+
"speaking"
|
|
12495
|
+
];
|
|
12496
|
+
|
|
12497
|
+
// src/react/VoiceWidget.tsx
|
|
12498
|
+
import { jsxDEV as jsxDEV22 } from "react/jsx-dev-runtime";
|
|
12499
|
+
var DEFAULT_THEME = {
|
|
12500
|
+
accent: "#3b82f6",
|
|
12501
|
+
background: "#0f172a",
|
|
12502
|
+
errorAccent: "#ef4444",
|
|
12503
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
12504
|
+
foreground: "#f8fafc",
|
|
12505
|
+
radius: 16
|
|
12506
|
+
};
|
|
12507
|
+
var DEFAULT_LABELS = {
|
|
12508
|
+
callEnded: "Call ended",
|
|
12509
|
+
connecting: "Connecting\u2026",
|
|
12510
|
+
endCall: "End call",
|
|
12511
|
+
idle: "Idle",
|
|
12512
|
+
listening: "Listening",
|
|
12513
|
+
mute: "Mute",
|
|
12514
|
+
speaking: "Speaking",
|
|
12515
|
+
startCall: "Start call",
|
|
12516
|
+
thinking: "Thinking",
|
|
12517
|
+
unmute: "Unmute"
|
|
12518
|
+
};
|
|
12519
|
+
var stateLabel = (state, labels) => {
|
|
12520
|
+
switch (state) {
|
|
12521
|
+
case "listening":
|
|
12522
|
+
return labels.listening;
|
|
12523
|
+
case "speaking":
|
|
12524
|
+
return labels.speaking;
|
|
12525
|
+
case "thinking":
|
|
12526
|
+
return labels.thinking;
|
|
12527
|
+
case "idle":
|
|
12528
|
+
return labels.idle;
|
|
12529
|
+
}
|
|
12530
|
+
};
|
|
12531
|
+
var resolveRadius = (radius) => typeof radius === "number" ? `${radius}px` : radius;
|
|
12532
|
+
var VoiceWidget = ({
|
|
12533
|
+
className,
|
|
12534
|
+
controllerOptions,
|
|
12535
|
+
labels: labelsOverride,
|
|
12536
|
+
onError,
|
|
12537
|
+
path = "/voice",
|
|
12538
|
+
theme: themeOverride,
|
|
12539
|
+
title
|
|
12540
|
+
}) => {
|
|
12541
|
+
const theme = { ...DEFAULT_THEME, ...themeOverride };
|
|
12542
|
+
const labels = { ...DEFAULT_LABELS, ...labelsOverride };
|
|
12543
|
+
const lastErrorRef = useRef26(null);
|
|
12544
|
+
const controller = useVoiceController(path, controllerOptions);
|
|
12545
|
+
if (controller.error && controller.error !== lastErrorRef.current) {
|
|
12546
|
+
lastErrorRef.current = controller.error;
|
|
12547
|
+
onError?.(controller.error);
|
|
12548
|
+
}
|
|
12549
|
+
const lastAssistantAt = useMemo(() => {
|
|
12550
|
+
const last = controller.assistantAudio.at(-1);
|
|
12551
|
+
return last?.receivedAt;
|
|
12552
|
+
}, [controller.assistantAudio]);
|
|
12553
|
+
const lastTranscriptAt = useMemo(() => {
|
|
12554
|
+
const lastTurn = controller.turns.at(-1);
|
|
12555
|
+
return lastTurn?.committedAt;
|
|
12556
|
+
}, [controller.turns]);
|
|
12557
|
+
const agentState = deriveVoiceAgentUIState({
|
|
12558
|
+
hasActivePartial: controller.partial.length > 0,
|
|
12559
|
+
isConnected: controller.isConnected,
|
|
12560
|
+
isPlaying: false,
|
|
12561
|
+
isRecording: controller.isRecording,
|
|
12562
|
+
lastAssistantAt,
|
|
12563
|
+
lastTranscriptAt
|
|
12564
|
+
});
|
|
12565
|
+
const connecting = !controller.isConnected && controller.status !== "idle" && !controller.error;
|
|
12566
|
+
const containerStyle = {
|
|
12567
|
+
background: theme.background,
|
|
12568
|
+
borderRadius: resolveRadius(theme.radius),
|
|
12569
|
+
color: theme.foreground,
|
|
12570
|
+
fontFamily: theme.fontFamily,
|
|
12571
|
+
minWidth: 240,
|
|
12572
|
+
padding: "20px 22px"
|
|
12573
|
+
};
|
|
12574
|
+
const statusDotStyle = {
|
|
12575
|
+
background: controller.error ? theme.errorAccent : agentState === "idle" ? "rgba(148, 163, 184, 0.6)" : theme.accent,
|
|
12576
|
+
borderRadius: "50%",
|
|
12577
|
+
boxShadow: agentState === "speaking" ? `0 0 12px ${theme.accent}` : undefined,
|
|
12578
|
+
height: 10,
|
|
12579
|
+
width: 10
|
|
12580
|
+
};
|
|
12581
|
+
const buttonStyle = (variant) => ({
|
|
12582
|
+
background: variant === "primary" ? theme.accent : variant === "danger" ? theme.errorAccent : "transparent",
|
|
12583
|
+
border: variant === "secondary" ? `1px solid rgba(255,255,255,0.18)` : "none",
|
|
12584
|
+
borderRadius: 12,
|
|
12585
|
+
color: theme.foreground,
|
|
12586
|
+
cursor: "pointer",
|
|
12587
|
+
fontSize: 14,
|
|
12588
|
+
fontWeight: 500,
|
|
12589
|
+
padding: "10px 14px"
|
|
12590
|
+
});
|
|
12591
|
+
const handleStart = () => {
|
|
12592
|
+
controller.startRecording();
|
|
12593
|
+
};
|
|
12594
|
+
const handleStop = () => {
|
|
12595
|
+
controller.stopRecording();
|
|
12596
|
+
};
|
|
12597
|
+
const handleEnd = () => {
|
|
12598
|
+
controller.close();
|
|
12599
|
+
};
|
|
12600
|
+
const showStart = !controller.isRecording && controller.status !== "completed";
|
|
12601
|
+
const showStop = controller.isRecording;
|
|
12602
|
+
return /* @__PURE__ */ jsxDEV22("div", {
|
|
12603
|
+
"aria-live": "polite",
|
|
12604
|
+
className,
|
|
12605
|
+
"data-agent-state": agentState,
|
|
12606
|
+
role: "region",
|
|
12607
|
+
style: containerStyle,
|
|
12608
|
+
children: [
|
|
12609
|
+
/* @__PURE__ */ jsxDEV22("div", {
|
|
12610
|
+
style: {
|
|
12611
|
+
alignItems: "center",
|
|
12612
|
+
display: "flex",
|
|
12613
|
+
gap: 10,
|
|
12614
|
+
marginBottom: 12
|
|
12615
|
+
},
|
|
12616
|
+
children: [
|
|
12617
|
+
/* @__PURE__ */ jsxDEV22("span", {
|
|
12618
|
+
"aria-hidden": "true",
|
|
12619
|
+
style: statusDotStyle
|
|
12620
|
+
}, undefined, false, undefined, this),
|
|
12621
|
+
/* @__PURE__ */ jsxDEV22("strong", {
|
|
12622
|
+
style: { fontSize: 15 },
|
|
12623
|
+
children: title ?? "Voice"
|
|
12624
|
+
}, undefined, false, undefined, this),
|
|
12625
|
+
/* @__PURE__ */ jsxDEV22("span", {
|
|
12626
|
+
style: {
|
|
12627
|
+
fontSize: 13,
|
|
12628
|
+
marginLeft: "auto",
|
|
12629
|
+
opacity: 0.7
|
|
12630
|
+
},
|
|
12631
|
+
children: controller.error ? "Error" : connecting ? labels.connecting : controller.status === "completed" ? labels.callEnded : stateLabel(agentState, labels)
|
|
12632
|
+
}, undefined, false, undefined, this)
|
|
12633
|
+
]
|
|
12634
|
+
}, undefined, true, undefined, this),
|
|
12635
|
+
controller.partial ? /* @__PURE__ */ jsxDEV22("p", {
|
|
12636
|
+
style: {
|
|
12637
|
+
fontSize: 13,
|
|
12638
|
+
margin: "8px 0 12px",
|
|
12639
|
+
opacity: 0.85,
|
|
12640
|
+
wordBreak: "break-word"
|
|
12641
|
+
},
|
|
12642
|
+
children: [
|
|
12643
|
+
"\u201C",
|
|
12644
|
+
controller.partial,
|
|
12645
|
+
"\u201D"
|
|
12646
|
+
]
|
|
12647
|
+
}, undefined, true, undefined, this) : null,
|
|
12648
|
+
/* @__PURE__ */ jsxDEV22("div", {
|
|
12649
|
+
style: { display: "flex", gap: 10 },
|
|
12650
|
+
children: [
|
|
12651
|
+
showStart ? /* @__PURE__ */ jsxDEV22("button", {
|
|
12652
|
+
onClick: handleStart,
|
|
12653
|
+
style: buttonStyle("primary"),
|
|
12654
|
+
type: "button",
|
|
12655
|
+
children: labels.startCall
|
|
12656
|
+
}, undefined, false, undefined, this) : null,
|
|
12657
|
+
showStop ? /* @__PURE__ */ jsxDEV22("button", {
|
|
12658
|
+
onClick: handleStop,
|
|
12659
|
+
style: buttonStyle("secondary"),
|
|
12660
|
+
type: "button",
|
|
12661
|
+
children: labels.mute
|
|
12662
|
+
}, undefined, false, undefined, this) : null,
|
|
12663
|
+
controller.isConnected ? /* @__PURE__ */ jsxDEV22("button", {
|
|
12664
|
+
onClick: handleEnd,
|
|
12665
|
+
style: buttonStyle("danger"),
|
|
12666
|
+
type: "button",
|
|
12667
|
+
children: labels.endCall
|
|
12668
|
+
}, undefined, false, undefined, this) : null
|
|
12669
|
+
]
|
|
12670
|
+
}, undefined, true, undefined, this),
|
|
12671
|
+
controller.error ? /* @__PURE__ */ jsxDEV22("p", {
|
|
12672
|
+
style: {
|
|
12673
|
+
color: theme.errorAccent,
|
|
12674
|
+
fontSize: 12,
|
|
12675
|
+
marginTop: 12
|
|
12676
|
+
},
|
|
12677
|
+
children: controller.error
|
|
12678
|
+
}, undefined, false, undefined, this) : null
|
|
12679
|
+
]
|
|
12680
|
+
}, undefined, true, undefined, this);
|
|
12681
|
+
};
|
|
12453
12682
|
// src/react/useVoiceWorkflowStatus.tsx
|
|
12454
|
-
import { useEffect as useEffect26, useRef as
|
|
12683
|
+
import { useEffect as useEffect26, useRef as useRef27, useSyncExternalStore as useSyncExternalStore26 } from "react";
|
|
12455
12684
|
|
|
12456
12685
|
// src/client/workflowStatus.ts
|
|
12457
12686
|
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
@@ -12534,7 +12763,7 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
|
|
|
12534
12763
|
|
|
12535
12764
|
// src/react/useVoiceWorkflowStatus.tsx
|
|
12536
12765
|
var useVoiceWorkflowStatus = (path = "/evals/scenarios/json", options = {}) => {
|
|
12537
|
-
const storeRef =
|
|
12766
|
+
const storeRef = useRef27(null);
|
|
12538
12767
|
if (!storeRef.current) {
|
|
12539
12768
|
storeRef.current = createVoiceWorkflowStatusStore(path, options);
|
|
12540
12769
|
}
|
|
@@ -12575,6 +12804,7 @@ export {
|
|
|
12575
12804
|
useVoiceCampaignDialerProof,
|
|
12576
12805
|
useVoiceCallDebugger,
|
|
12577
12806
|
useVoiceAgentSquadStatus,
|
|
12807
|
+
VoiceWidget,
|
|
12578
12808
|
VoiceTurnQuality,
|
|
12579
12809
|
VoiceTurnLatency,
|
|
12580
12810
|
VoiceTraceTimeline,
|