@voxevolv/client 0.3.1 → 0.3.3
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/CHANGELOG.md +12 -0
- package/README.md +36 -5
- package/dist/browser/index.js +6 -6
- package/dist/browser/index.js.map +4 -4
- package/dist/browser/index.js.sha384 +1 -1
- package/dist/browser/manifest.json +1 -1
- package/dist/context-queue.d.ts +19 -0
- package/dist/context-queue.d.ts.map +1 -0
- package/dist/context-queue.js +112 -0
- package/dist/context-queue.js.map +1 -0
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +160 -21
- package/dist/index.js.map +1 -1
- package/dist/transcripts.d.ts +21 -0
- package/dist/transcripts.d.ts.map +1 -0
- package/dist/transcripts.js +45 -0
- package/dist/transcripts.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
sha384-
|
|
1
|
+
sha384-PewpzPwvekVvKZhoey5uSqOKk7w9GZB54u2RoDFWb6gph0DQUrSo7DjKgVgbMIl0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ContextUpdate, ContextUpdatedPayload } from "./protocol.js";
|
|
2
|
+
/** Only replace updates can be coalesced or restored without duplicating data. */
|
|
3
|
+
export declare class ReplacementContextQueue {
|
|
4
|
+
private send;
|
|
5
|
+
private paused;
|
|
6
|
+
private generation;
|
|
7
|
+
private latest;
|
|
8
|
+
private pending;
|
|
9
|
+
private running;
|
|
10
|
+
private failure;
|
|
11
|
+
constructor(send: (update: ContextUpdate, timeoutMs: number) => Promise<ContextUpdatedPayload>);
|
|
12
|
+
submit(update: ContextUpdate, timeoutMs: number): Promise<ContextUpdatedPayload>;
|
|
13
|
+
pause(): void;
|
|
14
|
+
resume(restore?: boolean): Promise<void>;
|
|
15
|
+
clear(error: Error): void;
|
|
16
|
+
private start;
|
|
17
|
+
private drain;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=context-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-queue.d.ts","sourceRoot":"","sources":["../src/context-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAS1E,kFAAkF;AAClF,qBAAa,uBAAuB;IAQtB,OAAO,CAAC,IAAI;IAPxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,MAAM,CAAoC;IAClD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,OAAO,CAAsB;IAErC,YAAoB,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,EAAI;IAE1G,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAqB/E;IAED,KAAK,IAAI,IAAI,CAGZ;IAEK,MAAM,CAAC,OAAO,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB3C;IAED,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAKxB;IAED,OAAO,CAAC,KAAK;YASC,KAAK;CAsBpB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/** Only replace updates can be coalesced or restored without duplicating data. */
|
|
2
|
+
export class ReplacementContextQueue {
|
|
3
|
+
send;
|
|
4
|
+
paused = false;
|
|
5
|
+
generation = 0;
|
|
6
|
+
latest = new Map();
|
|
7
|
+
pending = new Map();
|
|
8
|
+
running = new Map();
|
|
9
|
+
failure = null;
|
|
10
|
+
constructor(send) {
|
|
11
|
+
this.send = send;
|
|
12
|
+
}
|
|
13
|
+
submit(update, timeoutMs) {
|
|
14
|
+
const activeKeys = new Set([...this.pending.keys(), ...this.running.keys()]);
|
|
15
|
+
if (activeKeys.size >= 64 && !activeKeys.has(update.key)) {
|
|
16
|
+
return Promise.reject(new Error("Too many pending context keys"));
|
|
17
|
+
}
|
|
18
|
+
// Bound retained image/text memory even for applications using dynamic keys.
|
|
19
|
+
this.latest.delete(update.key);
|
|
20
|
+
this.latest.set(update.key, update);
|
|
21
|
+
let bytes = 0;
|
|
22
|
+
let count = 0;
|
|
23
|
+
for (const [key, value] of [...this.latest].reverse()) {
|
|
24
|
+
bytes += "image" in value ? value.image.size : new TextEncoder().encode(value.text).byteLength;
|
|
25
|
+
count += 1;
|
|
26
|
+
if (bytes > 16 * 1024 * 1024 || count > 64)
|
|
27
|
+
this.latest.delete(key);
|
|
28
|
+
}
|
|
29
|
+
const response = new Promise((resolve, reject) => {
|
|
30
|
+
this.pending.get(update.key)?.reject(new Error("Context update superseded by a newer value"));
|
|
31
|
+
this.pending.set(update.key, { update, timeoutMs, resolve, reject });
|
|
32
|
+
});
|
|
33
|
+
this.start(update.key);
|
|
34
|
+
return response;
|
|
35
|
+
}
|
|
36
|
+
pause() {
|
|
37
|
+
this.generation += 1;
|
|
38
|
+
this.paused = true;
|
|
39
|
+
}
|
|
40
|
+
async resume(restore = false) {
|
|
41
|
+
const generation = this.generation;
|
|
42
|
+
// The SDK cancels tracked commands before restoring the new worker.
|
|
43
|
+
await Promise.all(this.running.values());
|
|
44
|
+
if (generation !== this.generation)
|
|
45
|
+
throw new Error("Context restoration interrupted");
|
|
46
|
+
this.failure = null;
|
|
47
|
+
if (restore) {
|
|
48
|
+
for (const [key, update] of this.latest) {
|
|
49
|
+
if (this.pending.has(key))
|
|
50
|
+
continue;
|
|
51
|
+
this.pending.set(key, {
|
|
52
|
+
update: { ...update, respond: false },
|
|
53
|
+
timeoutMs: 20_000,
|
|
54
|
+
resolve: () => { },
|
|
55
|
+
reject: () => { },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
this.paused = false;
|
|
60
|
+
for (const key of this.pending.keys())
|
|
61
|
+
this.start(key);
|
|
62
|
+
await Promise.all(this.running.values());
|
|
63
|
+
if (generation !== this.generation)
|
|
64
|
+
throw new Error("Context restoration interrupted");
|
|
65
|
+
if (this.failure)
|
|
66
|
+
throw this.failure;
|
|
67
|
+
}
|
|
68
|
+
clear(error) {
|
|
69
|
+
this.pause();
|
|
70
|
+
this.latest.clear();
|
|
71
|
+
for (const request of this.pending.values())
|
|
72
|
+
request.reject(error);
|
|
73
|
+
this.pending.clear();
|
|
74
|
+
}
|
|
75
|
+
start(key) {
|
|
76
|
+
if (this.paused || this.running.has(key))
|
|
77
|
+
return;
|
|
78
|
+
const task = this.drain(key).finally(() => {
|
|
79
|
+
this.running.delete(key);
|
|
80
|
+
if (this.pending.has(key))
|
|
81
|
+
this.start(key);
|
|
82
|
+
});
|
|
83
|
+
this.running.set(key, task);
|
|
84
|
+
}
|
|
85
|
+
async drain(key) {
|
|
86
|
+
while (!this.paused) {
|
|
87
|
+
const request = this.pending.get(key);
|
|
88
|
+
if (!request)
|
|
89
|
+
return;
|
|
90
|
+
this.pending.delete(key);
|
|
91
|
+
try {
|
|
92
|
+
request.resolve(await this.send(request.update, request.timeoutMs));
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (this.paused && !this.pending.has(key) && this.latest.get(key) === request.update) {
|
|
96
|
+
this.pending.set(key, request);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
request.reject(error instanceof Error ? error : new Error(String(error)));
|
|
100
|
+
}
|
|
101
|
+
if (!this.paused) {
|
|
102
|
+
// Invalid/rejected values must not poison the next restoration.
|
|
103
|
+
if (this.latest.get(key) === request.update)
|
|
104
|
+
this.latest.delete(key);
|
|
105
|
+
this.failure = error instanceof Error ? error : new Error(String(error));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=context-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-queue.js","sourceRoot":"","sources":["../src/context-queue.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Room } from "livekit-client";
|
|
2
2
|
import { type CommandAckPayload, type ContextUpdate, type ContextUpdatedPayload, type EventGap, type RealtimeEvent } from "./protocol.js";
|
|
3
|
+
import { type TranscriptMessage } from "./transcripts.js";
|
|
4
|
+
export { TranscriptStore, type TranscriptMessage } from "./transcripts.js";
|
|
3
5
|
export { CommandError, EventCursor, createClientMessage, isCommandAckPayload, isCommandErrorPayload, isContextRejectedPayload, isContextUpdatePayload, isContextUpdatedPayload, isRealtimeEvent, } from "./protocol.js";
|
|
4
6
|
export type { ClientMessage, CommandAckPayload, CommandErrorPayload, ContextRejectedPayload, ContextUpdate, ContextUpdatePayload, ContextUpdatedPayload, EventGap, RealtimeEvent, } from "./protocol.js";
|
|
5
7
|
export { decodeAgentSnapshotPayload, decodeClientHelloPayload, decodeClientMessage, decodeCommandAckPayload, decodeCommandErrorPayload, decodeContextRejectedPayload, decodeContextUpdatePayload, decodeContextUpdatedPayload, decodeRealtimeEvent, } from "./generated/protocol-codecs.js";
|
|
@@ -16,7 +18,7 @@ export interface SessionCredentials {
|
|
|
16
18
|
access_token: string;
|
|
17
19
|
access_token_expires_at: string;
|
|
18
20
|
}
|
|
19
|
-
export declare const SDK_VERSION = "0.3.
|
|
21
|
+
export declare const SDK_VERSION = "0.3.3";
|
|
20
22
|
type Listener = (event: RealtimeEvent) => void;
|
|
21
23
|
type StateListener = (state: ConnectionState) => void;
|
|
22
24
|
type GapListener = (gap: EventGap) => void;
|
|
@@ -46,6 +48,7 @@ export interface AutoRejoinOptions {
|
|
|
46
48
|
maxAttempts?: number;
|
|
47
49
|
baseDelayMs?: number;
|
|
48
50
|
maxDelayMs?: number;
|
|
51
|
+
timeoutMs?: number;
|
|
49
52
|
}
|
|
50
53
|
export interface RealtimeSessionOptions {
|
|
51
54
|
connect?: ConnectOptions;
|
|
@@ -115,6 +118,8 @@ export declare class RealtimeSession {
|
|
|
115
118
|
private readyListeners;
|
|
116
119
|
private userTranscriptListeners;
|
|
117
120
|
private agentTranscriptListeners;
|
|
121
|
+
private transcriptListeners;
|
|
122
|
+
private transcriptStore;
|
|
118
123
|
private errorListeners;
|
|
119
124
|
private endedListeners;
|
|
120
125
|
private toolCallListeners;
|
|
@@ -129,6 +134,9 @@ export declare class RealtimeSession {
|
|
|
129
134
|
private reconnectStartedAt;
|
|
130
135
|
private pendingReconnect;
|
|
131
136
|
private agentReady;
|
|
137
|
+
private agentStreamId;
|
|
138
|
+
private contextGeneration;
|
|
139
|
+
private readonly replacementContext;
|
|
132
140
|
private readyResolve;
|
|
133
141
|
private replayPromise;
|
|
134
142
|
private pendingCommands;
|
|
@@ -172,6 +180,9 @@ export declare class RealtimeSession {
|
|
|
172
180
|
onReady(listener: (event: RealtimeEvent) => void): () => void;
|
|
173
181
|
onUserTranscript(listener: (event: TranscriptEvent) => void): () => void;
|
|
174
182
|
onAgentTranscript(listener: (event: TranscriptEvent) => void): () => void;
|
|
183
|
+
/** Latest message snapshots, retained across transport recovery and replay. */
|
|
184
|
+
get transcript(): readonly TranscriptMessage[];
|
|
185
|
+
onTranscriptUpdated(listener: (message: TranscriptMessage) => void): () => void;
|
|
175
186
|
onError(listener: (event: RealtimeEvent) => void): () => void;
|
|
176
187
|
onEnded(listener: (event: RealtimeEvent) => void): () => void;
|
|
177
188
|
onToolCall(listener: (event: ToolCallEvent) => void): () => void;
|
|
@@ -184,6 +195,7 @@ export declare class RealtimeSession {
|
|
|
184
195
|
setMicrophoneEnabled(enabled: boolean): Promise<void>;
|
|
185
196
|
sendCommand<T extends Record<string, unknown>>(type: string, payload: T, timeoutMs?: number): Promise<CommandAckPayload>;
|
|
186
197
|
updateContext(update: ContextUpdate, timeoutMs?: number): Promise<ContextUpdatedPayload>;
|
|
198
|
+
private sendContextUpdate;
|
|
187
199
|
private uploadTextContext;
|
|
188
200
|
private uploadImageContext;
|
|
189
201
|
disconnect(): Promise<void>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,IAAI,EAIL,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAUL,KAAK,iBAAiB,EAEtB,KAAK,aAAa,EAElB,KAAK,qBAAqB,EAC1B,KAAK,QAAQ,EACb,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,QAAQ,EACR,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,EAC5B,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AAExC,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,YAAY,GACZ,qBAAqB,GACrB,WAAW,GACX,cAAc,GACd,UAAU,GACV,cAAc,GACd,QAAQ,CAAC;AAEb,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,WAAW,GACX,MAAM,GACN,MAAM,GACN,MAAM,CAAC;AAEX,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,qBAAqB,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,eAAO,MAAM,WAAW,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { ConnectionState as LiveKitConnectionState, DataPacket_Kind, DisconnectReason, Room, RoomEvent, RpcError, Track, } from "livekit-client";
|
|
2
2
|
import { createClientMessage, CommandError, EventCursor, isCommandAckPayload, isCommandErrorPayload, isContextRejectedPayload, isContextUpdatePayload, isContextUpdatedPayload, isRealtimeEvent, } from "./protocol.js";
|
|
3
|
+
import { ReplacementContextQueue } from "./context-queue.js";
|
|
4
|
+
import { TranscriptStore } from "./transcripts.js";
|
|
5
|
+
export { TranscriptStore } from "./transcripts.js";
|
|
3
6
|
export { CommandError, EventCursor, createClientMessage, isCommandAckPayload, isCommandErrorPayload, isContextRejectedPayload, isContextUpdatePayload, isContextUpdatedPayload, isRealtimeEvent, } from "./protocol.js";
|
|
4
7
|
export { decodeAgentSnapshotPayload, decodeClientHelloPayload, decodeClientMessage, decodeCommandAckPayload, decodeCommandErrorPayload, decodeContextRejectedPayload, decodeContextUpdatePayload, decodeContextUpdatedPayload, decodeRealtimeEvent, } from "./generated/protocol-codecs.js";
|
|
5
|
-
export const SDK_VERSION = "0.3.
|
|
8
|
+
export const SDK_VERSION = "0.3.3";
|
|
9
|
+
const CLIENT_HELLO_TIMEOUT_MS = 30_000;
|
|
6
10
|
export class RealtimeSessionHttpError extends Error {
|
|
7
11
|
status;
|
|
8
12
|
code;
|
|
@@ -33,6 +37,8 @@ export class RealtimeSession {
|
|
|
33
37
|
readyListeners = new Set();
|
|
34
38
|
userTranscriptListeners = new Set();
|
|
35
39
|
agentTranscriptListeners = new Set();
|
|
40
|
+
transcriptListeners = new Set();
|
|
41
|
+
transcriptStore = new TranscriptStore();
|
|
36
42
|
errorListeners = new Set();
|
|
37
43
|
endedListeners = new Set();
|
|
38
44
|
toolCallListeners = new Set();
|
|
@@ -47,6 +53,9 @@ export class RealtimeSession {
|
|
|
47
53
|
reconnectStartedAt = null;
|
|
48
54
|
pendingReconnect = null;
|
|
49
55
|
agentReady = false;
|
|
56
|
+
agentStreamId = null;
|
|
57
|
+
contextGeneration = 0;
|
|
58
|
+
replacementContext = new ReplacementContextQueue((update, timeoutMs) => this.sendContextUpdate(update, timeoutMs));
|
|
50
59
|
readyResolve = null;
|
|
51
60
|
replayPromise = null;
|
|
52
61
|
pendingCommands = new Map();
|
|
@@ -243,6 +252,14 @@ export class RealtimeSession {
|
|
|
243
252
|
this.agentTranscriptListeners.add(listener);
|
|
244
253
|
return () => this.agentTranscriptListeners.delete(listener);
|
|
245
254
|
}
|
|
255
|
+
/** Latest message snapshots, retained across transport recovery and replay. */
|
|
256
|
+
get transcript() {
|
|
257
|
+
return this.transcriptStore.snapshot;
|
|
258
|
+
}
|
|
259
|
+
onTranscriptUpdated(listener) {
|
|
260
|
+
this.transcriptListeners.add(listener);
|
|
261
|
+
return () => this.transcriptListeners.delete(listener);
|
|
262
|
+
}
|
|
246
263
|
onError(listener) {
|
|
247
264
|
this.errorListeners.add(listener);
|
|
248
265
|
return () => this.errorListeners.delete(listener);
|
|
@@ -290,6 +307,7 @@ export class RealtimeSession {
|
|
|
290
307
|
if (blockedStates.includes(this.stateValue)) {
|
|
291
308
|
throw new Error(`Cannot connect while session is ${this.stateValue}`);
|
|
292
309
|
}
|
|
310
|
+
const generation = this.contextGeneration;
|
|
293
311
|
const resolved = { ...this.connectDefaults, ...options };
|
|
294
312
|
const audioTrack = resolved.audioTrack ?? null;
|
|
295
313
|
const microphone = resolved.microphone ?? audioTrack === null;
|
|
@@ -303,6 +321,8 @@ export class RealtimeSession {
|
|
|
303
321
|
this.applicationAudioTrack = audioTrack;
|
|
304
322
|
if (!recovering) {
|
|
305
323
|
this.sessionEnded = false;
|
|
324
|
+
this.agentStreamId = null;
|
|
325
|
+
this.reconnectStartedAt = null;
|
|
306
326
|
this.pendingEndEvent = null;
|
|
307
327
|
this.endNotificationDelivered = false;
|
|
308
328
|
this.setState("connecting");
|
|
@@ -329,6 +349,14 @@ export class RealtimeSession {
|
|
|
329
349
|
if (waitForRemoteAudio)
|
|
330
350
|
await this.waitForRemoteAudioTrack(readyDeadline, signal);
|
|
331
351
|
throwIfAborted(signal);
|
|
352
|
+
if (this.sessionEnded || generation !== this.contextGeneration) {
|
|
353
|
+
throw new Error("Connection restoration interrupted");
|
|
354
|
+
}
|
|
355
|
+
await this.replacementContext.resume(recovering);
|
|
356
|
+
throwIfAborted(signal);
|
|
357
|
+
if (this.sessionEnded || generation !== this.contextGeneration) {
|
|
358
|
+
throw new Error("Connection restoration interrupted");
|
|
359
|
+
}
|
|
332
360
|
this.hasConnectedValue = true;
|
|
333
361
|
this.setState("connected");
|
|
334
362
|
}
|
|
@@ -373,6 +401,9 @@ export class RealtimeSession {
|
|
|
373
401
|
}
|
|
374
402
|
}
|
|
375
403
|
async performRejoin(apiBase, signal, recovering = true) {
|
|
404
|
+
this.contextGeneration += 1;
|
|
405
|
+
this.replacementContext.pause();
|
|
406
|
+
this.rejectPendingCommands(new Error("Restoring the session"));
|
|
376
407
|
let response = await this.fetchRoomToken(apiBase, signal);
|
|
377
408
|
if (response.status === 401 && this.refreshCredentialsCallback) {
|
|
378
409
|
await this.refreshCredentials();
|
|
@@ -393,6 +424,13 @@ export class RealtimeSession {
|
|
|
393
424
|
}
|
|
394
425
|
}
|
|
395
426
|
throwIfAborted(signal);
|
|
427
|
+
if (recovering && this.reconnectStartedAt !== null) {
|
|
428
|
+
this.pendingReconnect = {
|
|
429
|
+
started_at: new Date(this.reconnectStartedAt).toISOString(),
|
|
430
|
+
recovered_at: new Date().toISOString(),
|
|
431
|
+
duration_ms: Date.now() - this.reconnectStartedAt,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
396
434
|
await this.connectWithMode({
|
|
397
435
|
apiBase,
|
|
398
436
|
microphone: this.useManagedMicrophone,
|
|
@@ -408,9 +446,31 @@ export class RealtimeSession {
|
|
|
408
446
|
return this.sendTrackedCommand(message, timeoutMs);
|
|
409
447
|
}
|
|
410
448
|
async updateContext(update, timeoutMs = 20_000) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
449
|
+
if (this.sessionEnded || ["failed", "disconnected"].includes(this.stateValue)) {
|
|
450
|
+
throw new Error("Cannot update context while the session is inactive");
|
|
451
|
+
}
|
|
452
|
+
if (update.mode === "replace")
|
|
453
|
+
return this.replacementContext.submit(update, timeoutMs);
|
|
454
|
+
if (this.activeRecovery)
|
|
455
|
+
throw new Error("Cannot append context during recovery");
|
|
456
|
+
return this.sendContextUpdate(update, timeoutMs);
|
|
457
|
+
}
|
|
458
|
+
async sendContextUpdate(update, timeoutMs) {
|
|
459
|
+
const generation = this.contextGeneration;
|
|
460
|
+
let transferTimeout;
|
|
461
|
+
const transferExpired = new Promise((_resolve, reject) => {
|
|
462
|
+
transferTimeout = globalThis.setTimeout(() => {
|
|
463
|
+
const error = new Error(`Context transfer timed out after ${timeoutMs}ms`);
|
|
464
|
+
this.startAutoRejoin(error);
|
|
465
|
+
reject(error);
|
|
466
|
+
}, timeoutMs);
|
|
467
|
+
});
|
|
468
|
+
const transfer = await Promise.race([
|
|
469
|
+
"image" in update ? this.uploadImageContext(update) : this.uploadTextContext(update),
|
|
470
|
+
transferExpired,
|
|
471
|
+
]).finally(() => globalThis.clearTimeout(transferTimeout));
|
|
472
|
+
if (generation !== this.contextGeneration)
|
|
473
|
+
throw new Error("Context transfer interrupted by recovery");
|
|
414
474
|
const { payload } = transfer;
|
|
415
475
|
if (!isContextUpdatePayload(payload)) {
|
|
416
476
|
throw new TypeError("Invalid context update payload");
|
|
@@ -499,6 +559,8 @@ export class RealtimeSession {
|
|
|
499
559
|
}
|
|
500
560
|
async disconnect() {
|
|
501
561
|
this.cancelAutoRejoin();
|
|
562
|
+
this.contextGeneration += 1;
|
|
563
|
+
this.replacementContext.clear(new Error("Session disconnected"));
|
|
502
564
|
if (this.stateValue === "disconnected")
|
|
503
565
|
return;
|
|
504
566
|
this.rejectPendingCommands(new Error("Session disconnected before command completion"));
|
|
@@ -559,6 +621,11 @@ export class RealtimeSession {
|
|
|
559
621
|
this.notifyListeners(this.stateListeners, state);
|
|
560
622
|
}
|
|
561
623
|
bindRoomEvents() {
|
|
624
|
+
this.room.on(RoomEvent.ParticipantDisconnected, (participant) => {
|
|
625
|
+
if (participant.isAgent && !this.disconnectMode) {
|
|
626
|
+
this.startAutoRejoin(new Error("Agent disconnected from the room"));
|
|
627
|
+
}
|
|
628
|
+
});
|
|
562
629
|
this.room.on(RoomEvent.SignalReconnecting, () => this.handleLiveKitReconnecting());
|
|
563
630
|
this.room.on(RoomEvent.Reconnecting, () => this.handleLiveKitReconnecting());
|
|
564
631
|
this.room.on(RoomEvent.Reconnected, () => {
|
|
@@ -648,6 +715,8 @@ export class RealtimeSession {
|
|
|
648
715
|
});
|
|
649
716
|
}
|
|
650
717
|
handleLiveKitReconnecting() {
|
|
718
|
+
if (this.sessionEnded || this.disconnectMode === "intentional")
|
|
719
|
+
return;
|
|
651
720
|
this.agentReady = false;
|
|
652
721
|
// Once full rejoin owns recovery, late LiveKit reconnect notifications
|
|
653
722
|
// from the old transport must not move the wrapper back to reconnecting.
|
|
@@ -658,6 +727,8 @@ export class RealtimeSession {
|
|
|
658
727
|
this.setState("resuming");
|
|
659
728
|
return;
|
|
660
729
|
}
|
|
730
|
+
this.contextGeneration += 1;
|
|
731
|
+
this.replacementContext.pause();
|
|
661
732
|
this.reconnectStartedAt ??= Date.now();
|
|
662
733
|
this.rejectPendingCommands(new Error("Connection interrupted before command completion"), true);
|
|
663
734
|
if (this.activeRecovery === null) {
|
|
@@ -666,6 +737,9 @@ export class RealtimeSession {
|
|
|
666
737
|
this.setState("reconnecting");
|
|
667
738
|
}
|
|
668
739
|
async handleLiveKitReconnected() {
|
|
740
|
+
if (this.sessionEnded || this.disconnectMode || this.autoRejoinPromise)
|
|
741
|
+
return;
|
|
742
|
+
const generation = this.contextGeneration;
|
|
669
743
|
const recoveredAt = Date.now();
|
|
670
744
|
if (this.reconnectStartedAt !== null) {
|
|
671
745
|
this.pendingReconnect = {
|
|
@@ -683,8 +757,21 @@ export class RealtimeSession {
|
|
|
683
757
|
this.setState(this.hasConnectedValue ? "resuming" : "connected_not_ready");
|
|
684
758
|
try {
|
|
685
759
|
await this.sendHello();
|
|
760
|
+
const deadline = Date.now() + (this.connectDefaults.readyTimeoutMs ?? 15_000);
|
|
761
|
+
await this.waitForAgentReady(Math.max(deadline - Date.now(), 0));
|
|
762
|
+
if (this.connectDefaults.waitForRemoteAudio !== false)
|
|
763
|
+
await this.waitForRemoteAudioTrack(deadline);
|
|
764
|
+
if (this.sessionEnded || generation !== this.contextGeneration)
|
|
765
|
+
return;
|
|
766
|
+
await this.replacementContext.resume(true);
|
|
767
|
+
if (this.sessionEnded || generation !== this.contextGeneration)
|
|
768
|
+
return;
|
|
769
|
+
this.setState("connected");
|
|
770
|
+
this.completeRecovery();
|
|
686
771
|
}
|
|
687
772
|
catch (error) {
|
|
773
|
+
if (this.sessionEnded || generation !== this.contextGeneration)
|
|
774
|
+
return;
|
|
688
775
|
const normalizedError = toError(error);
|
|
689
776
|
if (this.shouldAutoRejoin()) {
|
|
690
777
|
this.startAutoRejoin(normalizedError);
|
|
@@ -697,8 +784,9 @@ export class RealtimeSession {
|
|
|
697
784
|
}
|
|
698
785
|
handleLiveKitDisconnected(reason) {
|
|
699
786
|
this.agentReady = false;
|
|
700
|
-
this.
|
|
701
|
-
|
|
787
|
+
if (this.disconnectMode !== "rejoin") {
|
|
788
|
+
this.pendingReconnect = null;
|
|
789
|
+
}
|
|
702
790
|
// Drop any remaining remote tracks so a stale, ended track cannot
|
|
703
791
|
// satisfy the next connect()'s wait for agent audio.
|
|
704
792
|
this.outputMediaStream?.getTracks().forEach((track) => {
|
|
@@ -775,15 +863,33 @@ export class RealtimeSession {
|
|
|
775
863
|
return (this.autoRejoinOptions !== null
|
|
776
864
|
&& this.hasConnectedValue
|
|
777
865
|
&& !this.sessionEnded
|
|
866
|
+
&& !["disconnected", "failed"].includes(this.stateValue)
|
|
778
867
|
&& !isTerminalDisconnectReason(reason));
|
|
779
868
|
}
|
|
780
869
|
startAutoRejoin(initialError) {
|
|
781
870
|
if (this.autoRejoinPromise || !this.shouldAutoRejoin())
|
|
782
871
|
return;
|
|
872
|
+
this.agentReady = false;
|
|
873
|
+
this.contextGeneration += 1;
|
|
874
|
+
this.replacementContext.pause();
|
|
875
|
+
this.rejectPendingCommands(initialError);
|
|
876
|
+
this.reconnectStartedAt ??= Date.now();
|
|
783
877
|
const controller = new AbortController();
|
|
784
878
|
this.autoRejoinController = controller;
|
|
879
|
+
const timeout = globalThis.setTimeout(() => {
|
|
880
|
+
if (controller.signal.aborted)
|
|
881
|
+
return;
|
|
882
|
+
const error = new Error("Session recovery timed out");
|
|
883
|
+
controller.abort(error);
|
|
884
|
+
this.contextGeneration += 1;
|
|
885
|
+
this.rejectPendingCommands(error);
|
|
886
|
+
this.replacementContext.clear(error);
|
|
887
|
+
this.failRecovery(error);
|
|
888
|
+
this.setState("failed");
|
|
889
|
+
}, this.autoRejoinOptions.timeoutMs);
|
|
785
890
|
const promise = this.runAutoRejoin(initialError, controller.signal)
|
|
786
891
|
.finally(() => {
|
|
892
|
+
globalThis.clearTimeout(timeout);
|
|
787
893
|
if (this.autoRejoinController === controller) {
|
|
788
894
|
this.autoRejoinController = null;
|
|
789
895
|
this.autoRejoinPromise = null;
|
|
@@ -813,6 +919,7 @@ export class RealtimeSession {
|
|
|
813
919
|
this.beginRecovery("rejoin", attempt);
|
|
814
920
|
await this.performRejoin(this.apiBase, signal);
|
|
815
921
|
throwIfAborted(signal);
|
|
922
|
+
this.reconnectStartedAt = null;
|
|
816
923
|
this.completeRecovery();
|
|
817
924
|
return;
|
|
818
925
|
}
|
|
@@ -825,6 +932,7 @@ export class RealtimeSession {
|
|
|
825
932
|
}
|
|
826
933
|
}
|
|
827
934
|
this.failRecovery(lastError);
|
|
935
|
+
this.replacementContext.clear(lastError);
|
|
828
936
|
this.setState("failed");
|
|
829
937
|
}
|
|
830
938
|
cancelAutoRejoin() {
|
|
@@ -867,12 +975,23 @@ export class RealtimeSession {
|
|
|
867
975
|
}
|
|
868
976
|
}
|
|
869
977
|
async fetchRoomToken(apiBase, signal) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
978
|
+
const controller = new AbortController();
|
|
979
|
+
const cancel = () => controller.abort(signal?.reason);
|
|
980
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
981
|
+
const timeout = globalThis.setTimeout(() => controller.abort(), 10_000);
|
|
982
|
+
try {
|
|
983
|
+
throwIfAborted(signal);
|
|
984
|
+
return await this.fetcher(`${apiBase}/sessions/${this.id}/room-tokens`, {
|
|
985
|
+
method: "POST",
|
|
986
|
+
headers: { Authorization: `Bearer ${this.accessToken}` },
|
|
987
|
+
credentials: this.lifecycleCredentials,
|
|
988
|
+
signal: controller.signal,
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
finally {
|
|
992
|
+
globalThis.clearTimeout(timeout);
|
|
993
|
+
signal?.removeEventListener("abort", cancel);
|
|
994
|
+
}
|
|
876
995
|
}
|
|
877
996
|
async refreshCredentials() {
|
|
878
997
|
if (!this.refreshCredentialsCallback)
|
|
@@ -886,11 +1005,16 @@ export class RealtimeSession {
|
|
|
886
1005
|
this.credentials = refreshed.connection;
|
|
887
1006
|
}
|
|
888
1007
|
observeConvenienceEvents(event) {
|
|
1008
|
+
if (event.type === "session.ending" || event.type === "session.ended") {
|
|
1009
|
+
this.contextGeneration += 1;
|
|
1010
|
+
this.rejectPendingCommands(new Error("Session ended"));
|
|
1011
|
+
}
|
|
889
1012
|
if (event.type === "session.ending") {
|
|
890
1013
|
// The server announced an intentional hang-up before tearing down the
|
|
891
1014
|
// room, so the coming disconnect must not fail recovery or auto-rejoin.
|
|
892
1015
|
this.sessionEnded = true;
|
|
893
1016
|
this.cancelAutoRejoin();
|
|
1017
|
+
this.replacementContext.clear(new Error("Session ended"));
|
|
894
1018
|
this.pendingEndEvent = event;
|
|
895
1019
|
}
|
|
896
1020
|
if (event.type === "session.ended") {
|
|
@@ -900,6 +1024,7 @@ export class RealtimeSession {
|
|
|
900
1024
|
|| this.stateValue === "reconnecting"
|
|
901
1025
|
|| this.stateValue === "resuming");
|
|
902
1026
|
this.sessionEnded = true;
|
|
1027
|
+
this.replacementContext.clear(new Error("Session ended"));
|
|
903
1028
|
if (this.activeRecovery !== null) {
|
|
904
1029
|
this.failRecovery(new Error("Session ended during recovery"));
|
|
905
1030
|
}
|
|
@@ -910,6 +1035,9 @@ export class RealtimeSession {
|
|
|
910
1035
|
}
|
|
911
1036
|
if (event.type.endsWith(".error"))
|
|
912
1037
|
this.notifyListeners(this.errorListeners, event);
|
|
1038
|
+
const message = this.transcriptStore.accept(event);
|
|
1039
|
+
if (message)
|
|
1040
|
+
this.notifyListeners(this.transcriptListeners, message);
|
|
913
1041
|
const transcript = transcriptEvent(event);
|
|
914
1042
|
if (!transcript)
|
|
915
1043
|
return;
|
|
@@ -937,7 +1065,7 @@ export class RealtimeSession {
|
|
|
937
1065
|
...(reconnect ? { reconnect } : {}),
|
|
938
1066
|
});
|
|
939
1067
|
this.lastHelloMessageId = message.message_id;
|
|
940
|
-
await this.sendTrackedCommand(message,
|
|
1068
|
+
await this.sendTrackedCommand(message, CLIENT_HELLO_TIMEOUT_MS);
|
|
941
1069
|
if (this.pendingReconnect === reconnect)
|
|
942
1070
|
this.pendingReconnect = null;
|
|
943
1071
|
}
|
|
@@ -948,7 +1076,10 @@ export class RealtimeSession {
|
|
|
948
1076
|
if (pending)
|
|
949
1077
|
globalThis.clearInterval(pending.retry);
|
|
950
1078
|
this.pendingCommands.delete(message.message_id);
|
|
951
|
-
|
|
1079
|
+
const error = new Error(`Command ${message.type} timed out after ${timeoutMs}ms`);
|
|
1080
|
+
reject(error);
|
|
1081
|
+
if (message.type === "context.update")
|
|
1082
|
+
this.startAutoRejoin(error);
|
|
952
1083
|
}, timeoutMs);
|
|
953
1084
|
const retry = globalThis.setInterval(() => {
|
|
954
1085
|
void this.publishCommand(message).catch(() => {
|
|
@@ -1035,6 +1166,9 @@ export class RealtimeSession {
|
|
|
1035
1166
|
});
|
|
1036
1167
|
}
|
|
1037
1168
|
observeReadiness(event) {
|
|
1169
|
+
// Replayed readiness describes an old worker, not the current transport.
|
|
1170
|
+
if (event.stream_id === "durable-replay")
|
|
1171
|
+
return;
|
|
1038
1172
|
const payload = event.payload;
|
|
1039
1173
|
const snapshotReady = event.type === "agent.snapshot"
|
|
1040
1174
|
&& payload.status === "ready"
|
|
@@ -1042,14 +1176,15 @@ export class RealtimeSession {
|
|
|
1042
1176
|
&& payload.ack_message_id === this.lastHelloMessageId;
|
|
1043
1177
|
if (event.type !== "agent.ready" && !snapshotReady)
|
|
1044
1178
|
return;
|
|
1179
|
+
if (this.agentStreamId && this.agentStreamId !== event.stream_id && !this.activeRecovery) {
|
|
1180
|
+
this.startAutoRejoin(new Error("Agent worker was replaced"));
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
this.agentStreamId = event.stream_id;
|
|
1045
1184
|
const wasReady = this.agentReady;
|
|
1046
1185
|
this.agentReady = true;
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
this.setState("connected");
|
|
1050
|
-
if (this.activeRecovery?.strategy === "livekit")
|
|
1051
|
-
this.completeRecovery();
|
|
1052
|
-
}
|
|
1186
|
+
// connect/reconnect owns the transition after hello, audio and context
|
|
1187
|
+
// restoration all finish. Readiness alone is not successful recovery.
|
|
1053
1188
|
this.readyResolve?.();
|
|
1054
1189
|
if (!wasReady)
|
|
1055
1190
|
this.notifyListeners(this.readyListeners, event);
|
|
@@ -1152,10 +1287,14 @@ function resolveAutoRejoinOptions(value) {
|
|
|
1152
1287
|
return null;
|
|
1153
1288
|
const options = value === true ? {} : value;
|
|
1154
1289
|
const resolved = {
|
|
1155
|
-
maxAttempts: options.maxAttempts ??
|
|
1290
|
+
maxAttempts: options.maxAttempts ?? Number.MAX_SAFE_INTEGER,
|
|
1156
1291
|
baseDelayMs: options.baseDelayMs ?? 750,
|
|
1157
1292
|
maxDelayMs: options.maxDelayMs ?? 5_000,
|
|
1293
|
+
timeoutMs: options.timeoutMs ?? 180_000,
|
|
1158
1294
|
};
|
|
1295
|
+
if (!Number.isFinite(resolved.timeoutMs) || resolved.timeoutMs <= 0) {
|
|
1296
|
+
throw new TypeError("autoRejoin.timeoutMs must be a positive finite number");
|
|
1297
|
+
}
|
|
1159
1298
|
if (!Number.isInteger(resolved.maxAttempts) || resolved.maxAttempts < 1) {
|
|
1160
1299
|
throw new TypeError("autoRejoin.maxAttempts must be a positive integer");
|
|
1161
1300
|
}
|