@absolutejs/voice 0.0.22-beta.129 → 0.0.22-beta.130
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 +90 -2
- package/dist/angular/voice-controller.service.d.ts +1 -0
- package/dist/angular/voice-stream.service.d.ts +1 -0
- package/dist/client/actions.d.ts +29 -0
- package/dist/client/htmxBootstrap.js +84 -2
- package/dist/client/index.js +84 -2
- package/dist/react/index.js +94 -2
- package/dist/react/useVoiceController.d.ts +1 -0
- package/dist/react/useVoiceStream.d.ts +1 -0
- package/dist/svelte/index.js +84 -2
- package/dist/testing/index.js +84 -2
- package/dist/types.d.ts +20 -1
- package/dist/vue/index.js +90 -2
- package/dist/vue/useVoiceController.d.ts +1 -0
- package/dist/vue/useVoiceStream.d.ts +1 -0
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -409,6 +409,11 @@ var serverMessageToAction = (message) => {
|
|
|
409
409
|
sessionId: message.sessionId,
|
|
410
410
|
type: "complete"
|
|
411
411
|
};
|
|
412
|
+
case "connection":
|
|
413
|
+
return {
|
|
414
|
+
reconnect: message.reconnect,
|
|
415
|
+
type: "connection"
|
|
416
|
+
};
|
|
412
417
|
case "call_lifecycle":
|
|
413
418
|
return {
|
|
414
419
|
event: message.event,
|
|
@@ -501,6 +506,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
501
506
|
case "assistant":
|
|
502
507
|
case "call_lifecycle":
|
|
503
508
|
case "complete":
|
|
509
|
+
case "connection":
|
|
504
510
|
case "error":
|
|
505
511
|
case "final":
|
|
506
512
|
case "partial":
|
|
@@ -542,6 +548,9 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
542
548
|
sessionId: options.sessionId ?? createSessionId(),
|
|
543
549
|
ws: null
|
|
544
550
|
};
|
|
551
|
+
const emitConnection = (reconnect) => {
|
|
552
|
+
listeners.forEach((listener) => listener(reconnect));
|
|
553
|
+
};
|
|
545
554
|
const clearTimers = () => {
|
|
546
555
|
if (state.pingInterval) {
|
|
547
556
|
clearInterval(state.pingInterval);
|
|
@@ -564,9 +573,28 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
564
573
|
}
|
|
565
574
|
};
|
|
566
575
|
const scheduleReconnect = () => {
|
|
576
|
+
const nextAttemptAt = Date.now() + RECONNECT_DELAY_MS;
|
|
567
577
|
state.reconnectAttempts += 1;
|
|
578
|
+
emitConnection({
|
|
579
|
+
reconnect: {
|
|
580
|
+
attempts: state.reconnectAttempts,
|
|
581
|
+
lastDisconnectAt: Date.now(),
|
|
582
|
+
maxAttempts: maxReconnectAttempts,
|
|
583
|
+
nextAttemptAt,
|
|
584
|
+
status: "reconnecting"
|
|
585
|
+
},
|
|
586
|
+
type: "connection"
|
|
587
|
+
});
|
|
568
588
|
state.reconnectTimeout = setTimeout(() => {
|
|
569
589
|
if (state.reconnectAttempts > maxReconnectAttempts) {
|
|
590
|
+
emitConnection({
|
|
591
|
+
reconnect: {
|
|
592
|
+
attempts: state.reconnectAttempts,
|
|
593
|
+
maxAttempts: maxReconnectAttempts,
|
|
594
|
+
status: "exhausted"
|
|
595
|
+
},
|
|
596
|
+
type: "connection"
|
|
597
|
+
});
|
|
570
598
|
return;
|
|
571
599
|
}
|
|
572
600
|
connect();
|
|
@@ -576,9 +604,21 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
576
604
|
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
577
605
|
ws.binaryType = "arraybuffer";
|
|
578
606
|
ws.onopen = () => {
|
|
607
|
+
const wasReconnecting = state.reconnectAttempts > 0;
|
|
579
608
|
state.isConnected = true;
|
|
580
|
-
state.reconnectAttempts = 0;
|
|
581
609
|
flushPendingMessages();
|
|
610
|
+
if (wasReconnecting) {
|
|
611
|
+
emitConnection({
|
|
612
|
+
reconnect: {
|
|
613
|
+
attempts: state.reconnectAttempts,
|
|
614
|
+
lastResumedAt: Date.now(),
|
|
615
|
+
maxAttempts: maxReconnectAttempts,
|
|
616
|
+
status: "resumed"
|
|
617
|
+
},
|
|
618
|
+
type: "connection"
|
|
619
|
+
});
|
|
620
|
+
state.reconnectAttempts = 0;
|
|
621
|
+
}
|
|
582
622
|
listeners.forEach((listener) => listener({
|
|
583
623
|
scenarioId: state.scenarioId ?? undefined,
|
|
584
624
|
sessionId: state.sessionId,
|
|
@@ -608,6 +648,16 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
608
648
|
const reconnectable = shouldReconnect && event.code !== WS_NORMAL_CLOSURE && state.reconnectAttempts < maxReconnectAttempts;
|
|
609
649
|
if (reconnectable) {
|
|
610
650
|
scheduleReconnect();
|
|
651
|
+
} else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
|
|
652
|
+
emitConnection({
|
|
653
|
+
reconnect: {
|
|
654
|
+
attempts: state.reconnectAttempts,
|
|
655
|
+
lastDisconnectAt: Date.now(),
|
|
656
|
+
maxAttempts: maxReconnectAttempts,
|
|
657
|
+
status: "exhausted"
|
|
658
|
+
},
|
|
659
|
+
type: "connection"
|
|
660
|
+
});
|
|
611
661
|
}
|
|
612
662
|
};
|
|
613
663
|
state.ws = ws;
|
|
@@ -678,6 +728,11 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
678
728
|
};
|
|
679
729
|
|
|
680
730
|
// src/client/store.ts
|
|
731
|
+
var createInitialReconnectState = () => ({
|
|
732
|
+
attempts: 0,
|
|
733
|
+
maxAttempts: 0,
|
|
734
|
+
status: "idle"
|
|
735
|
+
});
|
|
681
736
|
var createInitialState = () => ({
|
|
682
737
|
assistantAudio: [],
|
|
683
738
|
assistantTexts: [],
|
|
@@ -686,6 +741,7 @@ var createInitialState = () => ({
|
|
|
686
741
|
isConnected: false,
|
|
687
742
|
scenarioId: null,
|
|
688
743
|
partial: "",
|
|
744
|
+
reconnect: createInitialReconnectState(),
|
|
689
745
|
sessionId: null,
|
|
690
746
|
status: "idle",
|
|
691
747
|
turns: []
|
|
@@ -742,7 +798,19 @@ var createVoiceStreamStore = () => {
|
|
|
742
798
|
case "connected":
|
|
743
799
|
state = {
|
|
744
800
|
...state,
|
|
745
|
-
isConnected: true
|
|
801
|
+
isConnected: true,
|
|
802
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
803
|
+
...state.reconnect,
|
|
804
|
+
lastResumedAt: Date.now(),
|
|
805
|
+
nextAttemptAt: undefined,
|
|
806
|
+
status: "resumed"
|
|
807
|
+
} : state.reconnect
|
|
808
|
+
};
|
|
809
|
+
break;
|
|
810
|
+
case "connection":
|
|
811
|
+
state = {
|
|
812
|
+
...state,
|
|
813
|
+
reconnect: action.reconnect
|
|
746
814
|
};
|
|
747
815
|
break;
|
|
748
816
|
case "disconnected":
|
|
@@ -778,6 +846,12 @@ var createVoiceStreamStore = () => {
|
|
|
778
846
|
error: null,
|
|
779
847
|
isConnected: action.status === "active",
|
|
780
848
|
partial: action.partial,
|
|
849
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
850
|
+
...state.reconnect,
|
|
851
|
+
lastResumedAt: Date.now(),
|
|
852
|
+
nextAttemptAt: undefined,
|
|
853
|
+
status: "resumed"
|
|
854
|
+
} : state.reconnect,
|
|
781
855
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
782
856
|
sessionId: action.sessionId,
|
|
783
857
|
status: action.status,
|
|
@@ -870,6 +944,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
870
944
|
get partial() {
|
|
871
945
|
return store.getSnapshot().partial;
|
|
872
946
|
},
|
|
947
|
+
get reconnect() {
|
|
948
|
+
return store.getSnapshot().reconnect;
|
|
949
|
+
},
|
|
873
950
|
get sessionId() {
|
|
874
951
|
return connection.getSessionId();
|
|
875
952
|
},
|
|
@@ -915,6 +992,7 @@ class VoiceStreamService {
|
|
|
915
992
|
const errorSignal = signal3(null);
|
|
916
993
|
const isConnectedSignal = signal3(false);
|
|
917
994
|
const partialSignal = signal3("");
|
|
995
|
+
const reconnectSignal = signal3(stream.reconnect);
|
|
918
996
|
const sessionIdSignal = signal3(stream.sessionId);
|
|
919
997
|
const statusSignal = signal3(stream.status);
|
|
920
998
|
const turnsSignal = signal3([]);
|
|
@@ -925,6 +1003,7 @@ class VoiceStreamService {
|
|
|
925
1003
|
errorSignal.set(stream.error);
|
|
926
1004
|
isConnectedSignal.set(stream.isConnected);
|
|
927
1005
|
partialSignal.set(stream.partial);
|
|
1006
|
+
reconnectSignal.set(stream.reconnect);
|
|
928
1007
|
sessionIdSignal.set(stream.sessionId);
|
|
929
1008
|
statusSignal.set(stream.status);
|
|
930
1009
|
turnsSignal.set([...stream.turns]);
|
|
@@ -944,6 +1023,7 @@ class VoiceStreamService {
|
|
|
944
1023
|
error: computed3(() => errorSignal()),
|
|
945
1024
|
isConnected: computed3(() => isConnectedSignal()),
|
|
946
1025
|
partial: computed3(() => partialSignal()),
|
|
1026
|
+
reconnect: computed3(() => reconnectSignal()),
|
|
947
1027
|
sendAudio: (audio) => stream.sendAudio(audio),
|
|
948
1028
|
sessionId: computed3(() => sessionIdSignal()),
|
|
949
1029
|
status: computed3(() => statusSignal()),
|
|
@@ -1425,6 +1505,7 @@ var createInitialState2 = (stream) => ({
|
|
|
1425
1505
|
isConnected: stream.isConnected,
|
|
1426
1506
|
isRecording: false,
|
|
1427
1507
|
partial: stream.partial,
|
|
1508
|
+
reconnect: stream.reconnect,
|
|
1428
1509
|
recordingError: null,
|
|
1429
1510
|
sessionId: stream.sessionId,
|
|
1430
1511
|
scenarioId: stream.scenarioId,
|
|
@@ -1454,6 +1535,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1454
1535
|
error: stream.error,
|
|
1455
1536
|
isConnected: stream.isConnected,
|
|
1456
1537
|
partial: stream.partial,
|
|
1538
|
+
reconnect: stream.reconnect,
|
|
1457
1539
|
sessionId: stream.sessionId,
|
|
1458
1540
|
scenarioId: stream.scenarioId,
|
|
1459
1541
|
status: stream.status,
|
|
@@ -1554,6 +1636,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1554
1636
|
get recordingError() {
|
|
1555
1637
|
return state.recordingError;
|
|
1556
1638
|
},
|
|
1639
|
+
get reconnect() {
|
|
1640
|
+
return state.reconnect;
|
|
1641
|
+
},
|
|
1557
1642
|
sendAudio: (audio) => stream.sendAudio(audio),
|
|
1558
1643
|
get sessionId() {
|
|
1559
1644
|
return state.sessionId;
|
|
@@ -1609,6 +1694,7 @@ class VoiceControllerService {
|
|
|
1609
1694
|
const isConnectedSignal = signal4(false);
|
|
1610
1695
|
const isRecordingSignal = signal4(false);
|
|
1611
1696
|
const partialSignal = signal4("");
|
|
1697
|
+
const reconnectSignal = signal4(controller.reconnect);
|
|
1612
1698
|
const recordingErrorSignal = signal4(null);
|
|
1613
1699
|
const sessionIdSignal = signal4(controller.sessionId);
|
|
1614
1700
|
const statusSignal = signal4(controller.status);
|
|
@@ -1620,6 +1706,7 @@ class VoiceControllerService {
|
|
|
1620
1706
|
isConnectedSignal.set(controller.isConnected);
|
|
1621
1707
|
isRecordingSignal.set(controller.isRecording);
|
|
1622
1708
|
partialSignal.set(controller.partial);
|
|
1709
|
+
reconnectSignal.set(controller.reconnect);
|
|
1623
1710
|
recordingErrorSignal.set(controller.recordingError);
|
|
1624
1711
|
sessionIdSignal.set(controller.sessionId);
|
|
1625
1712
|
statusSignal.set(controller.status);
|
|
@@ -1640,6 +1727,7 @@ class VoiceControllerService {
|
|
|
1640
1727
|
isConnected: computed4(() => isConnectedSignal()),
|
|
1641
1728
|
isRecording: computed4(() => isRecordingSignal()),
|
|
1642
1729
|
partial: computed4(() => partialSignal()),
|
|
1730
|
+
reconnect: computed4(() => reconnectSignal()),
|
|
1643
1731
|
recordingError: computed4(() => recordingErrorSignal()),
|
|
1644
1732
|
sendAudio: (audio) => controller.sendAudio(audio),
|
|
1645
1733
|
sessionId: computed4(() => sessionIdSignal()),
|
|
@@ -15,6 +15,7 @@ export declare class VoiceControllerService {
|
|
|
15
15
|
isConnected: import("@angular/core").Signal<boolean>;
|
|
16
16
|
isRecording: import("@angular/core").Signal<boolean>;
|
|
17
17
|
partial: import("@angular/core").Signal<string>;
|
|
18
|
+
reconnect: import("@angular/core").Signal<import("..").VoiceReconnectClientState>;
|
|
18
19
|
recordingError: import("@angular/core").Signal<string | null>;
|
|
19
20
|
sendAudio: (audio: Uint8Array | ArrayBuffer) => void;
|
|
20
21
|
sessionId: import("@angular/core").Signal<string | null>;
|
|
@@ -15,6 +15,7 @@ export declare class VoiceStreamService {
|
|
|
15
15
|
error: import("@angular/core").Signal<string | null>;
|
|
16
16
|
isConnected: import("@angular/core").Signal<boolean>;
|
|
17
17
|
partial: import("@angular/core").Signal<string>;
|
|
18
|
+
reconnect: import("@angular/core").Signal<import("..").VoiceReconnectClientState>;
|
|
18
19
|
sendAudio: (audio: Uint8Array | ArrayBuffer) => void;
|
|
19
20
|
sessionId: import("@angular/core").Signal<string | null>;
|
|
20
21
|
status: import("@angular/core").Signal<import("..").VoiceSessionStatus | "idle">;
|
package/dist/client/actions.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
7
7
|
type: "audio";
|
|
8
8
|
text?: undefined;
|
|
9
9
|
sessionId?: undefined;
|
|
10
|
+
reconnect?: undefined;
|
|
10
11
|
event?: undefined;
|
|
11
12
|
message?: undefined;
|
|
12
13
|
transcript?: undefined;
|
|
@@ -25,6 +26,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
25
26
|
receivedAt?: undefined;
|
|
26
27
|
turnId?: undefined;
|
|
27
28
|
sessionId?: undefined;
|
|
29
|
+
reconnect?: undefined;
|
|
28
30
|
event?: undefined;
|
|
29
31
|
message?: undefined;
|
|
30
32
|
transcript?: undefined;
|
|
@@ -43,6 +45,26 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
43
45
|
receivedAt?: undefined;
|
|
44
46
|
turnId?: undefined;
|
|
45
47
|
text?: undefined;
|
|
48
|
+
reconnect?: undefined;
|
|
49
|
+
event?: undefined;
|
|
50
|
+
message?: undefined;
|
|
51
|
+
transcript?: undefined;
|
|
52
|
+
assistantTexts?: undefined;
|
|
53
|
+
call?: undefined;
|
|
54
|
+
partial?: undefined;
|
|
55
|
+
scenarioId?: undefined;
|
|
56
|
+
status?: undefined;
|
|
57
|
+
turns?: undefined;
|
|
58
|
+
turn?: undefined;
|
|
59
|
+
} | {
|
|
60
|
+
reconnect: import("..").VoiceReconnectClientState;
|
|
61
|
+
type: "connection";
|
|
62
|
+
chunk?: undefined;
|
|
63
|
+
format?: undefined;
|
|
64
|
+
receivedAt?: undefined;
|
|
65
|
+
turnId?: undefined;
|
|
66
|
+
text?: undefined;
|
|
67
|
+
sessionId?: undefined;
|
|
46
68
|
event?: undefined;
|
|
47
69
|
message?: undefined;
|
|
48
70
|
transcript?: undefined;
|
|
@@ -62,6 +84,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
62
84
|
receivedAt?: undefined;
|
|
63
85
|
turnId?: undefined;
|
|
64
86
|
text?: undefined;
|
|
87
|
+
reconnect?: undefined;
|
|
65
88
|
message?: undefined;
|
|
66
89
|
transcript?: undefined;
|
|
67
90
|
assistantTexts?: undefined;
|
|
@@ -80,6 +103,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
80
103
|
turnId?: undefined;
|
|
81
104
|
text?: undefined;
|
|
82
105
|
sessionId?: undefined;
|
|
106
|
+
reconnect?: undefined;
|
|
83
107
|
event?: undefined;
|
|
84
108
|
transcript?: undefined;
|
|
85
109
|
assistantTexts?: undefined;
|
|
@@ -98,6 +122,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
98
122
|
turnId?: undefined;
|
|
99
123
|
text?: undefined;
|
|
100
124
|
sessionId?: undefined;
|
|
125
|
+
reconnect?: undefined;
|
|
101
126
|
event?: undefined;
|
|
102
127
|
message?: undefined;
|
|
103
128
|
assistantTexts?: undefined;
|
|
@@ -116,6 +141,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
116
141
|
turnId?: undefined;
|
|
117
142
|
text?: undefined;
|
|
118
143
|
sessionId?: undefined;
|
|
144
|
+
reconnect?: undefined;
|
|
119
145
|
event?: undefined;
|
|
120
146
|
message?: undefined;
|
|
121
147
|
assistantTexts?: undefined;
|
|
@@ -139,6 +165,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
139
165
|
receivedAt?: undefined;
|
|
140
166
|
turnId?: undefined;
|
|
141
167
|
text?: undefined;
|
|
168
|
+
reconnect?: undefined;
|
|
142
169
|
event?: undefined;
|
|
143
170
|
message?: undefined;
|
|
144
171
|
transcript?: undefined;
|
|
@@ -153,6 +180,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
153
180
|
receivedAt?: undefined;
|
|
154
181
|
turnId?: undefined;
|
|
155
182
|
text?: undefined;
|
|
183
|
+
reconnect?: undefined;
|
|
156
184
|
event?: undefined;
|
|
157
185
|
message?: undefined;
|
|
158
186
|
transcript?: undefined;
|
|
@@ -170,6 +198,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
170
198
|
turnId?: undefined;
|
|
171
199
|
text?: undefined;
|
|
172
200
|
sessionId?: undefined;
|
|
201
|
+
reconnect?: undefined;
|
|
173
202
|
event?: undefined;
|
|
174
203
|
message?: undefined;
|
|
175
204
|
transcript?: undefined;
|
|
@@ -188,6 +188,11 @@ var serverMessageToAction = (message) => {
|
|
|
188
188
|
sessionId: message.sessionId,
|
|
189
189
|
type: "complete"
|
|
190
190
|
};
|
|
191
|
+
case "connection":
|
|
192
|
+
return {
|
|
193
|
+
reconnect: message.reconnect,
|
|
194
|
+
type: "connection"
|
|
195
|
+
};
|
|
191
196
|
case "call_lifecycle":
|
|
192
197
|
return {
|
|
193
198
|
event: message.event,
|
|
@@ -280,6 +285,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
280
285
|
case "assistant":
|
|
281
286
|
case "call_lifecycle":
|
|
282
287
|
case "complete":
|
|
288
|
+
case "connection":
|
|
283
289
|
case "error":
|
|
284
290
|
case "final":
|
|
285
291
|
case "partial":
|
|
@@ -321,6 +327,9 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
321
327
|
sessionId: options.sessionId ?? createSessionId(),
|
|
322
328
|
ws: null
|
|
323
329
|
};
|
|
330
|
+
const emitConnection = (reconnect) => {
|
|
331
|
+
listeners.forEach((listener) => listener(reconnect));
|
|
332
|
+
};
|
|
324
333
|
const clearTimers = () => {
|
|
325
334
|
if (state.pingInterval) {
|
|
326
335
|
clearInterval(state.pingInterval);
|
|
@@ -343,9 +352,28 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
343
352
|
}
|
|
344
353
|
};
|
|
345
354
|
const scheduleReconnect = () => {
|
|
355
|
+
const nextAttemptAt = Date.now() + RECONNECT_DELAY_MS;
|
|
346
356
|
state.reconnectAttempts += 1;
|
|
357
|
+
emitConnection({
|
|
358
|
+
reconnect: {
|
|
359
|
+
attempts: state.reconnectAttempts,
|
|
360
|
+
lastDisconnectAt: Date.now(),
|
|
361
|
+
maxAttempts: maxReconnectAttempts,
|
|
362
|
+
nextAttemptAt,
|
|
363
|
+
status: "reconnecting"
|
|
364
|
+
},
|
|
365
|
+
type: "connection"
|
|
366
|
+
});
|
|
347
367
|
state.reconnectTimeout = setTimeout(() => {
|
|
348
368
|
if (state.reconnectAttempts > maxReconnectAttempts) {
|
|
369
|
+
emitConnection({
|
|
370
|
+
reconnect: {
|
|
371
|
+
attempts: state.reconnectAttempts,
|
|
372
|
+
maxAttempts: maxReconnectAttempts,
|
|
373
|
+
status: "exhausted"
|
|
374
|
+
},
|
|
375
|
+
type: "connection"
|
|
376
|
+
});
|
|
349
377
|
return;
|
|
350
378
|
}
|
|
351
379
|
connect();
|
|
@@ -355,9 +383,21 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
355
383
|
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
356
384
|
ws.binaryType = "arraybuffer";
|
|
357
385
|
ws.onopen = () => {
|
|
386
|
+
const wasReconnecting = state.reconnectAttempts > 0;
|
|
358
387
|
state.isConnected = true;
|
|
359
|
-
state.reconnectAttempts = 0;
|
|
360
388
|
flushPendingMessages();
|
|
389
|
+
if (wasReconnecting) {
|
|
390
|
+
emitConnection({
|
|
391
|
+
reconnect: {
|
|
392
|
+
attempts: state.reconnectAttempts,
|
|
393
|
+
lastResumedAt: Date.now(),
|
|
394
|
+
maxAttempts: maxReconnectAttempts,
|
|
395
|
+
status: "resumed"
|
|
396
|
+
},
|
|
397
|
+
type: "connection"
|
|
398
|
+
});
|
|
399
|
+
state.reconnectAttempts = 0;
|
|
400
|
+
}
|
|
361
401
|
listeners.forEach((listener) => listener({
|
|
362
402
|
scenarioId: state.scenarioId ?? undefined,
|
|
363
403
|
sessionId: state.sessionId,
|
|
@@ -387,6 +427,16 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
387
427
|
const reconnectable = shouldReconnect && event.code !== WS_NORMAL_CLOSURE && state.reconnectAttempts < maxReconnectAttempts;
|
|
388
428
|
if (reconnectable) {
|
|
389
429
|
scheduleReconnect();
|
|
430
|
+
} else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
|
|
431
|
+
emitConnection({
|
|
432
|
+
reconnect: {
|
|
433
|
+
attempts: state.reconnectAttempts,
|
|
434
|
+
lastDisconnectAt: Date.now(),
|
|
435
|
+
maxAttempts: maxReconnectAttempts,
|
|
436
|
+
status: "exhausted"
|
|
437
|
+
},
|
|
438
|
+
type: "connection"
|
|
439
|
+
});
|
|
390
440
|
}
|
|
391
441
|
};
|
|
392
442
|
state.ws = ws;
|
|
@@ -457,6 +507,11 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
457
507
|
};
|
|
458
508
|
|
|
459
509
|
// src/client/store.ts
|
|
510
|
+
var createInitialReconnectState = () => ({
|
|
511
|
+
attempts: 0,
|
|
512
|
+
maxAttempts: 0,
|
|
513
|
+
status: "idle"
|
|
514
|
+
});
|
|
460
515
|
var createInitialState = () => ({
|
|
461
516
|
assistantAudio: [],
|
|
462
517
|
assistantTexts: [],
|
|
@@ -465,6 +520,7 @@ var createInitialState = () => ({
|
|
|
465
520
|
isConnected: false,
|
|
466
521
|
scenarioId: null,
|
|
467
522
|
partial: "",
|
|
523
|
+
reconnect: createInitialReconnectState(),
|
|
468
524
|
sessionId: null,
|
|
469
525
|
status: "idle",
|
|
470
526
|
turns: []
|
|
@@ -521,7 +577,19 @@ var createVoiceStreamStore = () => {
|
|
|
521
577
|
case "connected":
|
|
522
578
|
state = {
|
|
523
579
|
...state,
|
|
524
|
-
isConnected: true
|
|
580
|
+
isConnected: true,
|
|
581
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
582
|
+
...state.reconnect,
|
|
583
|
+
lastResumedAt: Date.now(),
|
|
584
|
+
nextAttemptAt: undefined,
|
|
585
|
+
status: "resumed"
|
|
586
|
+
} : state.reconnect
|
|
587
|
+
};
|
|
588
|
+
break;
|
|
589
|
+
case "connection":
|
|
590
|
+
state = {
|
|
591
|
+
...state,
|
|
592
|
+
reconnect: action.reconnect
|
|
525
593
|
};
|
|
526
594
|
break;
|
|
527
595
|
case "disconnected":
|
|
@@ -557,6 +625,12 @@ var createVoiceStreamStore = () => {
|
|
|
557
625
|
error: null,
|
|
558
626
|
isConnected: action.status === "active",
|
|
559
627
|
partial: action.partial,
|
|
628
|
+
reconnect: state.reconnect.status === "reconnecting" ? {
|
|
629
|
+
...state.reconnect,
|
|
630
|
+
lastResumedAt: Date.now(),
|
|
631
|
+
nextAttemptAt: undefined,
|
|
632
|
+
status: "resumed"
|
|
633
|
+
} : state.reconnect,
|
|
560
634
|
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
561
635
|
sessionId: action.sessionId,
|
|
562
636
|
status: action.status,
|
|
@@ -649,6 +723,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
649
723
|
get partial() {
|
|
650
724
|
return store.getSnapshot().partial;
|
|
651
725
|
},
|
|
726
|
+
get reconnect() {
|
|
727
|
+
return store.getSnapshot().reconnect;
|
|
728
|
+
},
|
|
652
729
|
get sessionId() {
|
|
653
730
|
return connection.getSessionId();
|
|
654
731
|
},
|
|
@@ -967,6 +1044,7 @@ var createInitialState2 = (stream) => ({
|
|
|
967
1044
|
isConnected: stream.isConnected,
|
|
968
1045
|
isRecording: false,
|
|
969
1046
|
partial: stream.partial,
|
|
1047
|
+
reconnect: stream.reconnect,
|
|
970
1048
|
recordingError: null,
|
|
971
1049
|
sessionId: stream.sessionId,
|
|
972
1050
|
scenarioId: stream.scenarioId,
|
|
@@ -996,6 +1074,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
996
1074
|
error: stream.error,
|
|
997
1075
|
isConnected: stream.isConnected,
|
|
998
1076
|
partial: stream.partial,
|
|
1077
|
+
reconnect: stream.reconnect,
|
|
999
1078
|
sessionId: stream.sessionId,
|
|
1000
1079
|
scenarioId: stream.scenarioId,
|
|
1001
1080
|
status: stream.status,
|
|
@@ -1096,6 +1175,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1096
1175
|
get recordingError() {
|
|
1097
1176
|
return state.recordingError;
|
|
1098
1177
|
},
|
|
1178
|
+
get reconnect() {
|
|
1179
|
+
return state.reconnect;
|
|
1180
|
+
},
|
|
1099
1181
|
sendAudio: (audio) => stream.sendAudio(audio),
|
|
1100
1182
|
get sessionId() {
|
|
1101
1183
|
return state.sessionId;
|