@absolutejs/voice 0.0.22-beta.660 → 0.0.22-beta.662
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/angular/index.js +21 -6
- package/dist/client/actions.d.ts +24 -0
- package/dist/client/htmxBootstrap.js +21 -6
- package/dist/client/index.js +21 -6
- package/dist/core/types.d.ts +10 -0
- package/dist/embed/index.js +21 -6
- package/dist/embed/voice-widget.js +5 -5
- package/dist/index.js +14 -2
- package/dist/react/index.js +21 -6
- package/dist/react/useVoiceController.d.ts +2 -0
- package/dist/react/useVoiceStream.d.ts +2 -0
- package/dist/svelte/index.js +21 -6
- package/dist/testing/index.js +25 -6
- package/dist/vue/index.js +21 -6
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -525,6 +525,8 @@ var serverMessageToAction = (message) => {
|
|
|
525
525
|
};
|
|
526
526
|
case "session":
|
|
527
527
|
return {
|
|
528
|
+
paused: message.paused,
|
|
529
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
528
530
|
sessionId: message.sessionId,
|
|
529
531
|
sessionMetadata: message.sessionMetadata,
|
|
530
532
|
scenarioId: message.scenarioId,
|
|
@@ -885,12 +887,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
885
887
|
state.reconnectResetTimeout = null;
|
|
886
888
|
}, reconnectResetAfterMs);
|
|
887
889
|
}
|
|
888
|
-
listeners.forEach((listener) => listener({
|
|
889
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
890
|
-
sessionId: state.sessionId,
|
|
891
|
-
status: "active",
|
|
892
|
-
type: "session"
|
|
893
|
-
}));
|
|
894
890
|
state.pingInterval = setInterval(() => {
|
|
895
891
|
if (ws.readyState === WS_OPEN) {
|
|
896
892
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -1121,6 +1117,7 @@ var createInitialState = () => ({
|
|
|
1121
1117
|
call: null,
|
|
1122
1118
|
error: null,
|
|
1123
1119
|
isConnected: false,
|
|
1120
|
+
paused: false,
|
|
1124
1121
|
partial: "",
|
|
1125
1122
|
reconnect: createInitialReconnectState(),
|
|
1126
1123
|
scenarioId: null,
|
|
@@ -1257,6 +1254,8 @@ var createVoiceStreamStore = () => {
|
|
|
1257
1254
|
state = {
|
|
1258
1255
|
...state,
|
|
1259
1256
|
error: null,
|
|
1257
|
+
paused: action.paused ?? false,
|
|
1258
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
1260
1259
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1261
1260
|
isConnected: action.status === "active",
|
|
1262
1261
|
sessionId: action.sessionId,
|
|
@@ -1393,6 +1392,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1393
1392
|
get partial() {
|
|
1394
1393
|
return store.getSnapshot().partial;
|
|
1395
1394
|
},
|
|
1395
|
+
get paused() {
|
|
1396
|
+
return store.getSnapshot().paused;
|
|
1397
|
+
},
|
|
1398
|
+
get pauseExpiresAt() {
|
|
1399
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
1400
|
+
},
|
|
1396
1401
|
get reconnect() {
|
|
1397
1402
|
return store.getSnapshot().reconnect;
|
|
1398
1403
|
},
|
|
@@ -1756,6 +1761,8 @@ var createInitialState2 = (stream) => ({
|
|
|
1756
1761
|
error: stream.error,
|
|
1757
1762
|
isConnected: stream.isConnected,
|
|
1758
1763
|
isRecording: false,
|
|
1764
|
+
paused: stream.paused,
|
|
1765
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1759
1766
|
partial: stream.partial,
|
|
1760
1767
|
reconnect: stream.reconnect,
|
|
1761
1768
|
recordingError: null,
|
|
@@ -1791,6 +1798,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1791
1798
|
call: stream.call,
|
|
1792
1799
|
error: stream.error,
|
|
1793
1800
|
isConnected: stream.isConnected,
|
|
1801
|
+
paused: stream.paused,
|
|
1802
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1794
1803
|
partial: stream.partial,
|
|
1795
1804
|
reconnect: stream.reconnect,
|
|
1796
1805
|
sessionId: stream.sessionId,
|
|
@@ -1938,6 +1947,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1938
1947
|
get partial() {
|
|
1939
1948
|
return state.partial;
|
|
1940
1949
|
},
|
|
1950
|
+
get paused() {
|
|
1951
|
+
return state.paused;
|
|
1952
|
+
},
|
|
1953
|
+
get pauseExpiresAt() {
|
|
1954
|
+
return state.pauseExpiresAt;
|
|
1955
|
+
},
|
|
1941
1956
|
get reconnect() {
|
|
1942
1957
|
return state.reconnect;
|
|
1943
1958
|
},
|
package/dist/client/actions.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
20
20
|
sessionMetadata?: undefined;
|
|
21
21
|
status?: undefined;
|
|
22
22
|
turns?: undefined;
|
|
23
|
+
paused?: undefined;
|
|
24
|
+
pauseExpiresAt?: undefined;
|
|
23
25
|
turn?: undefined;
|
|
24
26
|
} | {
|
|
25
27
|
text: string;
|
|
@@ -42,6 +44,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
42
44
|
sessionMetadata?: undefined;
|
|
43
45
|
status?: undefined;
|
|
44
46
|
turns?: undefined;
|
|
47
|
+
paused?: undefined;
|
|
48
|
+
pauseExpiresAt?: undefined;
|
|
45
49
|
turn?: undefined;
|
|
46
50
|
} | {
|
|
47
51
|
delta: string;
|
|
@@ -64,6 +68,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
64
68
|
sessionMetadata?: undefined;
|
|
65
69
|
status?: undefined;
|
|
66
70
|
turns?: undefined;
|
|
71
|
+
paused?: undefined;
|
|
72
|
+
pauseExpiresAt?: undefined;
|
|
67
73
|
turn?: undefined;
|
|
68
74
|
} | {
|
|
69
75
|
sessionId: string;
|
|
@@ -86,6 +92,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
86
92
|
sessionMetadata?: undefined;
|
|
87
93
|
status?: undefined;
|
|
88
94
|
turns?: undefined;
|
|
95
|
+
paused?: undefined;
|
|
96
|
+
pauseExpiresAt?: undefined;
|
|
89
97
|
turn?: undefined;
|
|
90
98
|
} | {
|
|
91
99
|
reconnect: import("..").VoiceReconnectClientState;
|
|
@@ -108,6 +116,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
108
116
|
sessionMetadata?: undefined;
|
|
109
117
|
status?: undefined;
|
|
110
118
|
turns?: undefined;
|
|
119
|
+
paused?: undefined;
|
|
120
|
+
pauseExpiresAt?: undefined;
|
|
111
121
|
turn?: undefined;
|
|
112
122
|
} | {
|
|
113
123
|
event: import("..").VoiceCallLifecycleEvent;
|
|
@@ -130,6 +140,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
130
140
|
sessionMetadata?: undefined;
|
|
131
141
|
status?: undefined;
|
|
132
142
|
turns?: undefined;
|
|
143
|
+
paused?: undefined;
|
|
144
|
+
pauseExpiresAt?: undefined;
|
|
133
145
|
turn?: undefined;
|
|
134
146
|
} | {
|
|
135
147
|
message: string;
|
|
@@ -152,6 +164,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
152
164
|
sessionMetadata?: undefined;
|
|
153
165
|
status?: undefined;
|
|
154
166
|
turns?: undefined;
|
|
167
|
+
paused?: undefined;
|
|
168
|
+
pauseExpiresAt?: undefined;
|
|
155
169
|
turn?: undefined;
|
|
156
170
|
} | {
|
|
157
171
|
transcript: import("..").Transcript;
|
|
@@ -174,6 +188,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
174
188
|
sessionMetadata?: undefined;
|
|
175
189
|
status?: undefined;
|
|
176
190
|
turns?: undefined;
|
|
191
|
+
paused?: undefined;
|
|
192
|
+
pauseExpiresAt?: undefined;
|
|
177
193
|
turn?: undefined;
|
|
178
194
|
} | {
|
|
179
195
|
transcript: import("..").Transcript;
|
|
@@ -196,6 +212,8 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
196
212
|
sessionMetadata?: undefined;
|
|
197
213
|
status?: undefined;
|
|
198
214
|
turns?: undefined;
|
|
215
|
+
paused?: undefined;
|
|
216
|
+
pauseExpiresAt?: undefined;
|
|
199
217
|
turn?: undefined;
|
|
200
218
|
} | {
|
|
201
219
|
assistantTexts: string[];
|
|
@@ -218,8 +236,12 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
218
236
|
message?: undefined;
|
|
219
237
|
recoverable?: undefined;
|
|
220
238
|
transcript?: undefined;
|
|
239
|
+
paused?: undefined;
|
|
240
|
+
pauseExpiresAt?: undefined;
|
|
221
241
|
turn?: undefined;
|
|
222
242
|
} | {
|
|
243
|
+
paused: boolean | undefined;
|
|
244
|
+
pauseExpiresAt: number | undefined;
|
|
223
245
|
sessionId: string;
|
|
224
246
|
sessionMetadata: Record<string, unknown> | undefined;
|
|
225
247
|
scenarioId: string | undefined;
|
|
@@ -263,4 +285,6 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
263
285
|
sessionMetadata?: undefined;
|
|
264
286
|
status?: undefined;
|
|
265
287
|
turns?: undefined;
|
|
288
|
+
paused?: undefined;
|
|
289
|
+
pauseExpiresAt?: undefined;
|
|
266
290
|
} | null;
|
|
@@ -293,6 +293,8 @@ var serverMessageToAction = (message) => {
|
|
|
293
293
|
};
|
|
294
294
|
case "session":
|
|
295
295
|
return {
|
|
296
|
+
paused: message.paused,
|
|
297
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
296
298
|
sessionId: message.sessionId,
|
|
297
299
|
sessionMetadata: message.sessionMetadata,
|
|
298
300
|
scenarioId: message.scenarioId,
|
|
@@ -802,12 +804,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
802
804
|
state.reconnectResetTimeout = null;
|
|
803
805
|
}, reconnectResetAfterMs);
|
|
804
806
|
}
|
|
805
|
-
listeners.forEach((listener) => listener({
|
|
806
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
807
|
-
sessionId: state.sessionId,
|
|
808
|
-
status: "active",
|
|
809
|
-
type: "session"
|
|
810
|
-
}));
|
|
811
807
|
state.pingInterval = setInterval(() => {
|
|
812
808
|
if (ws.readyState === WS_OPEN) {
|
|
813
809
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -1038,6 +1034,7 @@ var createInitialState = () => ({
|
|
|
1038
1034
|
call: null,
|
|
1039
1035
|
error: null,
|
|
1040
1036
|
isConnected: false,
|
|
1037
|
+
paused: false,
|
|
1041
1038
|
partial: "",
|
|
1042
1039
|
reconnect: createInitialReconnectState(),
|
|
1043
1040
|
scenarioId: null,
|
|
@@ -1174,6 +1171,8 @@ var createVoiceStreamStore = () => {
|
|
|
1174
1171
|
state = {
|
|
1175
1172
|
...state,
|
|
1176
1173
|
error: null,
|
|
1174
|
+
paused: action.paused ?? false,
|
|
1175
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
1177
1176
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1178
1177
|
isConnected: action.status === "active",
|
|
1179
1178
|
sessionId: action.sessionId,
|
|
@@ -1310,6 +1309,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1310
1309
|
get partial() {
|
|
1311
1310
|
return store.getSnapshot().partial;
|
|
1312
1311
|
},
|
|
1312
|
+
get paused() {
|
|
1313
|
+
return store.getSnapshot().paused;
|
|
1314
|
+
},
|
|
1315
|
+
get pauseExpiresAt() {
|
|
1316
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
1317
|
+
},
|
|
1313
1318
|
get reconnect() {
|
|
1314
1319
|
return store.getSnapshot().reconnect;
|
|
1315
1320
|
},
|
|
@@ -1636,6 +1641,8 @@ var createInitialState2 = (stream) => ({
|
|
|
1636
1641
|
error: stream.error,
|
|
1637
1642
|
isConnected: stream.isConnected,
|
|
1638
1643
|
isRecording: false,
|
|
1644
|
+
paused: stream.paused,
|
|
1645
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1639
1646
|
partial: stream.partial,
|
|
1640
1647
|
reconnect: stream.reconnect,
|
|
1641
1648
|
recordingError: null,
|
|
@@ -1671,6 +1678,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1671
1678
|
call: stream.call,
|
|
1672
1679
|
error: stream.error,
|
|
1673
1680
|
isConnected: stream.isConnected,
|
|
1681
|
+
paused: stream.paused,
|
|
1682
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1674
1683
|
partial: stream.partial,
|
|
1675
1684
|
reconnect: stream.reconnect,
|
|
1676
1685
|
sessionId: stream.sessionId,
|
|
@@ -1818,6 +1827,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1818
1827
|
get partial() {
|
|
1819
1828
|
return state.partial;
|
|
1820
1829
|
},
|
|
1830
|
+
get paused() {
|
|
1831
|
+
return state.paused;
|
|
1832
|
+
},
|
|
1833
|
+
get pauseExpiresAt() {
|
|
1834
|
+
return state.pauseExpiresAt;
|
|
1835
|
+
},
|
|
1821
1836
|
get reconnect() {
|
|
1822
1837
|
return state.reconnect;
|
|
1823
1838
|
},
|
package/dist/client/index.js
CHANGED
|
@@ -366,12 +366,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
366
366
|
state.reconnectResetTimeout = null;
|
|
367
367
|
}, reconnectResetAfterMs);
|
|
368
368
|
}
|
|
369
|
-
listeners.forEach((listener) => listener({
|
|
370
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
371
|
-
sessionId: state.sessionId,
|
|
372
|
-
status: "active",
|
|
373
|
-
type: "session"
|
|
374
|
-
}));
|
|
375
369
|
state.pingInterval = setInterval(() => {
|
|
376
370
|
if (ws.readyState === WS_OPEN) {
|
|
377
371
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -1396,6 +1390,8 @@ var serverMessageToAction = (message) => {
|
|
|
1396
1390
|
};
|
|
1397
1391
|
case "session":
|
|
1398
1392
|
return {
|
|
1393
|
+
paused: message.paused,
|
|
1394
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
1399
1395
|
sessionId: message.sessionId,
|
|
1400
1396
|
sessionMetadata: message.sessionMetadata,
|
|
1401
1397
|
scenarioId: message.scenarioId,
|
|
@@ -1524,6 +1520,7 @@ var createInitialState2 = () => ({
|
|
|
1524
1520
|
call: null,
|
|
1525
1521
|
error: null,
|
|
1526
1522
|
isConnected: false,
|
|
1523
|
+
paused: false,
|
|
1527
1524
|
partial: "",
|
|
1528
1525
|
reconnect: createInitialReconnectState(),
|
|
1529
1526
|
scenarioId: null,
|
|
@@ -1660,6 +1657,8 @@ var createVoiceStreamStore = () => {
|
|
|
1660
1657
|
state = {
|
|
1661
1658
|
...state,
|
|
1662
1659
|
error: null,
|
|
1660
|
+
paused: action.paused ?? false,
|
|
1661
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
1663
1662
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1664
1663
|
isConnected: action.status === "active",
|
|
1665
1664
|
sessionId: action.sessionId,
|
|
@@ -1796,6 +1795,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1796
1795
|
get partial() {
|
|
1797
1796
|
return store.getSnapshot().partial;
|
|
1798
1797
|
},
|
|
1798
|
+
get paused() {
|
|
1799
|
+
return store.getSnapshot().paused;
|
|
1800
|
+
},
|
|
1801
|
+
get pauseExpiresAt() {
|
|
1802
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
1803
|
+
},
|
|
1799
1804
|
get reconnect() {
|
|
1800
1805
|
return store.getSnapshot().reconnect;
|
|
1801
1806
|
},
|
|
@@ -2352,6 +2357,8 @@ var createInitialState3 = (stream) => ({
|
|
|
2352
2357
|
error: stream.error,
|
|
2353
2358
|
isConnected: stream.isConnected,
|
|
2354
2359
|
isRecording: false,
|
|
2360
|
+
paused: stream.paused,
|
|
2361
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
2355
2362
|
partial: stream.partial,
|
|
2356
2363
|
reconnect: stream.reconnect,
|
|
2357
2364
|
recordingError: null,
|
|
@@ -2387,6 +2394,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
2387
2394
|
call: stream.call,
|
|
2388
2395
|
error: stream.error,
|
|
2389
2396
|
isConnected: stream.isConnected,
|
|
2397
|
+
paused: stream.paused,
|
|
2398
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
2390
2399
|
partial: stream.partial,
|
|
2391
2400
|
reconnect: stream.reconnect,
|
|
2392
2401
|
sessionId: stream.sessionId,
|
|
@@ -2534,6 +2543,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
2534
2543
|
get partial() {
|
|
2535
2544
|
return state.partial;
|
|
2536
2545
|
},
|
|
2546
|
+
get paused() {
|
|
2547
|
+
return state.paused;
|
|
2548
|
+
},
|
|
2549
|
+
get pauseExpiresAt() {
|
|
2550
|
+
return state.pauseExpiresAt;
|
|
2551
|
+
},
|
|
2537
2552
|
get reconnect() {
|
|
2538
2553
|
return state.reconnect;
|
|
2539
2554
|
},
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1281,6 +1281,8 @@ export type VoiceClientPingMessage = {
|
|
|
1281
1281
|
export type VoiceClientMessage = VoiceClientStartMessage | VoiceClientEndTurnMessage | VoiceClientCloseMessage | VoiceClientCallControlMessage | VoiceClientPingMessage;
|
|
1282
1282
|
export type VoiceServerSessionMessage = {
|
|
1283
1283
|
type: "session";
|
|
1284
|
+
paused?: boolean;
|
|
1285
|
+
pauseExpiresAt?: number;
|
|
1284
1286
|
sessionId: string;
|
|
1285
1287
|
status: VoiceSessionStatus;
|
|
1286
1288
|
scenarioId?: string;
|
|
@@ -1531,6 +1533,8 @@ export type VoiceHTMXOptions<TSession extends VoiceSessionRecord = VoiceSessionR
|
|
|
1531
1533
|
export type VoiceHTMXConfig<TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = VoiceHTMXRenderer<TSession, TResult> | VoiceHTMXOptions<TSession, TResult>;
|
|
1532
1534
|
export type VoiceStreamState<TResult = unknown> = {
|
|
1533
1535
|
call: VoiceCallLifecycleState | null;
|
|
1536
|
+
paused: boolean;
|
|
1537
|
+
pauseExpiresAt?: number;
|
|
1534
1538
|
sessionMetadata: Record<string, unknown> | null;
|
|
1535
1539
|
sessionId: string | null;
|
|
1536
1540
|
scenarioId: string | null;
|
|
@@ -1551,6 +1555,8 @@ export type VoiceStreamState<TResult = unknown> = {
|
|
|
1551
1555
|
};
|
|
1552
1556
|
export type VoiceStream<TResult = unknown> = {
|
|
1553
1557
|
call: VoiceCallLifecycleState | null;
|
|
1558
|
+
paused: boolean;
|
|
1559
|
+
pauseExpiresAt?: number;
|
|
1554
1560
|
callControl: (message: Omit<VoiceClientCallControlMessage, "requestId" | "type">) => Promise<void>;
|
|
1555
1561
|
close: (reason?: string) => void;
|
|
1556
1562
|
/** Release the transport without terminally completing the server session. */
|
|
@@ -1648,6 +1654,8 @@ export type VoiceBargeInBinding = {
|
|
|
1648
1654
|
export type VoiceController<TResult = unknown> = {
|
|
1649
1655
|
bindHTMX: (options: VoiceHTMXBindingOptions) => () => void;
|
|
1650
1656
|
call: VoiceCallLifecycleState | null;
|
|
1657
|
+
paused: boolean;
|
|
1658
|
+
pauseExpiresAt?: number;
|
|
1651
1659
|
callControl: (message: Omit<VoiceClientCallControlMessage, "requestId" | "type">) => Promise<void>;
|
|
1652
1660
|
close: (reason?: string) => void;
|
|
1653
1661
|
/** Release the transport while leaving the server session resumable. */
|
|
@@ -1697,6 +1705,8 @@ export type VoiceHTMXBindingOptions = {
|
|
|
1697
1705
|
};
|
|
1698
1706
|
export type VoiceStoreAction<TResult = unknown> = {
|
|
1699
1707
|
type: "session";
|
|
1708
|
+
paused?: boolean;
|
|
1709
|
+
pauseExpiresAt?: number;
|
|
1700
1710
|
sessionId: string;
|
|
1701
1711
|
sessionMetadata?: Record<string, unknown>;
|
|
1702
1712
|
scenarioId?: string;
|
package/dist/embed/index.js
CHANGED
|
@@ -290,6 +290,8 @@ var serverMessageToAction = (message) => {
|
|
|
290
290
|
};
|
|
291
291
|
case "session":
|
|
292
292
|
return {
|
|
293
|
+
paused: message.paused,
|
|
294
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
293
295
|
sessionId: message.sessionId,
|
|
294
296
|
sessionMetadata: message.sessionMetadata,
|
|
295
297
|
scenarioId: message.scenarioId,
|
|
@@ -799,12 +801,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
799
801
|
state.reconnectResetTimeout = null;
|
|
800
802
|
}, reconnectResetAfterMs);
|
|
801
803
|
}
|
|
802
|
-
listeners.forEach((listener) => listener({
|
|
803
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
804
|
-
sessionId: state.sessionId,
|
|
805
|
-
status: "active",
|
|
806
|
-
type: "session"
|
|
807
|
-
}));
|
|
808
804
|
state.pingInterval = setInterval(() => {
|
|
809
805
|
if (ws.readyState === WS_OPEN) {
|
|
810
806
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -1035,6 +1031,7 @@ var createInitialState = () => ({
|
|
|
1035
1031
|
call: null,
|
|
1036
1032
|
error: null,
|
|
1037
1033
|
isConnected: false,
|
|
1034
|
+
paused: false,
|
|
1038
1035
|
partial: "",
|
|
1039
1036
|
reconnect: createInitialReconnectState(),
|
|
1040
1037
|
scenarioId: null,
|
|
@@ -1171,6 +1168,8 @@ var createVoiceStreamStore = () => {
|
|
|
1171
1168
|
state = {
|
|
1172
1169
|
...state,
|
|
1173
1170
|
error: null,
|
|
1171
|
+
paused: action.paused ?? false,
|
|
1172
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
1174
1173
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1175
1174
|
isConnected: action.status === "active",
|
|
1176
1175
|
sessionId: action.sessionId,
|
|
@@ -1307,6 +1306,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1307
1306
|
get partial() {
|
|
1308
1307
|
return store.getSnapshot().partial;
|
|
1309
1308
|
},
|
|
1309
|
+
get paused() {
|
|
1310
|
+
return store.getSnapshot().paused;
|
|
1311
|
+
},
|
|
1312
|
+
get pauseExpiresAt() {
|
|
1313
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
1314
|
+
},
|
|
1310
1315
|
get reconnect() {
|
|
1311
1316
|
return store.getSnapshot().reconnect;
|
|
1312
1317
|
},
|
|
@@ -1633,6 +1638,8 @@ var createInitialState2 = (stream) => ({
|
|
|
1633
1638
|
error: stream.error,
|
|
1634
1639
|
isConnected: stream.isConnected,
|
|
1635
1640
|
isRecording: false,
|
|
1641
|
+
paused: stream.paused,
|
|
1642
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1636
1643
|
partial: stream.partial,
|
|
1637
1644
|
reconnect: stream.reconnect,
|
|
1638
1645
|
recordingError: null,
|
|
@@ -1668,6 +1675,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1668
1675
|
call: stream.call,
|
|
1669
1676
|
error: stream.error,
|
|
1670
1677
|
isConnected: stream.isConnected,
|
|
1678
|
+
paused: stream.paused,
|
|
1679
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1671
1680
|
partial: stream.partial,
|
|
1672
1681
|
reconnect: stream.reconnect,
|
|
1673
1682
|
sessionId: stream.sessionId,
|
|
@@ -1815,6 +1824,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1815
1824
|
get partial() {
|
|
1816
1825
|
return state.partial;
|
|
1817
1826
|
},
|
|
1827
|
+
get paused() {
|
|
1828
|
+
return state.paused;
|
|
1829
|
+
},
|
|
1830
|
+
get pauseExpiresAt() {
|
|
1831
|
+
return state.pauseExpiresAt;
|
|
1832
|
+
},
|
|
1818
1833
|
get reconnect() {
|
|
1819
1834
|
return state.reconnect;
|
|
1820
1835
|
},
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:k,getOwnPropertyNames:w0,getOwnPropertyDescriptor:J0}=Object,S0=Object.prototype.hasOwnProperty;function Y0(V){return this[V]}var Z0=(V)=>{var g=(l??=new WeakMap).get(V),C;if(g)return g;if(g=k({},"__esModule",{value:!0}),V&&typeof V==="object"||typeof V==="function"){for(var A of w0(V))if(!S0.call(g,A))k(g,A,{get:Y0.bind(V,A),enumerable:!(C=J0(V,A))||C.enumerable})}return l.set(V,g),g},l;var y0=(V)=>V;function h0(V,g){this[V]=y0.bind(null,g)}var Q0=(V,g)=>{for(var C in g)k(V,C,{get:g[C],enumerable:!0,configurable:!0,set:h0.bind(g,C)})};var _V={};Q0(_V,{mount:()=>$0,default:()=>TV,VOICE_EMBED_VERSION:()=>R0});var K0=(V)=>{if(typeof V!=="string")return V;return document.querySelector(V)},c0=(V,g,C,A)=>{let R=g??V.getAttribute("hx-get")??"";if(!R)return"";let _=new URL(R,window.location.origin);if(A)_.searchParams.set(C,A);else _.searchParams.delete(C);return`${_.pathname}${_.search}${_.hash}`},d=(V,g)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=K0(g.element);if(!C)return()=>{};let A=g.eventName??"voice-refresh",R=g.sessionQueryParam??"sessionId",_=()=>{let X=window,H=c0(C,g.route,R,V.sessionId);if(H)C.setAttribute("hx-get",H);X.htmx?.process?.(C),X.htmx?.trigger?.(C,A)},D=V.subscribe(_);return _(),()=>{D()}};var E0=(V)=>Math.max(-1,Math.min(1,V)),q0=(V)=>{let g=new Int16Array(V.length);for(let C=0;C<V.length;C+=1){let A=E0(V[C]??0);g[C]=A<0?A*32768:A*32767}return new Uint8Array(g.buffer)},N0=(V)=>{let g=V instanceof Uint8Array?V:new Uint8Array(V);if(g.byteLength<2)return 0;let C=new Int16Array(g.buffer,g.byteOffset,Math.floor(g.byteLength/2));if(C.length===0)return 0;let A=0;for(let R of C){let _=R/32768;A+=_*_}return Math.min(1,Math.max(0,Math.sqrt(A/C.length)*5.5))},z0=(V,g,C)=>{if(g===C)return V;let A=g/C,R=Math.round(V.length/A),_=new Float32Array(R),D=0,X=0;while(D<_.length){let H=Math.round((D+1)*A),O=0,L=0;for(let W=X;W<H&&W<V.length;W+=1)O+=V[W]??0,L+=1;_[D]=L>0?O/L:0,D+=1,X=H}return _},v=(V)=>{let g=null,C=null,A=null,R=null,_=0,D=null,X=(L)=>{L.processorNode?.disconnect(),L.sourceNode?.disconnect(),L.mediaStream?.getTracks().forEach((W)=>W.stop()),L.audioContext?.close()};return{start:()=>{if(R)return Promise.resolve();if(D)return D;let L=++_,U=(async()=>{if(!V.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let T=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!T)throw Error("Browser microphone capture requires AudioContext support.");let J=null,h=null,Z=null,Q=null;try{if(h=V.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:V.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),L!==_)throw Error("Microphone capture stopped during startup.");if(J=new T,J.state==="suspended")await J.resume();if(L!==_)throw Error("Microphone capture stopped during startup.");if(Q=J.createMediaStreamSource(h),Z=J.createScriptProcessor(4096,1,1),Z.onaudioprocess=(G)=>{let c=G.inputBuffer.getChannelData(0),q=z0(c,J?.sampleRate??48000,V.sampleRateHz??16000),$=q0(q);V.onLevel?.(N0($)),V.onAudio($)},Q.connect(Z),Z.connect(J.destination),L!==_)throw Error("Microphone capture stopped during startup.");g=J,R=h,A=Z,C=Q}catch(G){throw X({audioContext:J,mediaStream:h,processorNode:Z,sourceNode:Q}),G}})().finally(()=>{if(D===U)D=null});return D=U,U},stop:()=>{_+=1,X({audioContext:g,mediaStream:R,processorNode:A,sourceNode:C}),V.onLevel?.(0),g=null,R=null,A=null,C=null}}};var F=(V)=>{if(typeof V==="string"&&V.trim())return V;if(V instanceof Error&&V.message.trim())return V.message;if(V&&typeof V==="object"){let g=V;for(let C of["message","reason","description"]){let A=g[C];if(typeof A==="string"&&A.trim())return A}if("error"in g)return F(g.error);if("cause"in g)return F(g.cause);try{return JSON.stringify(V)}catch{}}return"Unexpected error"},i=(V)=>{switch(V.type){case"audio":return{chunk:Uint8Array.from(atob(V.chunkBase64),(g)=>g.charCodeAt(0)),format:V.format,receivedAt:V.receivedAt,turnId:V.turnId,type:"audio"};case"assistant":return{text:V.text,turnId:V.turnId,type:"assistant"};case"assistant_delta":return{delta:V.delta,turnId:V.turnId,type:"assistant_delta"};case"complete":return{sessionId:V.sessionId,type:"complete"};case"connection":return{reconnect:V.reconnect,type:"connection"};case"call_lifecycle":return{event:V.event,sessionId:V.sessionId,type:"call_lifecycle"};case"error":return{message:F(V.message),recoverable:V.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:V.transcript,type:"final"};case"partial":return{transcript:V.transcript,type:"partial"};case"replay":return{assistantTexts:V.assistantTexts,call:V.call,partial:V.partial,scenarioId:V.scenarioId,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,status:V.status,turns:V.turns,type:"replay"};case"session":return{sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,type:"session"};case"turn":return{turn:V.turn,type:"turn"};default:return null}};var UV=Math.PI*2;var N=(V,g,C,A)=>{V.push({code:C,message:A,severity:g})};var P0=(V)=>V.length===0?void 0:V.reduce((g,C)=>g+C,0)/V.length,x=(V)=>V.length===0?void 0:Math.max(...V);var K=(V,g)=>{let C=V[g];return typeof C==="number"&&Number.isFinite(C)?C:void 0},j=(V,g)=>{let C=V[g];return typeof C==="boolean"?C:void 0},E=(V,g)=>{let C=V[g];return typeof C==="string"?C:void 0},f=(V)=>String(V.id??E(V,"ssrc")??K(V,"ssrc")??E(V,"trackIdentifier")??E(V,"mid")??"unknown"),o=(V)=>V===void 0?void 0:V*1000;var B0=(V)=>{let g={};for(let[C,A]of Object.entries(V))if(A===null||typeof A==="boolean"||typeof A==="number"||typeof A==="string")g[C]=A;return g};var n=(V={})=>{let g=V.stats??[],C=[],A=g.filter(($)=>$.type==="inbound-rtp"&&E($,"kind")!=="video"),R=g.filter(($)=>$.type==="outbound-rtp"&&E($,"kind")!=="video"),_=g.filter(($)=>$.type==="candidate-pair"),D=g.filter(($)=>($.type==="track"||$.type==="media-source")&&E($,"kind")==="audio"),X=_.filter(($)=>j($,"selected")===!0||j($,"nominated")===!0||E($,"state")==="succeeded").length,H=D.filter(($)=>E($,"readyState")!=="ended"&&E($,"trackState")!=="ended"&&j($,"ended")!==!0).length,O=D.filter(($)=>E($,"readyState")==="ended"||E($,"trackState")==="ended"||j($,"ended")===!0).length,L=A.reduce(($,S)=>$+(K(S,"packetsReceived")??0),0),W=R.reduce(($,S)=>$+(K(S,"packetsSent")??0),0),U=[...A,...R].reduce(($,S)=>$+Math.max(0,K(S,"packetsLost")??0),0),T=L+U,J=T===0?0:U/T,h=A.reduce(($,S)=>$+(K(S,"bytesReceived")??0),0),Z=R.reduce(($,S)=>$+(K(S,"bytesSent")??0),0),Q=x(_.map(($)=>o(K($,"currentRoundTripTime")??K($,"roundTripTime"))).filter(($)=>$!==void 0)),G=x([...A,...R].map(($)=>o(K($,"jitter"))).filter(($)=>$!==void 0)),c=x(A.map(($)=>{let S=K($,"jitterBufferDelay"),b=K($,"jitterBufferEmittedCount");return S!==void 0&&b!==void 0&&b>0?S/b*1000:void 0}).filter(($)=>$!==void 0)),q=D.map(($)=>K($,"audioLevel")).filter(($)=>$!==void 0);if(V.requireConnectedCandidatePair&&_.length>0&&X===0)N(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(V.requireLiveAudioTrack&&H===0)N(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(V.maxPacketLossRatio!==void 0&&J>V.maxPacketLossRatio)N(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(J)} above ${String(V.maxPacketLossRatio)}.`);if(V.maxRoundTripTimeMs!==void 0&&Q!==void 0&&Q>V.maxRoundTripTimeMs)N(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(Q)}ms above ${String(V.maxRoundTripTimeMs)}ms.`);if(V.maxJitterMs!==void 0&&G!==void 0&&G>V.maxJitterMs)N(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(G)}ms above ${String(V.maxJitterMs)}ms.`);return{activeCandidatePairs:X,audioLevelAverage:P0(q),bytesReceived:h,bytesSent:Z,checkedAt:Date.now(),endedAudioTracks:O,inboundPackets:L,issues:C,jitterBufferDelayMs:c,jitterMs:G,liveAudioTracks:H,outboundPackets:W,packetLossRatio:J,packetsLost:U,roundTripTimeMs:Q,status:C.some(($)=>$.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:g.length}},m=async(V)=>{return[...(await V.peerConnection.getStats(V.selector??null)).values()].map(B0)};var u=(V={})=>{let g=V.stats??[],C=V.previousStats??[],A=[],R=new Map(C.map((U)=>[f(U),U])),D=g.filter((U)=>(U.type==="inbound-rtp"||U.type==="outbound-rtp")&&E(U,"kind")!=="video"&&E(U,"mediaType")!=="video").map((U)=>{let T=U.type==="outbound-rtp"?"outbound":"inbound",J=T==="outbound"?"packetsSent":"packetsReceived",h=T==="outbound"?"bytesSent":"bytesReceived",Z=R.get(f(U)),Q=K(U,J),G=Z?K(Z,J):void 0,c=K(U,h),q=Z?K(Z,h):void 0,$=U.timestamp!==void 0&&Z?.timestamp!==void 0?U.timestamp-Z.timestamp:void 0;return{bytesDelta:c!==void 0&&q!==void 0?c-q:void 0,currentPackets:Q,direction:T,id:f(U),packetDelta:Q!==void 0&&G!==void 0?Q-G:void 0,previousPackets:G,timeDeltaMs:$}}),X=D.filter((U)=>U.direction==="inbound"),H=D.filter((U)=>U.direction==="outbound"),O=x(D.map((U)=>U.timeDeltaMs).filter((U)=>U!==void 0)),L=X.filter((U)=>V.maxInboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxInboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length,W=H.filter((U)=>V.maxOutboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxOutboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length;if(V.requireInboundAudio&&X.length===0)N(A,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(V.requireOutboundAudio&&H.length===0)N(A,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(V.maxGapMs!==void 0&&O!==void 0&&O>V.maxGapMs)N(A,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(O)}ms above ${String(V.maxGapMs)}ms.`);if(L>0)N(A,"error","media.webrtc_inbound_stalled",`${String(L)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(W>0)N(A,"error","media.webrtc_outbound_stalled",`${String(W)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:X.length,issues:A,maxObservedGapMs:O,outboundAudioStreams:H.length,stalledInboundStreams:L,stalledOutboundStreams:W,status:A.some((U)=>U.severity==="error")?"fail":A.length>0?"warn":"pass",streams:D,totalStats:g.length}};var M0="/api/voice/browser-media",b0=5000,j0=async(V)=>V.peerConnection??await V.getPeerConnection?.()??null,x0=async(V,g)=>{let C=g.fetch??globalThis.fetch;if(!C)return;await C(g.path??M0,{body:JSON.stringify(V),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(V)=>{let g=null,C=[],A=async()=>{let D=await j0(V);if(!D)return;let X=await m({peerConnection:D}),H=n({...V,stats:X}),O=V.continuity===!1?void 0:u({...V.continuity,previousStats:C,stats:X}),L={at:Date.now(),continuity:O,report:H,scenarioId:V.getScenarioId?.()??null,sessionId:V.getSessionId?.()??null};return C=X,V.onReport?.(L),await x0(L,V),L},R=()=>{A().catch((D)=>{V.onError?.(D)})},_=()=>{if(g)clearInterval(g),g=null};return{close:_,reportOnce:A,stop:_,start:()=>{if(g)return;R(),g=setInterval(R,V.intervalMs??b0)}}};var k0=(V,g,C)=>Math.min(C,g*2**(Math.max(1,V)-1));class s extends Error{constructor(V="Voice authorization could not be renewed."){super(V);this.name="VoiceReconnectRejectedError"}}var P=()=>{},F0=()=>Promise.resolve(),f0=()=>P,l0={callControl:F0,close:P,disconnect:P,endTurn:P,send:P,sendAudio:P,simulateDisconnect:P,subscribe:f0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},d0=()=>crypto.randomUUID(),v0=(V,g,C,A)=>{let{hostname:R,port:_,protocol:D}=window.location,X=D==="https:"?"wss:":"ws:",H=_?`:${_}`:"",O=new URL(`${X}//${R}${H}${V}`);if(O.searchParams.set("sessionId",g),C)O.searchParams.set("scenarioId",C);for(let[L,W]of Object.entries(A))if(L!=="sessionId"&&L!=="scenarioId"&&W)O.searchParams.set(L,W);return O.toString()},i0=(V)=>{if(!V||typeof V!=="object"||!("type"in V))return!1;switch(V.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},o0=(V)=>{if(typeof V.data!=="string")return null;try{let g=JSON.parse(V.data);return i0(g)?g:null}catch{return null}},a=(V,g={})=>{if(typeof window>"u")return l0;let C=new Set,A=new Map,R=g.reconnect!==!1,_=g.maxReconnectAttempts??15,D=g.reconnectMaxDelayMs??8000,X=g.pingInterval??30000,H=g.reconnectResetAfterMs??30000,O=0,L=!1,W=null,U=(I)=>k0(I,500,D),T={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:g.sessionId??d0(),ws:null},J=(I)=>{C.forEach((w)=>w(I))},h=(I)=>{C.forEach((w)=>w({message:I,recoverable:!1,type:"error"})),J({reconnect:{attempts:T.reconnectAttempts,maxAttempts:_,status:"exhausted"},type:"connection"})},Z=()=>{if(T.pingInterval)clearInterval(T.pingInterval),T.pingInterval=null;if(T.reconnectTimeout)clearTimeout(T.reconnectTimeout),T.reconnectTimeout=null;if(T.reconnectResetTimeout)clearTimeout(T.reconnectResetTimeout),T.reconnectResetTimeout=null},Q=()=>{if(T.ws?.readyState!==1)return;while(T.pendingMessages.length>0){let I=T.pendingMessages.shift();if(I!==void 0)T.ws.send(I)}},G=(I)=>{for(let w of A.values())clearTimeout(w.timeout),w.reject(Error(I));A.clear()},c=()=>{if(L)return;let I=O;T.reconnectAttempts+=1;let w=U(T.reconnectAttempts),y=Date.now()+w;J({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,nextAttemptAt:y,status:"reconnecting"},type:"connection"}),T.reconnectTimeout=setTimeout(async()=>{if(L||O!==I)return;if(T.reconnectAttempts>_){h("Voice connection could not be restored.");return}try{if(g.prepareReconnect){let Y=new AbortController;W=Y;let B=setTimeout(()=>Y.abort("Voice reconnect preparation timed out"),g.prepareReconnectTimeoutMs??1e4);try{await Promise.race([g.prepareReconnect({attempt:T.reconnectAttempts,path:V,scenarioId:T.scenarioId,sessionId:T.sessionId,signal:Y.signal}),new Promise((M,O0)=>{Y.signal.addEventListener("abort",()=>O0(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(B),W===Y)W=null}}}catch(Y){if(L||O!==I)return;if(Y instanceof s){h(Y.message);return}if(T.reconnectAttempts<_)c();else h("Voice authorization could not be renewed for reconnect.");return}if(L||O!==I)return;q()},w)},q=()=>{if(L)return;let I=new WebSocket(v0(V,T.sessionId,T.scenarioId,g.query??{}));I.binaryType="arraybuffer",I.onopen=()=>{if(T.ws!==I){I.close(1000);return}let w=T.reconnectAttempts>0;if(T.isConnected=!0,Q(),w)J({reconnect:{attempts:T.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:_,status:"resumed"},type:"connection"}),T.reconnectResetTimeout=setTimeout(()=>{if(T.ws===I&&I.readyState===1)T.reconnectAttempts=0;T.reconnectResetTimeout=null},H);C.forEach((y)=>y({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,status:"active",type:"session"})),T.pingInterval=setInterval(()=>{if(I.readyState===1)I.send(JSON.stringify({type:"ping"}))},X)},I.onmessage=(w)=>{if(T.ws!==I)return;let y=o0(w);if(!y)return;if(y.type==="session")T.sessionId=y.sessionId,T.scenarioId=y.scenarioId??T.scenarioId;if(y.type==="call_control_ack"){let Y=A.get(y.requestId);if(Y)if(clearTimeout(Y.timeout),A.delete(y.requestId),y.ok)Y.resolve();else Y.reject(Error(y.message??`${y.action} was not applied`))}C.forEach((Y)=>Y(y))},I.onclose=(w)=>{if(T.ws!==I)return;T.ws=null,T.isConnected=!1,Z(),G("Voice connection interrupted");let y=R&&w.code!==1000&&w.code!==4401&&w.code!==4403&&w.code!==4500&&T.reconnectAttempts<_,Y=w.code===4401||w.code===4403,B=w.code===4500;if(Y)C.forEach((M)=>M({message:w.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(B)C.forEach((M)=>M({message:"Voice provider initialization failed.",recoverable:!1,type:"error"}));if(y)c();else if(R&&w.code!==1000){if(Y)J({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,status:"exhausted"},type:"connection"});else if(!B)h("Voice connection could not be restored.")}},T.ws=I},$=(I)=>{if(L)return;if(T.ws?.readyState===1){T.ws.send(I);return}if(typeof I!=="string")return;if(T.pendingMessages.length>=100)T.pendingMessages.shift();T.pendingMessages.push(I)},S=(I)=>{$(JSON.stringify(I))},b=(I={})=>{if(I.sessionId&&I.sessionId!==T.sessionId)throw Error("Voice session switching requires a new connection instance.");if(I.sessionId)T.sessionId=I.sessionId;if(I.scenarioId)T.scenarioId=I.scenarioId;S({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,type:"start"})},I0=(I)=>{$(I)},U0=()=>{S({type:"end_turn"})},L0=(I)=>{if(T.ws?.readyState!==1)return Promise.reject(Error(`${I.action} is unavailable while disconnected`));let w=crypto.randomUUID(),{promise:y,reject:Y,resolve:B}=Promise.withResolvers(),M=setTimeout(()=>{A.delete(w),Y(Error(`${I.action} acknowledgement timed out`))},5000);return A.set(w,{reject:Y,resolve:B,timeout:M}),T.ws.send(JSON.stringify({...I,requestId:w,type:"call_control"})),y},W0=(I="client-close")=>{if(L=!0,W?.abort(),W=null,O+=1,Z(),G("Voice connection closed"),T.pendingMessages.length=0,T.ws){let w=T.ws;if(T.ws=null,w.readyState===1)w.send(JSON.stringify({reason:I,type:"close"}));w.close(1000)}T.isConnected=!1,C.clear()},D0=()=>{if(L=!0,W?.abort(),W=null,O+=1,Z(),G("Voice connection disconnected"),T.pendingMessages.length=0,T.ws){let I=T.ws;T.ws=null,I.close(1000)}T.isConnected=!1,C.clear()},X0=()=>{if(T.ws?.readyState===1)T.ws.close(4000,"absolutejs-voice-reconnect-proof")},G0=(I)=>{return C.add(I),()=>{C.delete(I)}};return q(),{callControl:L0,close:W0,disconnect:D0,endTurn:U0,send:S,sendAudio:I0,simulateDisconnect:X0,start:b,subscribe:G0,getReadyState:()=>T.ws?.readyState??3,getScenarioId:()=>T.scenarioId??"",getSessionId:()=>T.sessionId}};var n0=()=>({attempts:0,maxAttempts:0,status:"idle"}),m0=(V,g)=>{let C=g.trim().replace(/\s+/g," ");if(!C)return V;if(!V)return C;if(V===C||V.endsWith(C))return V;if(C.includes(V))return C;return`${V} ${C}`},u0=(V,g)=>{let C=g.trim().replace(/\s+/g," ");if(!V)return C;if(!C||V.endsWith(C))return V;return`${V} ${C}`},r0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:n0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),p=()=>{let V=r0(),g="",C=new Set,A=()=>{C.forEach((_)=>_())};return{dispatch:(_)=>{switch(_.type){case"audio":V={...V,assistantAudio:[...V.assistantAudio,{chunk:_.chunk,format:_.format,receivedAt:_.receivedAt,turnId:_.turnId}]};break;case"assistant":V={...V,assistantStreamingText:"",assistantTexts:[...V.assistantTexts,_.text]};break;case"assistant_delta":V={...V,assistantStreamingText:`${V.assistantStreamingText}${_.delta}`};break;case"complete":V={...V,sessionId:_.sessionId,status:"completed"};break;case"call_lifecycle":V={...V,call:{...V.call,disposition:_.event.type==="end"?_.event.disposition:V.call?.disposition,endedAt:_.event.type==="end"?_.event.at:V.call?.endedAt,events:[...V.call?.events??[],_.event],lastEventAt:_.event.at,startedAt:V.call?.startedAt??_.event.at},sessionId:_.sessionId};break;case"connected":V={...V,isConnected:!0,reconnect:V.reconnect.status==="reconnecting"?{...V.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:V.reconnect};break;case"connection":V={...V,reconnect:_.reconnect};break;case"disconnected":V={...V,isConnected:!1};break;case"error":V={...V,error:_.message,..._.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":g=m0(g,_.transcript.text),V={...V,partial:g};break;case"partial":V={...V,partial:u0(g,_.transcript.text)};break;case"replay":g=_.partial,V={...V,assistantStreamingText:"",assistantTexts:[..._.assistantTexts],call:_.call??null,error:null,isConnected:_.status==="active",partial:_.partial,reconnect:V.reconnect.status==="reconnecting"?{...V.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:V.reconnect,scenarioId:_.scenarioId??V.scenarioId,sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??V.sessionMetadata,status:_.status,turns:[..._.turns]};break;case"session":V={...V,error:null,scenarioId:_.scenarioId??V.scenarioId,isConnected:_.status==="active",sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??V.sessionMetadata,status:_.status};break;case"turn":g="",V={...V,partial:"",turns:[...V.turns,_.turn]};break}A()},getServerSnapshot:()=>V,getSnapshot:()=>V,subscribe:(_)=>{return C.add(_),()=>{C.delete(_)}}}};var t=(V,g={})=>{let C=a(V,g),A=p(),R=g.browserMedia&&typeof window<"u"?r({...g.browserMedia,getScenarioId:()=>g.browserMedia?g.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>g.browserMedia?g.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,_=new Set,D=!1,X=(W)=>Promise.resolve().then(()=>{if(D)return;if(!W?.sessionId&&!W?.scenarioId)return;C.start(W),R?.start()}),H=()=>{_.forEach((W)=>W())},O=()=>{if(!g.reconnectReportPath||typeof fetch>"u")return;let W=A.getSnapshot(),U=JSON.stringify({at:Date.now(),reconnect:W.reconnect,scenarioId:W.scenarioId,sessionId:C.getSessionId(),turnIds:W.turns.map((T)=>T.id)});fetch(g.reconnectReportPath,{body:U,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=C.subscribe((W)=>{let U=i(W);if(U){if(A.dispatch(U),W.type==="connection")O();H()}});return{start:X,get assistantAudio(){return A.getSnapshot().assistantAudio},get assistantTexts(){return A.getSnapshot().assistantTexts},get assistantStreamingText(){return A.getSnapshot().assistantStreamingText},get call(){return A.getSnapshot().call},callControl(W){return C.callControl(W)},close(W){D=!0,L(),R?.close(),C.close(W),A.dispatch({type:"disconnected"}),H()},disconnect(){D=!0,L(),R?.close(),C.disconnect(),A.dispatch({type:"disconnected"}),H()},endTurn(){C.endTurn()},get error(){return A.getSnapshot().error},getServerSnapshot(){return A.getServerSnapshot()},getSnapshot(){return A.getSnapshot()},get isConnected(){return A.getSnapshot().isConnected},get partial(){return A.getSnapshot().partial},get reconnect(){return A.getSnapshot().reconnect},get scenarioId(){return A.getSnapshot().scenarioId},sendAudio(W){C.sendAudio(W)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return A.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return A.getSnapshot().status},subscribe(W){return _.add(W),()=>{_.delete(W)}},get turns(){return A.getSnapshot().turns}}};var e=(V)=>{if(!V||V.enabled===!1)return;return{enabled:!0,maxGain:V.maxGain??3,noiseGateAttenuation:V.noiseGateAttenuation??0.15,noiseGateThreshold:V.noiseGateThreshold??0.006,targetLevel:V.targetLevel??0.08}};var s0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},a0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var V0=(V)=>{let g=V?.profile??"fast",C=V?.qualityProfile??"general",A=s0[g],R=a0[C],_=V?.silenceMs??R.silenceMs??A.silenceMs;return{profile:g,qualityProfile:C,minSilenceMs:Math.min(_,V?.minSilenceMs??R.minSilenceMs??A.minSilenceMs),silenceMs:_,speechThreshold:V?.speechThreshold??R.speechThreshold??A.speechThreshold,transcriptStabilityMs:V?.transcriptStabilityMs??R.transcriptStabilityMs??A.transcriptStabilityMs}};var p0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},g0=(V="default")=>{let g=p0[V];return{audioConditioning:e(g.audioConditioning),capture:{channelCount:g.capture?.channelCount??1,sampleRateHz:g.capture?.sampleRateHz??16000},connection:{...g.connection},name:V,sttLifecycle:g.sttLifecycle??"continuous",turnDetection:V0(g.turnDetection)}};var t0=(V)=>({assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,isRecording:!1,partial:V.partial,reconnect:V.reconnect,recordingError:null,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]}),A0=(V,g={})=>{let C=g0(g.preset),A=t(V,{...C.connection,...g.connection}),R=null,_=0,D=!1,X=null,H=t0(A),O=new Set,L=()=>{for(let G of O)G()},W=()=>{if(H={...H,assistantAudio:[...A.assistantAudio],assistantStreamingText:A.assistantStreamingText,assistantTexts:[...A.assistantTexts],call:A.call,error:A.error,isConnected:A.isConnected,partial:A.partial,reconnect:A.reconnect,sessionId:A.sessionId,sessionMetadata:A.sessionMetadata,scenarioId:A.scenarioId,status:A.status,turns:[...A.turns]},g.autoStopOnComplete!==!1&&H.status==="completed"&&H.isRecording)R?.stop(),R=null,H={...H,isRecording:!1};L()},U=A.subscribe(W);W();let T=()=>{if(R)return R;return R=v({channelCount:g.capture?.channelCount??C.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(G)=>{if(g.capture?.onAudio){g.capture.onAudio(G,A.sendAudio);return}A.sendAudio(G)},sampleRateHz:g.capture?.sampleRateHz??C.capture.sampleRateHz,...g.capture?.stream?{stream:g.capture.stream}:{}}),R},J=()=>{_+=1,R?.stop(),R=null,H={...H,isRecording:!1},L()},h=async()=>{if(D)throw Error("Voice controller is closed.");if(H.isRecording)return;if(X)return X;let G=++_,c=T(),$=(async()=>{try{if(H={...H,recordingError:null},L(),await c.start(),D||G!==_||R!==c){c.stop();return}H={...H,isRecording:!0},L()}catch(S){if(c.stop(),G!==_||R!==c)throw S;throw R=null,H={...H,isRecording:!1,recordingError:S instanceof Error?S.message:String(S)},L(),S}})().finally(()=>{if(X===$)X=null});return X=$,X};return{close:(G)=>{D=!0,U(),J(),A.close(G)},disconnect:()=>{D=!0,U(),J(),A.disconnect()},startRecording:h,stopRecording:J,get assistantAudio(){return H.assistantAudio},get assistantTexts(){return H.assistantTexts},get assistantStreamingText(){return H.assistantStreamingText},bindHTMX(G){return d(A,G)},get call(){return H.call},callControl:(G)=>A.callControl(G),endTurn:()=>A.endTurn(),get error(){return H.error},getServerSnapshot:()=>H,getSnapshot:()=>H,get isConnected(){return H.isConnected},get isRecording(){return H.isRecording},get partial(){return H.partial},get reconnect(){return H.reconnect},get recordingError(){return H.recordingError},get scenarioId(){return H.scenarioId},sendAudio:(G)=>A.sendAudio(G),get sessionId(){return H.sessionId},get sessionMetadata(){return H.sessionMetadata},simulateDisconnect:()=>A.simulateDisconnect(),get status(){return H.status},subscribe:(G)=>{return O.add(G),()=>{O.delete(G)}},toggleRecording:async()=>{if(H.isRecording){J();return}await h()},get turns(){return H.turns}}};var z=(V)=>String(V).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var C0=(V)=>{if(!V.isConnected)return"idle";if(V.isPlaying)return"speaking";if(V.isRecording&&V.hasActivePartial)return"listening";if(V.isRecording)return"listening";if(V.lastTranscriptAt&&!V.lastAssistantAt)return"thinking";if(V.lastTranscriptAt&&V.lastAssistantAt&&V.lastTranscriptAt>V.lastAssistantAt)return"thinking";return"idle"};var e0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},VV={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},gV=(V,g)=>{switch(V){case"listening":return g.listening;case"speaking":return g.speaking;case"thinking":return g.thinking;case"idle":return g.idle}},_0=(V)=>{let g={...e0,...V.theme},C={...VV,...V.labels},A=V.state.assistantAudio.at(-1)?.receivedAt,R=V.state.turns.at(-1)?.committedAt,_=C0({hasActivePartial:V.state.partial.length>0,isConnected:V.state.isConnected,isPlaying:!1,isRecording:V.state.isRecording,lastAssistantAt:A,lastTranscriptAt:R}),D=!V.state.isConnected&&V.state.status!=="idle"&&!V.state.error,X=V.state.error?"Error":D?C.connecting:V.state.status==="completed"?C.callEnded:gV(_,C);return{agentState:_,classes:{container:`absolute-voice-widget absolute-voice-widget--${_}`,dot:`absolute-voice-widget__dot${V.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:V.state.isConnected,canMute:V.state.isRecording,canStart:!V.state.isRecording&&V.state.status!=="completed"},errorMessage:V.state.error??void 0,labels:C,partial:V.state.partial||void 0,statusLabel:X,theme:g,title:V.title??"Voice"}},AV=(V)=>typeof V==="number"?`${V}px`:V,T0=(V)=>{let g=V.theme,C=`background:${g.background};border-radius:${AV(g.radius)};color:${g.foreground};font-family:${g.fontFamily};min-width:240px;padding:20px 22px;`,A=`background:${V.errorMessage?g.errorAccent:V.agentState==="idle"?"rgba(148,163,184,0.6)":g.accent};border-radius:50%;height:10px;width:10px;`,R=[];if(V.controls.canStart)R.push(`<button type="button" data-action="start" style="background:${g.accent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${z(V.labels.startCall)}</button>`);if(V.controls.canMute)R.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${z(V.labels.mute)}</button>`);if(V.controls.canEnd)R.push(`<button type="button" data-action="end" style="background:${g.errorAccent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${z(V.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${V.agentState}" class="${z(V.classes.container)}" style="${C}">
|
|
1
|
+
(()=>{var{defineProperty:k,getOwnPropertyNames:S0,getOwnPropertyDescriptor:w0}=Object,J0=Object.prototype.hasOwnProperty;function h0(V){return this[V]}var Y0=(V)=>{var A=(l??=new WeakMap).get(V),C;if(A)return A;if(A=k({},"__esModule",{value:!0}),V&&typeof V==="object"||typeof V==="function"){for(var g of S0(V))if(!J0.call(A,g))k(A,g,{get:h0.bind(V,g),enumerable:!(C=w0(V,g))||C.enumerable})}return l.set(V,A),A},l;var Z0=(V)=>V;function y0(V,A){this[V]=Z0.bind(null,A)}var Q0=(V,A)=>{for(var C in A)k(V,C,{get:A[C],enumerable:!0,configurable:!0,set:y0.bind(A,C)})};var _V={};Q0(_V,{mount:()=>$0,default:()=>TV,VOICE_EMBED_VERSION:()=>R0});var E0=(V)=>{if(typeof V!=="string")return V;return document.querySelector(V)},K0=(V,A,C,g)=>{let H=A??V.getAttribute("hx-get")??"";if(!H)return"";let _=new URL(H,window.location.origin);if(g)_.searchParams.set(C,g);else _.searchParams.delete(C);return`${_.pathname}${_.search}${_.hash}`},d=(V,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=E0(A.element);if(!C)return()=>{};let g=A.eventName??"voice-refresh",H=A.sessionQueryParam??"sessionId",_=()=>{let X=window,R=K0(C,A.route,H,V.sessionId);if(R)C.setAttribute("hx-get",R);X.htmx?.process?.(C),X.htmx?.trigger?.(C,g)},D=V.subscribe(_);return _(),()=>{D()}};var c0=(V)=>Math.max(-1,Math.min(1,V)),q0=(V)=>{let A=new Int16Array(V.length);for(let C=0;C<V.length;C+=1){let g=c0(V[C]??0);A[C]=g<0?g*32768:g*32767}return new Uint8Array(A.buffer)},N0=(V)=>{let A=V instanceof Uint8Array?V:new Uint8Array(V);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let g=0;for(let H of C){let _=H/32768;g+=_*_}return Math.min(1,Math.max(0,Math.sqrt(g/C.length)*5.5))},z0=(V,A,C)=>{if(A===C)return V;let g=A/C,H=Math.round(V.length/g),_=new Float32Array(H),D=0,X=0;while(D<_.length){let R=Math.round((D+1)*g),O=0,L=0;for(let W=X;W<R&&W<V.length;W+=1)O+=V[W]??0,L+=1;_[D]=L>0?O/L:0,D+=1,X=R}return _},v=(V)=>{let A=null,C=null,g=null,H=null,_=0,D=null,X=(L)=>{L.processorNode?.disconnect(),L.sourceNode?.disconnect(),L.mediaStream?.getTracks().forEach((W)=>W.stop()),L.audioContext?.close()};return{start:()=>{if(H)return Promise.resolve();if(D)return D;let L=++_,U=(async()=>{if(!V.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let T=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!T)throw Error("Browser microphone capture requires AudioContext support.");let w=null,Z=null,Y=null,Q=null;try{if(Z=V.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:V.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),L!==_)throw Error("Microphone capture stopped during startup.");if(w=new T,w.state==="suspended")await w.resume();if(L!==_)throw Error("Microphone capture stopped during startup.");if(Q=w.createMediaStreamSource(Z),Y=w.createScriptProcessor(4096,1,1),Y.onaudioprocess=(G)=>{let K=G.inputBuffer.getChannelData(0),q=z0(K,w?.sampleRate??48000,V.sampleRateHz??16000),$=q0(q);V.onLevel?.(N0($)),V.onAudio($)},Q.connect(Y),Y.connect(w.destination),L!==_)throw Error("Microphone capture stopped during startup.");A=w,H=Z,g=Y,C=Q}catch(G){throw X({audioContext:w,mediaStream:Z,processorNode:Y,sourceNode:Q}),G}})().finally(()=>{if(D===U)D=null});return D=U,U},stop:()=>{_+=1,X({audioContext:A,mediaStream:H,processorNode:g,sourceNode:C}),V.onLevel?.(0),A=null,H=null,g=null,C=null}}};var F=(V)=>{if(typeof V==="string"&&V.trim())return V;if(V instanceof Error&&V.message.trim())return V.message;if(V&&typeof V==="object"){let A=V;for(let C of["message","reason","description"]){let g=A[C];if(typeof g==="string"&&g.trim())return g}if("error"in A)return F(A.error);if("cause"in A)return F(A.cause);try{return JSON.stringify(V)}catch{}}return"Unexpected error"},i=(V)=>{switch(V.type){case"audio":return{chunk:Uint8Array.from(atob(V.chunkBase64),(A)=>A.charCodeAt(0)),format:V.format,receivedAt:V.receivedAt,turnId:V.turnId,type:"audio"};case"assistant":return{text:V.text,turnId:V.turnId,type:"assistant"};case"assistant_delta":return{delta:V.delta,turnId:V.turnId,type:"assistant_delta"};case"complete":return{sessionId:V.sessionId,type:"complete"};case"connection":return{reconnect:V.reconnect,type:"connection"};case"call_lifecycle":return{event:V.event,sessionId:V.sessionId,type:"call_lifecycle"};case"error":return{message:F(V.message),recoverable:V.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:V.transcript,type:"final"};case"partial":return{transcript:V.transcript,type:"partial"};case"replay":return{assistantTexts:V.assistantTexts,call:V.call,partial:V.partial,scenarioId:V.scenarioId,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,status:V.status,turns:V.turns,type:"replay"};case"session":return{paused:V.paused,pauseExpiresAt:V.pauseExpiresAt,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,type:"session"};case"turn":return{turn:V.turn,type:"turn"};default:return null}};var UV=Math.PI*2;var N=(V,A,C,g)=>{V.push({code:C,message:g,severity:A})};var P0=(V)=>V.length===0?void 0:V.reduce((A,C)=>A+C,0)/V.length,x=(V)=>V.length===0?void 0:Math.max(...V);var E=(V,A)=>{let C=V[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},j=(V,A)=>{let C=V[A];return typeof C==="boolean"?C:void 0},c=(V,A)=>{let C=V[A];return typeof C==="string"?C:void 0},f=(V)=>String(V.id??c(V,"ssrc")??E(V,"ssrc")??c(V,"trackIdentifier")??c(V,"mid")??"unknown"),o=(V)=>V===void 0?void 0:V*1000;var B0=(V)=>{let A={};for(let[C,g]of Object.entries(V))if(g===null||typeof g==="boolean"||typeof g==="number"||typeof g==="string")A[C]=g;return A};var n=(V={})=>{let A=V.stats??[],C=[],g=A.filter(($)=>$.type==="inbound-rtp"&&c($,"kind")!=="video"),H=A.filter(($)=>$.type==="outbound-rtp"&&c($,"kind")!=="video"),_=A.filter(($)=>$.type==="candidate-pair"),D=A.filter(($)=>($.type==="track"||$.type==="media-source")&&c($,"kind")==="audio"),X=_.filter(($)=>j($,"selected")===!0||j($,"nominated")===!0||c($,"state")==="succeeded").length,R=D.filter(($)=>c($,"readyState")!=="ended"&&c($,"trackState")!=="ended"&&j($,"ended")!==!0).length,O=D.filter(($)=>c($,"readyState")==="ended"||c($,"trackState")==="ended"||j($,"ended")===!0).length,L=g.reduce(($,J)=>$+(E(J,"packetsReceived")??0),0),W=H.reduce(($,J)=>$+(E(J,"packetsSent")??0),0),U=[...g,...H].reduce(($,J)=>$+Math.max(0,E(J,"packetsLost")??0),0),T=L+U,w=T===0?0:U/T,Z=g.reduce(($,J)=>$+(E(J,"bytesReceived")??0),0),Y=H.reduce(($,J)=>$+(E(J,"bytesSent")??0),0),Q=x(_.map(($)=>o(E($,"currentRoundTripTime")??E($,"roundTripTime"))).filter(($)=>$!==void 0)),G=x([...g,...H].map(($)=>o(E($,"jitter"))).filter(($)=>$!==void 0)),K=x(g.map(($)=>{let J=E($,"jitterBufferDelay"),b=E($,"jitterBufferEmittedCount");return J!==void 0&&b!==void 0&&b>0?J/b*1000:void 0}).filter(($)=>$!==void 0)),q=D.map(($)=>E($,"audioLevel")).filter(($)=>$!==void 0);if(V.requireConnectedCandidatePair&&_.length>0&&X===0)N(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(V.requireLiveAudioTrack&&R===0)N(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(V.maxPacketLossRatio!==void 0&&w>V.maxPacketLossRatio)N(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(w)} above ${String(V.maxPacketLossRatio)}.`);if(V.maxRoundTripTimeMs!==void 0&&Q!==void 0&&Q>V.maxRoundTripTimeMs)N(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(Q)}ms above ${String(V.maxRoundTripTimeMs)}ms.`);if(V.maxJitterMs!==void 0&&G!==void 0&&G>V.maxJitterMs)N(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(G)}ms above ${String(V.maxJitterMs)}ms.`);return{activeCandidatePairs:X,audioLevelAverage:P0(q),bytesReceived:Z,bytesSent:Y,checkedAt:Date.now(),endedAudioTracks:O,inboundPackets:L,issues:C,jitterBufferDelayMs:K,jitterMs:G,liveAudioTracks:R,outboundPackets:W,packetLossRatio:w,packetsLost:U,roundTripTimeMs:Q,status:C.some(($)=>$.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},m=async(V)=>{return[...(await V.peerConnection.getStats(V.selector??null)).values()].map(B0)};var u=(V={})=>{let A=V.stats??[],C=V.previousStats??[],g=[],H=new Map(C.map((U)=>[f(U),U])),D=A.filter((U)=>(U.type==="inbound-rtp"||U.type==="outbound-rtp")&&c(U,"kind")!=="video"&&c(U,"mediaType")!=="video").map((U)=>{let T=U.type==="outbound-rtp"?"outbound":"inbound",w=T==="outbound"?"packetsSent":"packetsReceived",Z=T==="outbound"?"bytesSent":"bytesReceived",Y=H.get(f(U)),Q=E(U,w),G=Y?E(Y,w):void 0,K=E(U,Z),q=Y?E(Y,Z):void 0,$=U.timestamp!==void 0&&Y?.timestamp!==void 0?U.timestamp-Y.timestamp:void 0;return{bytesDelta:K!==void 0&&q!==void 0?K-q:void 0,currentPackets:Q,direction:T,id:f(U),packetDelta:Q!==void 0&&G!==void 0?Q-G:void 0,previousPackets:G,timeDeltaMs:$}}),X=D.filter((U)=>U.direction==="inbound"),R=D.filter((U)=>U.direction==="outbound"),O=x(D.map((U)=>U.timeDeltaMs).filter((U)=>U!==void 0)),L=X.filter((U)=>V.maxInboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxInboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length,W=R.filter((U)=>V.maxOutboundPacketStallMs!==void 0&&U.timeDeltaMs!==void 0&&U.timeDeltaMs>=V.maxOutboundPacketStallMs&&U.packetDelta!==void 0&&U.packetDelta<=0).length;if(V.requireInboundAudio&&X.length===0)N(g,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(V.requireOutboundAudio&&R.length===0)N(g,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(V.maxGapMs!==void 0&&O!==void 0&&O>V.maxGapMs)N(g,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(O)}ms above ${String(V.maxGapMs)}ms.`);if(L>0)N(g,"error","media.webrtc_inbound_stalled",`${String(L)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(W>0)N(g,"error","media.webrtc_outbound_stalled",`${String(W)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:X.length,issues:g,maxObservedGapMs:O,outboundAudioStreams:R.length,stalledInboundStreams:L,stalledOutboundStreams:W,status:g.some((U)=>U.severity==="error")?"fail":g.length>0?"warn":"pass",streams:D,totalStats:A.length}};var M0="/api/voice/browser-media",b0=5000,j0=async(V)=>V.peerConnection??await V.getPeerConnection?.()??null,x0=async(V,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??M0,{body:JSON.stringify(V),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(V)=>{let A=null,C=[],g=async()=>{let D=await j0(V);if(!D)return;let X=await m({peerConnection:D}),R=n({...V,stats:X}),O=V.continuity===!1?void 0:u({...V.continuity,previousStats:C,stats:X}),L={at:Date.now(),continuity:O,report:R,scenarioId:V.getScenarioId?.()??null,sessionId:V.getSessionId?.()??null};return C=X,V.onReport?.(L),await x0(L,V),L},H=()=>{g().catch((D)=>{V.onError?.(D)})},_=()=>{if(A)clearInterval(A),A=null};return{close:_,reportOnce:g,stop:_,start:()=>{if(A)return;H(),A=setInterval(H,V.intervalMs??b0)}}};var k0=(V,A,C)=>Math.min(C,A*2**(Math.max(1,V)-1));class s extends Error{constructor(V="Voice authorization could not be renewed."){super(V);this.name="VoiceReconnectRejectedError"}}var P=()=>{},F0=()=>Promise.resolve(),f0=()=>P,l0={callControl:F0,close:P,disconnect:P,endTurn:P,send:P,sendAudio:P,simulateDisconnect:P,subscribe:f0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},d0=()=>crypto.randomUUID(),v0=(V,A,C,g)=>{let{hostname:H,port:_,protocol:D}=window.location,X=D==="https:"?"wss:":"ws:",R=_?`:${_}`:"",O=new URL(`${X}//${H}${R}${V}`);if(O.searchParams.set("sessionId",A),C)O.searchParams.set("scenarioId",C);for(let[L,W]of Object.entries(g))if(L!=="sessionId"&&L!=="scenarioId"&&W)O.searchParams.set(L,W);return O.toString()},i0=(V)=>{if(!V||typeof V!=="object"||!("type"in V))return!1;switch(V.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},o0=(V)=>{if(typeof V.data!=="string")return null;try{let A=JSON.parse(V.data);return i0(A)?A:null}catch{return null}},a=(V,A={})=>{if(typeof window>"u")return l0;let C=new Set,g=new Map,H=A.reconnect!==!1,_=A.maxReconnectAttempts??15,D=A.reconnectMaxDelayMs??8000,X=A.pingInterval??30000,R=A.reconnectResetAfterMs??30000,O=0,L=!1,W=null,U=(I)=>k0(I,500,D),T={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:A.sessionId??d0(),ws:null},w=(I)=>{C.forEach((S)=>S(I))},Z=(I)=>{C.forEach((S)=>S({message:I,recoverable:!1,type:"error"})),w({reconnect:{attempts:T.reconnectAttempts,maxAttempts:_,status:"exhausted"},type:"connection"})},Y=()=>{if(T.pingInterval)clearInterval(T.pingInterval),T.pingInterval=null;if(T.reconnectTimeout)clearTimeout(T.reconnectTimeout),T.reconnectTimeout=null;if(T.reconnectResetTimeout)clearTimeout(T.reconnectResetTimeout),T.reconnectResetTimeout=null},Q=()=>{if(T.ws?.readyState!==1)return;while(T.pendingMessages.length>0){let I=T.pendingMessages.shift();if(I!==void 0)T.ws.send(I)}},G=(I)=>{for(let S of g.values())clearTimeout(S.timeout),S.reject(Error(I));g.clear()},K=()=>{if(L)return;let I=O;T.reconnectAttempts+=1;let S=U(T.reconnectAttempts),y=Date.now()+S;w({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,nextAttemptAt:y,status:"reconnecting"},type:"connection"}),T.reconnectTimeout=setTimeout(async()=>{if(L||O!==I)return;if(T.reconnectAttempts>_){Z("Voice connection could not be restored.");return}try{if(A.prepareReconnect){let h=new AbortController;W=h;let B=setTimeout(()=>h.abort("Voice reconnect preparation timed out"),A.prepareReconnectTimeoutMs??1e4);try{await Promise.race([A.prepareReconnect({attempt:T.reconnectAttempts,path:V,scenarioId:T.scenarioId,sessionId:T.sessionId,signal:h.signal}),new Promise((M,O0)=>{h.signal.addEventListener("abort",()=>O0(Error("Voice reconnect preparation timed out.")),{once:!0})})])}finally{if(clearTimeout(B),W===h)W=null}}}catch(h){if(L||O!==I)return;if(h instanceof s){Z(h.message);return}if(T.reconnectAttempts<_)K();else Z("Voice authorization could not be renewed for reconnect.");return}if(L||O!==I)return;q()},S)},q=()=>{if(L)return;let I=new WebSocket(v0(V,T.sessionId,T.scenarioId,A.query??{}));I.binaryType="arraybuffer",I.onopen=()=>{if(T.ws!==I){I.close(1000);return}let S=T.reconnectAttempts>0;if(T.isConnected=!0,Q(),S)w({reconnect:{attempts:T.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:_,status:"resumed"},type:"connection"}),T.reconnectResetTimeout=setTimeout(()=>{if(T.ws===I&&I.readyState===1)T.reconnectAttempts=0;T.reconnectResetTimeout=null},R);T.pingInterval=setInterval(()=>{if(I.readyState===1)I.send(JSON.stringify({type:"ping"}))},X)},I.onmessage=(S)=>{if(T.ws!==I)return;let y=o0(S);if(!y)return;if(y.type==="session")T.sessionId=y.sessionId,T.scenarioId=y.scenarioId??T.scenarioId;if(y.type==="call_control_ack"){let h=g.get(y.requestId);if(h)if(clearTimeout(h.timeout),g.delete(y.requestId),y.ok)h.resolve();else h.reject(Error(y.message??`${y.action} was not applied`))}C.forEach((h)=>h(y))},I.onclose=(S)=>{if(T.ws!==I)return;T.ws=null,T.isConnected=!1,Y(),G("Voice connection interrupted");let y=H&&S.code!==1000&&S.code!==4401&&S.code!==4403&&S.code!==4500&&T.reconnectAttempts<_,h=S.code===4401||S.code===4403,B=S.code===4500;if(h)C.forEach((M)=>M({message:S.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(B)C.forEach((M)=>M({message:"Voice provider initialization failed.",recoverable:!1,type:"error"}));if(y)K();else if(H&&S.code!==1000){if(h)w({reconnect:{attempts:T.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:_,status:"exhausted"},type:"connection"});else if(!B)Z("Voice connection could not be restored.")}},T.ws=I},$=(I)=>{if(L)return;if(T.ws?.readyState===1){T.ws.send(I);return}if(typeof I!=="string")return;if(T.pendingMessages.length>=100)T.pendingMessages.shift();T.pendingMessages.push(I)},J=(I)=>{$(JSON.stringify(I))},b=(I={})=>{if(I.sessionId&&I.sessionId!==T.sessionId)throw Error("Voice session switching requires a new connection instance.");if(I.sessionId)T.sessionId=I.sessionId;if(I.scenarioId)T.scenarioId=I.scenarioId;J({scenarioId:T.scenarioId??void 0,sessionId:T.sessionId,type:"start"})},I0=(I)=>{$(I)},U0=()=>{J({type:"end_turn"})},L0=(I)=>{if(T.ws?.readyState!==1)return Promise.reject(Error(`${I.action} is unavailable while disconnected`));let S=crypto.randomUUID(),{promise:y,reject:h,resolve:B}=Promise.withResolvers(),M=setTimeout(()=>{g.delete(S),h(Error(`${I.action} acknowledgement timed out`))},5000);return g.set(S,{reject:h,resolve:B,timeout:M}),T.ws.send(JSON.stringify({...I,requestId:S,type:"call_control"})),y},W0=(I="client-close")=>{if(L=!0,W?.abort(),W=null,O+=1,Y(),G("Voice connection closed"),T.pendingMessages.length=0,T.ws){let S=T.ws;if(T.ws=null,S.readyState===1)S.send(JSON.stringify({reason:I,type:"close"}));S.close(1000)}T.isConnected=!1,C.clear()},D0=()=>{if(L=!0,W?.abort(),W=null,O+=1,Y(),G("Voice connection disconnected"),T.pendingMessages.length=0,T.ws){let I=T.ws;T.ws=null,I.close(1000)}T.isConnected=!1,C.clear()},X0=()=>{if(T.ws?.readyState===1)T.ws.close(4000,"absolutejs-voice-reconnect-proof")},G0=(I)=>{return C.add(I),()=>{C.delete(I)}};return q(),{callControl:L0,close:W0,disconnect:D0,endTurn:U0,send:J,sendAudio:I0,simulateDisconnect:X0,start:b,subscribe:G0,getReadyState:()=>T.ws?.readyState??3,getScenarioId:()=>T.scenarioId??"",getSessionId:()=>T.sessionId}};var n0=()=>({attempts:0,maxAttempts:0,status:"idle"}),m0=(V,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return V;if(!V)return C;if(V===C||V.endsWith(C))return V;if(C.includes(V))return C;return`${V} ${C}`},u0=(V,A)=>{let C=A.trim().replace(/\s+/g," ");if(!V)return C;if(!C||V.endsWith(C))return V;return`${V} ${C}`},r0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,paused:!1,partial:"",reconnect:n0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),p=()=>{let V=r0(),A="",C=new Set,g=()=>{C.forEach((_)=>_())};return{dispatch:(_)=>{switch(_.type){case"audio":V={...V,assistantAudio:[...V.assistantAudio,{chunk:_.chunk,format:_.format,receivedAt:_.receivedAt,turnId:_.turnId}]};break;case"assistant":V={...V,assistantStreamingText:"",assistantTexts:[...V.assistantTexts,_.text]};break;case"assistant_delta":V={...V,assistantStreamingText:`${V.assistantStreamingText}${_.delta}`};break;case"complete":V={...V,sessionId:_.sessionId,status:"completed"};break;case"call_lifecycle":V={...V,call:{...V.call,disposition:_.event.type==="end"?_.event.disposition:V.call?.disposition,endedAt:_.event.type==="end"?_.event.at:V.call?.endedAt,events:[...V.call?.events??[],_.event],lastEventAt:_.event.at,startedAt:V.call?.startedAt??_.event.at},sessionId:_.sessionId};break;case"connected":V={...V,isConnected:!0,reconnect:V.reconnect.status==="reconnecting"?{...V.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:V.reconnect};break;case"connection":V={...V,reconnect:_.reconnect};break;case"disconnected":V={...V,isConnected:!1};break;case"error":V={...V,error:_.message,..._.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":A=m0(A,_.transcript.text),V={...V,partial:A};break;case"partial":V={...V,partial:u0(A,_.transcript.text)};break;case"replay":A=_.partial,V={...V,assistantStreamingText:"",assistantTexts:[..._.assistantTexts],call:_.call??null,error:null,isConnected:_.status==="active",partial:_.partial,reconnect:V.reconnect.status==="reconnecting"?{...V.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:V.reconnect,scenarioId:_.scenarioId??V.scenarioId,sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??V.sessionMetadata,status:_.status,turns:[..._.turns]};break;case"session":V={...V,error:null,paused:_.paused??!1,pauseExpiresAt:_.pauseExpiresAt,scenarioId:_.scenarioId??V.scenarioId,isConnected:_.status==="active",sessionId:_.sessionId,sessionMetadata:_.sessionMetadata??V.sessionMetadata,status:_.status};break;case"turn":A="",V={...V,partial:"",turns:[...V.turns,_.turn]};break}g()},getServerSnapshot:()=>V,getSnapshot:()=>V,subscribe:(_)=>{return C.add(_),()=>{C.delete(_)}}}};var t=(V,A={})=>{let C=a(V,A),g=p(),H=A.browserMedia&&typeof window<"u"?r({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,_=new Set,D=!1,X=(W)=>Promise.resolve().then(()=>{if(D)return;if(!W?.sessionId&&!W?.scenarioId)return;C.start(W),H?.start()}),R=()=>{_.forEach((W)=>W())},O=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let W=g.getSnapshot(),U=JSON.stringify({at:Date.now(),reconnect:W.reconnect,scenarioId:W.scenarioId,sessionId:C.getSessionId(),turnIds:W.turns.map((T)=>T.id)});fetch(A.reconnectReportPath,{body:U,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=C.subscribe((W)=>{let U=i(W);if(U){if(g.dispatch(U),W.type==="connection")O();R()}});return{start:X,get assistantAudio(){return g.getSnapshot().assistantAudio},get assistantTexts(){return g.getSnapshot().assistantTexts},get assistantStreamingText(){return g.getSnapshot().assistantStreamingText},get call(){return g.getSnapshot().call},callControl(W){return C.callControl(W)},close(W){D=!0,L(),H?.close(),C.close(W),g.dispatch({type:"disconnected"}),R()},disconnect(){D=!0,L(),H?.close(),C.disconnect(),g.dispatch({type:"disconnected"}),R()},endTurn(){C.endTurn()},get error(){return g.getSnapshot().error},getServerSnapshot(){return g.getServerSnapshot()},getSnapshot(){return g.getSnapshot()},get isConnected(){return g.getSnapshot().isConnected},get partial(){return g.getSnapshot().partial},get paused(){return g.getSnapshot().paused},get pauseExpiresAt(){return g.getSnapshot().pauseExpiresAt},get reconnect(){return g.getSnapshot().reconnect},get scenarioId(){return g.getSnapshot().scenarioId},sendAudio(W){C.sendAudio(W)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return g.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return g.getSnapshot().status},subscribe(W){return _.add(W),()=>{_.delete(W)}},get turns(){return g.getSnapshot().turns}}};var e=(V)=>{if(!V||V.enabled===!1)return;return{enabled:!0,maxGain:V.maxGain??3,noiseGateAttenuation:V.noiseGateAttenuation??0.15,noiseGateThreshold:V.noiseGateThreshold??0.006,targetLevel:V.targetLevel??0.08}};var s0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},a0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var V0=(V)=>{let A=V?.profile??"fast",C=V?.qualityProfile??"general",g=s0[A],H=a0[C],_=V?.silenceMs??H.silenceMs??g.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(_,V?.minSilenceMs??H.minSilenceMs??g.minSilenceMs),silenceMs:_,speechThreshold:V?.speechThreshold??H.speechThreshold??g.speechThreshold,transcriptStabilityMs:V?.transcriptStabilityMs??H.transcriptStabilityMs??g.transcriptStabilityMs}};var p0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},A0=(V="default")=>{let A=p0[V];return{audioConditioning:e(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:V,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:V0(A.turnDetection)}};var t0=(V)=>({assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,isRecording:!1,paused:V.paused,pauseExpiresAt:V.pauseExpiresAt,partial:V.partial,reconnect:V.reconnect,recordingError:null,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]}),g0=(V,A={})=>{let C=A0(A.preset),g=t(V,{...C.connection,...A.connection}),H=null,_=0,D=!1,X=null,R=t0(g),O=new Set,L=()=>{for(let G of O)G()},W=()=>{if(R={...R,assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,paused:g.paused,pauseExpiresAt:g.pauseExpiresAt,partial:g.partial,reconnect:g.reconnect,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]},A.autoStopOnComplete!==!1&&R.status==="completed"&&R.isRecording)H?.stop(),H=null,R={...R,isRecording:!1};L()},U=g.subscribe(W);W();let T=()=>{if(H)return H;return H=v({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(G)=>{if(A.capture?.onAudio){A.capture.onAudio(G,g.sendAudio);return}g.sendAudio(G)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),H},w=()=>{_+=1,H?.stop(),H=null,R={...R,isRecording:!1},L()},Z=async()=>{if(D)throw Error("Voice controller is closed.");if(R.isRecording)return;if(X)return X;let G=++_,K=T(),$=(async()=>{try{if(R={...R,recordingError:null},L(),await K.start(),D||G!==_||H!==K){K.stop();return}R={...R,isRecording:!0},L()}catch(J){if(K.stop(),G!==_||H!==K)throw J;throw H=null,R={...R,isRecording:!1,recordingError:J instanceof Error?J.message:String(J)},L(),J}})().finally(()=>{if(X===$)X=null});return X=$,X};return{close:(G)=>{D=!0,U(),w(),g.close(G)},disconnect:()=>{D=!0,U(),w(),g.disconnect()},startRecording:Z,stopRecording:w,get assistantAudio(){return R.assistantAudio},get assistantTexts(){return R.assistantTexts},get assistantStreamingText(){return R.assistantStreamingText},bindHTMX(G){return d(g,G)},get call(){return R.call},callControl:(G)=>g.callControl(G),endTurn:()=>g.endTurn(),get error(){return R.error},getServerSnapshot:()=>R,getSnapshot:()=>R,get isConnected(){return R.isConnected},get isRecording(){return R.isRecording},get partial(){return R.partial},get paused(){return R.paused},get pauseExpiresAt(){return R.pauseExpiresAt},get reconnect(){return R.reconnect},get recordingError(){return R.recordingError},get scenarioId(){return R.scenarioId},sendAudio:(G)=>g.sendAudio(G),get sessionId(){return R.sessionId},get sessionMetadata(){return R.sessionMetadata},simulateDisconnect:()=>g.simulateDisconnect(),get status(){return R.status},subscribe:(G)=>{return O.add(G),()=>{O.delete(G)}},toggleRecording:async()=>{if(R.isRecording){w();return}await Z()},get turns(){return R.turns}}};var z=(V)=>String(V).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var C0=(V)=>{if(!V.isConnected)return"idle";if(V.isPlaying)return"speaking";if(V.isRecording&&V.hasActivePartial)return"listening";if(V.isRecording)return"listening";if(V.lastTranscriptAt&&!V.lastAssistantAt)return"thinking";if(V.lastTranscriptAt&&V.lastAssistantAt&&V.lastTranscriptAt>V.lastAssistantAt)return"thinking";return"idle"};var e0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},VV={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},AV=(V,A)=>{switch(V){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},_0=(V)=>{let A={...e0,...V.theme},C={...VV,...V.labels},g=V.state.assistantAudio.at(-1)?.receivedAt,H=V.state.turns.at(-1)?.committedAt,_=C0({hasActivePartial:V.state.partial.length>0,isConnected:V.state.isConnected,isPlaying:!1,isRecording:V.state.isRecording,lastAssistantAt:g,lastTranscriptAt:H}),D=!V.state.isConnected&&V.state.status!=="idle"&&!V.state.error,X=V.state.error?"Error":D?C.connecting:V.state.status==="completed"?C.callEnded:AV(_,C);return{agentState:_,classes:{container:`absolute-voice-widget absolute-voice-widget--${_}`,dot:`absolute-voice-widget__dot${V.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:V.state.isConnected,canMute:V.state.isRecording,canStart:!V.state.isRecording&&V.state.status!=="completed"},errorMessage:V.state.error??void 0,labels:C,partial:V.state.partial||void 0,statusLabel:X,theme:A,title:V.title??"Voice"}},gV=(V)=>typeof V==="number"?`${V}px`:V,T0=(V)=>{let A=V.theme,C=`background:${A.background};border-radius:${gV(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,g=`background:${V.errorMessage?A.errorAccent:V.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,H=[];if(V.controls.canStart)H.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${z(V.labels.startCall)}</button>`);if(V.controls.canMute)H.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${z(V.labels.mute)}</button>`);if(V.controls.canEnd)H.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${z(V.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${V.agentState}" class="${z(V.classes.container)}" style="${C}">
|
|
2
2
|
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
3
|
-
<span aria-hidden="true" class="${z(V.classes.dot)}" style="${
|
|
3
|
+
<span aria-hidden="true" class="${z(V.classes.dot)}" style="${g}"></span>
|
|
4
4
|
<strong style="font-size:15px;">${z(V.title)}</strong>
|
|
5
5
|
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${z(V.statusLabel)}</span>
|
|
6
6
|
</div>
|
|
7
7
|
${V.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${z(V.partial)}”</p>`:""}
|
|
8
|
-
<div style="display:flex;gap:10px;">${
|
|
9
|
-
${V.errorMessage?`<p style="color:${
|
|
10
|
-
</div>`};var CV=(V)=>{if(typeof V!=="string")return V;let
|
|
8
|
+
<div style="display:flex;gap:10px;">${H.join("")}</div>
|
|
9
|
+
${V.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${z(V.errorMessage)}</p>`:""}
|
|
10
|
+
</div>`};var CV=(V)=>{if(typeof V!=="string")return V;let A=document.querySelector(V);if(!A)throw Error(`AbsoluteVoice.mount: no element matches "${V}"`);return A},$0=(V,A={})=>{let C=CV(V),g=g0(A.path??"/voice",A.controllerOptions),H=null,_=null,D=()=>{let R=_0({...A.labels!==void 0?{labels:A.labels}:{},state:{assistantAudio:g.assistantAudio,error:g.error,isConnected:g.isConnected,isRecording:g.isRecording,partial:g.partial,status:g.status,turns:g.turns},...A.theme!==void 0?{theme:A.theme}:{},...A.title!==void 0?{title:A.title}:{}});C.innerHTML=T0(R);for(let O of C.querySelectorAll("button[data-action]")){let{action:L}=O.dataset;O.addEventListener("click",()=>{if(L==="start")g.startRecording();else if(L==="mute")g.stopRecording();else if(L==="end")g.close()})}if(g.error&&g.error!==H)H=g.error,A.onError?.(g.error);if(g.status!==_)_=g.status,A.onStatusChange?.(g.status)},X=g.subscribe(D);if(D(),A.autoStart)g.startRecording();return{controller:g,async end(){await g.close()},mute(){g.stopRecording()},async start(){await g.startRecording()},unmount(){X(),g.close(),C.innerHTML=""}}},R0="0.0.22-beta.516",H0={mount:$0,version:R0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=H0;var TV=H0;})();
|
package/dist/index.js
CHANGED
|
@@ -6880,6 +6880,8 @@ var createVoiceSession = (options) => {
|
|
|
6880
6880
|
if (session.status === "completed" || session.status === "failed") {
|
|
6881
6881
|
await options.store.set(options.id, session);
|
|
6882
6882
|
await send({
|
|
6883
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
6884
|
+
paused: Boolean(session.pause),
|
|
6883
6885
|
sessionId: options.id,
|
|
6884
6886
|
status: session.status,
|
|
6885
6887
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
|
@@ -6915,6 +6917,8 @@ var createVoiceSession = (options) => {
|
|
|
6915
6917
|
await sendCallLifecycle(session);
|
|
6916
6918
|
}
|
|
6917
6919
|
await send({
|
|
6920
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
6921
|
+
paused: callerPaused,
|
|
6918
6922
|
sessionId: options.id,
|
|
6919
6923
|
status: session.status,
|
|
6920
6924
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
|
@@ -40429,8 +40433,15 @@ var voice = (config) => {
|
|
|
40429
40433
|
};
|
|
40430
40434
|
const createAndConnectSession = async (ws, sessionId, scenarioId) => {
|
|
40431
40435
|
const identity = socketIdentity(ws);
|
|
40432
|
-
|
|
40433
|
-
|
|
40436
|
+
let session;
|
|
40437
|
+
try {
|
|
40438
|
+
session = await createManagedSession(ws, sessionId, scenarioId);
|
|
40439
|
+
} catch (error) {
|
|
40440
|
+
runtime.logger.warn?.(`[voice] session initialization failed for "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
40441
|
+
closedSockets.add(identity);
|
|
40442
|
+
ws.close(4500, "voice session initialization failed");
|
|
40443
|
+
throw error;
|
|
40444
|
+
}
|
|
40434
40445
|
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40435
40446
|
ws.close(1000, "superseded");
|
|
40436
40447
|
throw new Error("Voice socket was superseded during session creation");
|
|
@@ -40446,6 +40457,7 @@ var voice = (config) => {
|
|
|
40446
40457
|
ws.close(4500, "voice session initialization failed");
|
|
40447
40458
|
throw error;
|
|
40448
40459
|
}
|
|
40460
|
+
const typedSession = session;
|
|
40449
40461
|
if (closedSockets.has(identity) || !socketIsOpen(ws) || runtime.activeSockets.get(sessionId) !== identity) {
|
|
40450
40462
|
await session.disconnect({
|
|
40451
40463
|
code: 1000,
|
package/dist/react/index.js
CHANGED
|
@@ -11338,6 +11338,8 @@ var serverMessageToAction = (message) => {
|
|
|
11338
11338
|
};
|
|
11339
11339
|
case "session":
|
|
11340
11340
|
return {
|
|
11341
|
+
paused: message.paused,
|
|
11342
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
11341
11343
|
sessionId: message.sessionId,
|
|
11342
11344
|
sessionMetadata: message.sessionMetadata,
|
|
11343
11345
|
scenarioId: message.scenarioId,
|
|
@@ -11698,12 +11700,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
11698
11700
|
state.reconnectResetTimeout = null;
|
|
11699
11701
|
}, reconnectResetAfterMs);
|
|
11700
11702
|
}
|
|
11701
|
-
listeners.forEach((listener) => listener({
|
|
11702
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
11703
|
-
sessionId: state.sessionId,
|
|
11704
|
-
status: "active",
|
|
11705
|
-
type: "session"
|
|
11706
|
-
}));
|
|
11707
11703
|
state.pingInterval = setInterval(() => {
|
|
11708
11704
|
if (ws.readyState === WS_OPEN) {
|
|
11709
11705
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -11934,6 +11930,7 @@ var createInitialState = () => ({
|
|
|
11934
11930
|
call: null,
|
|
11935
11931
|
error: null,
|
|
11936
11932
|
isConnected: false,
|
|
11933
|
+
paused: false,
|
|
11937
11934
|
partial: "",
|
|
11938
11935
|
reconnect: createInitialReconnectState(),
|
|
11939
11936
|
scenarioId: null,
|
|
@@ -12070,6 +12067,8 @@ var createVoiceStreamStore = () => {
|
|
|
12070
12067
|
state = {
|
|
12071
12068
|
...state,
|
|
12072
12069
|
error: null,
|
|
12070
|
+
paused: action.paused ?? false,
|
|
12071
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
12073
12072
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
12074
12073
|
isConnected: action.status === "active",
|
|
12075
12074
|
sessionId: action.sessionId,
|
|
@@ -12206,6 +12205,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
12206
12205
|
get partial() {
|
|
12207
12206
|
return store.getSnapshot().partial;
|
|
12208
12207
|
},
|
|
12208
|
+
get paused() {
|
|
12209
|
+
return store.getSnapshot().paused;
|
|
12210
|
+
},
|
|
12211
|
+
get pauseExpiresAt() {
|
|
12212
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
12213
|
+
},
|
|
12209
12214
|
get reconnect() {
|
|
12210
12215
|
return store.getSnapshot().reconnect;
|
|
12211
12216
|
},
|
|
@@ -12801,6 +12806,8 @@ var createInitialState2 = (stream) => ({
|
|
|
12801
12806
|
error: stream.error,
|
|
12802
12807
|
isConnected: stream.isConnected,
|
|
12803
12808
|
isRecording: false,
|
|
12809
|
+
paused: stream.paused,
|
|
12810
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
12804
12811
|
partial: stream.partial,
|
|
12805
12812
|
reconnect: stream.reconnect,
|
|
12806
12813
|
recordingError: null,
|
|
@@ -12836,6 +12843,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12836
12843
|
call: stream.call,
|
|
12837
12844
|
error: stream.error,
|
|
12838
12845
|
isConnected: stream.isConnected,
|
|
12846
|
+
paused: stream.paused,
|
|
12847
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
12839
12848
|
partial: stream.partial,
|
|
12840
12849
|
reconnect: stream.reconnect,
|
|
12841
12850
|
sessionId: stream.sessionId,
|
|
@@ -12983,6 +12992,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12983
12992
|
get partial() {
|
|
12984
12993
|
return state.partial;
|
|
12985
12994
|
},
|
|
12995
|
+
get paused() {
|
|
12996
|
+
return state.paused;
|
|
12997
|
+
},
|
|
12998
|
+
get pauseExpiresAt() {
|
|
12999
|
+
return state.pauseExpiresAt;
|
|
13000
|
+
},
|
|
12986
13001
|
get reconnect() {
|
|
12987
13002
|
return state.reconnect;
|
|
12988
13003
|
},
|
|
@@ -10,6 +10,8 @@ export declare const useVoiceController: <TResult = unknown>(path: string, optio
|
|
|
10
10
|
stopRecording: () => void;
|
|
11
11
|
toggleRecording: () => Promise<void>;
|
|
12
12
|
call: import("..").VoiceCallLifecycleState | null;
|
|
13
|
+
paused: boolean;
|
|
14
|
+
pauseExpiresAt?: number;
|
|
13
15
|
sessionMetadata: Record<string, unknown> | null;
|
|
14
16
|
sessionId: string | null;
|
|
15
17
|
scenarioId: string | null;
|
|
@@ -6,6 +6,8 @@ export declare const useVoiceStream: <TResult = unknown>(path: string, options?:
|
|
|
6
6
|
sendAudio: (audio: Uint8Array | ArrayBuffer) => void;
|
|
7
7
|
simulateDisconnect: () => void;
|
|
8
8
|
call: import("..").VoiceCallLifecycleState | null;
|
|
9
|
+
paused: boolean;
|
|
10
|
+
pauseExpiresAt?: number;
|
|
9
11
|
sessionMetadata: Record<string, unknown> | null;
|
|
10
12
|
sessionId: string | null;
|
|
11
13
|
scenarioId: string | null;
|
package/dist/svelte/index.js
CHANGED
|
@@ -707,6 +707,8 @@ var serverMessageToAction = (message) => {
|
|
|
707
707
|
};
|
|
708
708
|
case "session":
|
|
709
709
|
return {
|
|
710
|
+
paused: message.paused,
|
|
711
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
710
712
|
sessionId: message.sessionId,
|
|
711
713
|
sessionMetadata: message.sessionMetadata,
|
|
712
714
|
scenarioId: message.scenarioId,
|
|
@@ -1067,12 +1069,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
1067
1069
|
state.reconnectResetTimeout = null;
|
|
1068
1070
|
}, reconnectResetAfterMs);
|
|
1069
1071
|
}
|
|
1070
|
-
listeners.forEach((listener) => listener({
|
|
1071
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
1072
|
-
sessionId: state.sessionId,
|
|
1073
|
-
status: "active",
|
|
1074
|
-
type: "session"
|
|
1075
|
-
}));
|
|
1076
1072
|
state.pingInterval = setInterval(() => {
|
|
1077
1073
|
if (ws.readyState === WS_OPEN) {
|
|
1078
1074
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -1303,6 +1299,7 @@ var createInitialState = () => ({
|
|
|
1303
1299
|
call: null,
|
|
1304
1300
|
error: null,
|
|
1305
1301
|
isConnected: false,
|
|
1302
|
+
paused: false,
|
|
1306
1303
|
partial: "",
|
|
1307
1304
|
reconnect: createInitialReconnectState(),
|
|
1308
1305
|
scenarioId: null,
|
|
@@ -1439,6 +1436,8 @@ var createVoiceStreamStore = () => {
|
|
|
1439
1436
|
state = {
|
|
1440
1437
|
...state,
|
|
1441
1438
|
error: null,
|
|
1439
|
+
paused: action.paused ?? false,
|
|
1440
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
1442
1441
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1443
1442
|
isConnected: action.status === "active",
|
|
1444
1443
|
sessionId: action.sessionId,
|
|
@@ -1575,6 +1574,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1575
1574
|
get partial() {
|
|
1576
1575
|
return store.getSnapshot().partial;
|
|
1577
1576
|
},
|
|
1577
|
+
get paused() {
|
|
1578
|
+
return store.getSnapshot().paused;
|
|
1579
|
+
},
|
|
1580
|
+
get pauseExpiresAt() {
|
|
1581
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
1582
|
+
},
|
|
1578
1583
|
get reconnect() {
|
|
1579
1584
|
return store.getSnapshot().reconnect;
|
|
1580
1585
|
},
|
|
@@ -1938,6 +1943,8 @@ var createInitialState2 = (stream) => ({
|
|
|
1938
1943
|
error: stream.error,
|
|
1939
1944
|
isConnected: stream.isConnected,
|
|
1940
1945
|
isRecording: false,
|
|
1946
|
+
paused: stream.paused,
|
|
1947
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1941
1948
|
partial: stream.partial,
|
|
1942
1949
|
reconnect: stream.reconnect,
|
|
1943
1950
|
recordingError: null,
|
|
@@ -1973,6 +1980,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1973
1980
|
call: stream.call,
|
|
1974
1981
|
error: stream.error,
|
|
1975
1982
|
isConnected: stream.isConnected,
|
|
1983
|
+
paused: stream.paused,
|
|
1984
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
1976
1985
|
partial: stream.partial,
|
|
1977
1986
|
reconnect: stream.reconnect,
|
|
1978
1987
|
sessionId: stream.sessionId,
|
|
@@ -2120,6 +2129,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
2120
2129
|
get partial() {
|
|
2121
2130
|
return state.partial;
|
|
2122
2131
|
},
|
|
2132
|
+
get paused() {
|
|
2133
|
+
return state.paused;
|
|
2134
|
+
},
|
|
2135
|
+
get pauseExpiresAt() {
|
|
2136
|
+
return state.pauseExpiresAt;
|
|
2137
|
+
},
|
|
2123
2138
|
get reconnect() {
|
|
2124
2139
|
return state.reconnect;
|
|
2125
2140
|
},
|
package/dist/testing/index.js
CHANGED
|
@@ -2928,6 +2928,8 @@ var serverMessageToAction = (message) => {
|
|
|
2928
2928
|
};
|
|
2929
2929
|
case "session":
|
|
2930
2930
|
return {
|
|
2931
|
+
paused: message.paused,
|
|
2932
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
2931
2933
|
sessionId: message.sessionId,
|
|
2932
2934
|
sessionMetadata: message.sessionMetadata,
|
|
2933
2935
|
scenarioId: message.scenarioId,
|
|
@@ -3288,12 +3290,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
3288
3290
|
state.reconnectResetTimeout = null;
|
|
3289
3291
|
}, reconnectResetAfterMs);
|
|
3290
3292
|
}
|
|
3291
|
-
listeners.forEach((listener) => listener({
|
|
3292
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
3293
|
-
sessionId: state.sessionId,
|
|
3294
|
-
status: "active",
|
|
3295
|
-
type: "session"
|
|
3296
|
-
}));
|
|
3297
3293
|
state.pingInterval = setInterval(() => {
|
|
3298
3294
|
if (ws.readyState === WS_OPEN) {
|
|
3299
3295
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -3524,6 +3520,7 @@ var createInitialState2 = () => ({
|
|
|
3524
3520
|
call: null,
|
|
3525
3521
|
error: null,
|
|
3526
3522
|
isConnected: false,
|
|
3523
|
+
paused: false,
|
|
3527
3524
|
partial: "",
|
|
3528
3525
|
reconnect: createInitialReconnectState(),
|
|
3529
3526
|
scenarioId: null,
|
|
@@ -3660,6 +3657,8 @@ var createVoiceStreamStore = () => {
|
|
|
3660
3657
|
state = {
|
|
3661
3658
|
...state,
|
|
3662
3659
|
error: null,
|
|
3660
|
+
paused: action.paused ?? false,
|
|
3661
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
3663
3662
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
3664
3663
|
isConnected: action.status === "active",
|
|
3665
3664
|
sessionId: action.sessionId,
|
|
@@ -3796,6 +3795,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
3796
3795
|
get partial() {
|
|
3797
3796
|
return store.getSnapshot().partial;
|
|
3798
3797
|
},
|
|
3798
|
+
get paused() {
|
|
3799
|
+
return store.getSnapshot().paused;
|
|
3800
|
+
},
|
|
3801
|
+
get pauseExpiresAt() {
|
|
3802
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
3803
|
+
},
|
|
3799
3804
|
get reconnect() {
|
|
3800
3805
|
return store.getSnapshot().reconnect;
|
|
3801
3806
|
},
|
|
@@ -4159,6 +4164,8 @@ var createInitialState3 = (stream) => ({
|
|
|
4159
4164
|
error: stream.error,
|
|
4160
4165
|
isConnected: stream.isConnected,
|
|
4161
4166
|
isRecording: false,
|
|
4167
|
+
paused: stream.paused,
|
|
4168
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
4162
4169
|
partial: stream.partial,
|
|
4163
4170
|
reconnect: stream.reconnect,
|
|
4164
4171
|
recordingError: null,
|
|
@@ -4194,6 +4201,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
4194
4201
|
call: stream.call,
|
|
4195
4202
|
error: stream.error,
|
|
4196
4203
|
isConnected: stream.isConnected,
|
|
4204
|
+
paused: stream.paused,
|
|
4205
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
4197
4206
|
partial: stream.partial,
|
|
4198
4207
|
reconnect: stream.reconnect,
|
|
4199
4208
|
sessionId: stream.sessionId,
|
|
@@ -4341,6 +4350,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
4341
4350
|
get partial() {
|
|
4342
4351
|
return state.partial;
|
|
4343
4352
|
},
|
|
4353
|
+
get paused() {
|
|
4354
|
+
return state.paused;
|
|
4355
|
+
},
|
|
4356
|
+
get pauseExpiresAt() {
|
|
4357
|
+
return state.pauseExpiresAt;
|
|
4358
|
+
},
|
|
4344
4359
|
get reconnect() {
|
|
4345
4360
|
return state.reconnect;
|
|
4346
4361
|
},
|
|
@@ -9817,6 +9832,8 @@ var createVoiceSession = (options) => {
|
|
|
9817
9832
|
if (session.status === "completed" || session.status === "failed") {
|
|
9818
9833
|
await options.store.set(options.id, session);
|
|
9819
9834
|
await send({
|
|
9835
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
9836
|
+
paused: Boolean(session.pause),
|
|
9820
9837
|
sessionId: options.id,
|
|
9821
9838
|
status: session.status,
|
|
9822
9839
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
|
@@ -9852,6 +9869,8 @@ var createVoiceSession = (options) => {
|
|
|
9852
9869
|
await sendCallLifecycle(session);
|
|
9853
9870
|
}
|
|
9854
9871
|
await send({
|
|
9872
|
+
pauseExpiresAt: session.pause?.expiresAt,
|
|
9873
|
+
paused: callerPaused,
|
|
9855
9874
|
sessionId: options.id,
|
|
9856
9875
|
status: session.status,
|
|
9857
9876
|
sessionMetadata: session.metadata && typeof session.metadata === "object" ? session.metadata : undefined,
|
package/dist/vue/index.js
CHANGED
|
@@ -10734,6 +10734,8 @@ var serverMessageToAction = (message) => {
|
|
|
10734
10734
|
};
|
|
10735
10735
|
case "session":
|
|
10736
10736
|
return {
|
|
10737
|
+
paused: message.paused,
|
|
10738
|
+
pauseExpiresAt: message.pauseExpiresAt,
|
|
10737
10739
|
sessionId: message.sessionId,
|
|
10738
10740
|
sessionMetadata: message.sessionMetadata,
|
|
10739
10741
|
scenarioId: message.scenarioId,
|
|
@@ -11094,12 +11096,6 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
11094
11096
|
state.reconnectResetTimeout = null;
|
|
11095
11097
|
}, reconnectResetAfterMs);
|
|
11096
11098
|
}
|
|
11097
|
-
listeners.forEach((listener) => listener({
|
|
11098
|
-
scenarioId: state.scenarioId ?? undefined,
|
|
11099
|
-
sessionId: state.sessionId,
|
|
11100
|
-
status: "active",
|
|
11101
|
-
type: "session"
|
|
11102
|
-
}));
|
|
11103
11099
|
state.pingInterval = setInterval(() => {
|
|
11104
11100
|
if (ws.readyState === WS_OPEN) {
|
|
11105
11101
|
ws.send(JSON.stringify({ type: "ping" }));
|
|
@@ -11330,6 +11326,7 @@ var createInitialState = () => ({
|
|
|
11330
11326
|
call: null,
|
|
11331
11327
|
error: null,
|
|
11332
11328
|
isConnected: false,
|
|
11329
|
+
paused: false,
|
|
11333
11330
|
partial: "",
|
|
11334
11331
|
reconnect: createInitialReconnectState(),
|
|
11335
11332
|
scenarioId: null,
|
|
@@ -11466,6 +11463,8 @@ var createVoiceStreamStore = () => {
|
|
|
11466
11463
|
state = {
|
|
11467
11464
|
...state,
|
|
11468
11465
|
error: null,
|
|
11466
|
+
paused: action.paused ?? false,
|
|
11467
|
+
pauseExpiresAt: action.pauseExpiresAt,
|
|
11469
11468
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
11470
11469
|
isConnected: action.status === "active",
|
|
11471
11470
|
sessionId: action.sessionId,
|
|
@@ -11602,6 +11601,12 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
11602
11601
|
get partial() {
|
|
11603
11602
|
return store.getSnapshot().partial;
|
|
11604
11603
|
},
|
|
11604
|
+
get paused() {
|
|
11605
|
+
return store.getSnapshot().paused;
|
|
11606
|
+
},
|
|
11607
|
+
get pauseExpiresAt() {
|
|
11608
|
+
return store.getSnapshot().pauseExpiresAt;
|
|
11609
|
+
},
|
|
11605
11610
|
get reconnect() {
|
|
11606
11611
|
return store.getSnapshot().reconnect;
|
|
11607
11612
|
},
|
|
@@ -12218,6 +12223,8 @@ var createInitialState2 = (stream) => ({
|
|
|
12218
12223
|
error: stream.error,
|
|
12219
12224
|
isConnected: stream.isConnected,
|
|
12220
12225
|
isRecording: false,
|
|
12226
|
+
paused: stream.paused,
|
|
12227
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
12221
12228
|
partial: stream.partial,
|
|
12222
12229
|
reconnect: stream.reconnect,
|
|
12223
12230
|
recordingError: null,
|
|
@@ -12253,6 +12260,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12253
12260
|
call: stream.call,
|
|
12254
12261
|
error: stream.error,
|
|
12255
12262
|
isConnected: stream.isConnected,
|
|
12263
|
+
paused: stream.paused,
|
|
12264
|
+
pauseExpiresAt: stream.pauseExpiresAt,
|
|
12256
12265
|
partial: stream.partial,
|
|
12257
12266
|
reconnect: stream.reconnect,
|
|
12258
12267
|
sessionId: stream.sessionId,
|
|
@@ -12400,6 +12409,12 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12400
12409
|
get partial() {
|
|
12401
12410
|
return state.partial;
|
|
12402
12411
|
},
|
|
12412
|
+
get paused() {
|
|
12413
|
+
return state.paused;
|
|
12414
|
+
},
|
|
12415
|
+
get pauseExpiresAt() {
|
|
12416
|
+
return state.pauseExpiresAt;
|
|
12417
|
+
},
|
|
12403
12418
|
get reconnect() {
|
|
12404
12419
|
return state.reconnect;
|
|
12405
12420
|
},
|