@d-id/client-sdk 2.0.5 → 2.0.6

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.
@@ -0,0 +1,521 @@
1
+ import { c as Je, C as Q, S as g, a as Qe, b as We, A as m, d as qe, l as fe, e as Ge, t as He, f as A, g as N, h as Xe, i as Ze, j as R, n as Ye } from "./index-BLArKcFJ.js";
2
+ function en() {
3
+ try {
4
+ return Intl.DateTimeFormat().resolvedOptions().timeZone ?? "";
5
+ } catch {
6
+ return "";
7
+ }
8
+ }
9
+ function nn() {
10
+ if (typeof navigator > "u")
11
+ return "";
12
+ const l = navigator.userAgent ?? "", C = (navigator.platform ?? "").toLowerCase();
13
+ let u = "Unknown";
14
+ /android/i.test(l) ? u = "Android" : /iphone|ipad|ipod/i.test(l) ? u = "iOS" : C.includes("win") ? u = "Windows" : C.includes("mac") ? u = "Mac OS X" : C.includes("linux") && (u = "Linux");
15
+ const i = u === "Android" || u === "iOS" || /Mobi/i.test(l);
16
+ return `${u}, ${i ? "Mobile" : "Desktop"}`;
17
+ }
18
+ function tn() {
19
+ const l = {}, C = en();
20
+ C && (l.timezone = C);
21
+ const u = nn();
22
+ return u && (l.device = u), l;
23
+ }
24
+ function on(l, C, u, i) {
25
+ const k = Je(l, `${C}/v2/agents/${u}`, i);
26
+ return {
27
+ async createStream(f) {
28
+ return k.post("/sessions", f);
29
+ }
30
+ };
31
+ }
32
+ const rn = {
33
+ [g.ChatAnswer]: Q.Answer,
34
+ [g.ChatPartial]: Q.Partial
35
+ }, he = 2e4, an = [];
36
+ async function cn() {
37
+ try {
38
+ return await import("./index-BLArKcFJ.js").then((l) => l.z);
39
+ } catch {
40
+ throw new Error(
41
+ "LiveKit client is required for this streaming manager. Please install it using: npm install livekit-client"
42
+ );
43
+ }
44
+ }
45
+ const sn = {
46
+ excellent: N.Strong,
47
+ good: N.Strong,
48
+ poor: N.Weak,
49
+ lost: N.Unknown,
50
+ unknown: N.Unknown
51
+ }, x = (l = "Stream Error") => new Ge(l);
52
+ function me(l, C, u) {
53
+ var i, k;
54
+ throw C("Failed to connect to LiveKit room:", l), (i = u.onConnectionStateChange) == null || i.call(u, A.Fail, "internal:init-error"), (k = u.onError) == null || k.call(u, l, { sessionId: "" }), l;
55
+ }
56
+ async function dn(l, C, u) {
57
+ var ue;
58
+ const i = Qe(u.debug || !1, "LiveKitStreamingManager"), { Room: k, RoomEvent: f, ConnectionState: I, Track: Y } = await cn(), { callbacks: n, auth: Ce, baseURL: Se, analytics: ee } = u;
59
+ let a = null, E = !1;
60
+ const ne = We.Fluent;
61
+ let P = null;
62
+ const b = { isPublishing: !1, publication: null }, W = { isPublishing: !1, publication: null };
63
+ let h = null, S = null, U = null, D = !1;
64
+ a = new k({
65
+ adaptiveStream: !1,
66
+ // Must be false to use mediaStreamTrack directly
67
+ dynacast: !0
68
+ });
69
+ let L = null, M = m.Idle, q = !0;
70
+ const v = /* @__PURE__ */ new Map();
71
+ let V = null;
72
+ const Te = on(Ce, Se || qe, l, n.onError);
73
+ let T, _, $, te = !0;
74
+ try {
75
+ const e = await Te.createStream({
76
+ transport: C.transport,
77
+ chat_persist: C.chat_persist ?? !0,
78
+ verbose: u.verbose ?? !1
79
+ }), { id: t, session_token: o, session_url: r, interrupt_enabled: c } = e;
80
+ (ue = n.onStreamCreated) == null || ue.call(n, { session_id: t, stream_id: t, agent_id: l }), T = t, _ = o, $ = r, te = c ?? !0, await a.prepareConnection($, _);
81
+ } catch (e) {
82
+ me(e, i, n);
83
+ }
84
+ if (!$ || !_ || !T)
85
+ return Promise.reject(new Error("Failed to initialize LiveKit stream"));
86
+ a.on(f.ConnectionStateChanged, we).on(f.ConnectionQualityChanged, Ae).on(f.ParticipantConnected, Ee).on(f.ParticipantDisconnected, Le).on(f.TrackSubscribed, Pe).on(f.TrackUnsubscribed, be).on(f.DataReceived, xe).on(f.MediaDevicesError, De).on(f.TranscriptionReceived, ye).on(f.EncryptionError, Ve).on(f.TrackSubscriptionFailed, Fe);
87
+ function ye(e, t) {
88
+ t != null && t.isLocal && fe.update();
89
+ }
90
+ async function ve() {
91
+ const e = tn();
92
+ if (!(!a || Object.keys(e).length === 0))
93
+ try {
94
+ await a.localParticipant.setAttributes(e);
95
+ } catch (t) {
96
+ i("Failed to set user context attributes", t);
97
+ }
98
+ }
99
+ try {
100
+ await a.connect($, _), i("LiveKit room joined successfully"), ve(), L = setTimeout(() => {
101
+ var t;
102
+ i(
103
+ `Track subscription timeout - no track subscribed within ${he / 1e3} seconds after connect`
104
+ ), L = null;
105
+ const e = x("Track subscription timeout");
106
+ ee.track("connectivity-error", {
107
+ error: He(e),
108
+ sessionId: T
109
+ }), (t = n.onError) == null || t.call(n, e, { sessionId: T }), Z("internal:track-subscription-timeout");
110
+ }, he);
111
+ } catch (e) {
112
+ me(e, i, n);
113
+ }
114
+ ee.enrich({
115
+ "stream-type": ne
116
+ });
117
+ function we(e) {
118
+ var t, o, r, c;
119
+ switch (i("Connection state changed:", e), e) {
120
+ case I.Connecting:
121
+ i("CALLBACK: onConnectionStateChange(Connecting)"), (t = n.onConnectionStateChange) == null || t.call(n, A.Connecting, "livekit:connecting");
122
+ break;
123
+ case I.Connected:
124
+ i("LiveKit room connected successfully"), E = !0;
125
+ break;
126
+ case I.Disconnected:
127
+ i("LiveKit room disconnected"), E = !1, D = !1, b.publication = null, W.publication = null, (o = n.onConnectionStateChange) == null || o.call(n, A.Disconnected, "livekit:disconnected");
128
+ break;
129
+ case I.Reconnecting:
130
+ i("LiveKit room reconnecting..."), (r = n.onConnectionStateChange) == null || r.call(n, A.Connecting, "livekit:reconnecting");
131
+ break;
132
+ case I.SignalReconnecting:
133
+ i("LiveKit room signal reconnecting..."), (c = n.onConnectionStateChange) == null || c.call(n, A.Connecting, "livekit:signal-reconnecting");
134
+ break;
135
+ }
136
+ }
137
+ function Ae(e, t) {
138
+ var o;
139
+ i("Connection quality:", e), t != null && t.isLocal && ((o = n.onConnectivityStateChange) == null || o.call(n, sn[e]));
140
+ }
141
+ function Ee(e) {
142
+ i("Participant connected:", e.identity);
143
+ }
144
+ function Le(e) {
145
+ i("Participant disconnected:", e.identity), Z("livekit:participant-disconnected");
146
+ }
147
+ function Re() {
148
+ var e;
149
+ U !== R.Start && (i("CALLBACK: onVideoStateChange(Start)"), U = R.Start, (e = n.onVideoStateChange) == null || e.call(n, R.Start));
150
+ }
151
+ function ie(e) {
152
+ var t;
153
+ U !== R.Stop && (i("CALLBACK: onVideoStateChange(Stop)"), U = R.Stop, (t = n.onVideoStateChange) == null || t.call(n, R.Stop, e));
154
+ }
155
+ function Pe(e, t, o) {
156
+ var c, d, s;
157
+ i(`Track subscribed: ${e.kind} from ${o.identity}`);
158
+ const r = e.mediaStreamTrack;
159
+ if (!r) {
160
+ i(`No mediaStreamTrack available for ${e.kind}`);
161
+ return;
162
+ }
163
+ P ? (P.addTrack(r), i(`Added ${e.kind} track to shared MediaStream`)) : (P = new MediaStream([r]), i(`Created shared MediaStream with ${e.kind} track`)), e.kind === "audio" && (S = Ze(
164
+ () => e.getRTCStatsReport(),
165
+ ({ sttLatency: p, serviceLatency: y }) => {
166
+ var de, le, ge;
167
+ const F = fe.get(!0);
168
+ let O = 0;
169
+ if (p) {
170
+ const pe = ((le = (de = h == null ? void 0 : h.getReport()) == null ? void 0 : de.webRTCStats) == null ? void 0 : le.avgRtt) ?? 0;
171
+ O = pe > 0 ? Math.round(pe * 1e3) : 0;
172
+ }
173
+ const K = F > 0 ? F + (p ?? 0) + O : void 0, w = K !== void 0 && y !== void 0 ? K - y : void 0;
174
+ (ge = n.onFirstAudioDetected) == null || ge.call(n, { latency: K, networkLatency: w });
175
+ }
176
+ )), e.kind === "video" && ((c = n.onStreamReady) == null || c.call(n), i("CALLBACK: onSrcObjectReady"), (d = n.onSrcObjectReady) == null || d.call(n, P), D || (D = !0, i("CALLBACK: onConnectionStateChange(Connected)"), (s = n.onConnectionStateChange) == null || s.call(n, A.Connected, "livekit:track-subscribed")), h = Xe(
177
+ () => e.getRTCStatsReport(),
178
+ () => E,
179
+ Ye,
180
+ (p, y) => {
181
+ i(`Video state change: ${p}`), p === R.Start ? (L && (clearTimeout(L), L = null, i("Track subscription timeout cleared")), Re()) : p === R.Stop && ie(y);
182
+ }
183
+ ), h.start());
184
+ }
185
+ function be(e, t, o) {
186
+ i(`Track unsubscribed: ${e.kind} from ${o.identity}`), e.kind === "audio" && (S == null || S.destroy(), S = null), e.kind === "video" && (ie(h == null ? void 0 : h.getReport()), h == null || h.stop(), h = null);
187
+ }
188
+ function oe(e, t) {
189
+ var r;
190
+ const o = rn[e];
191
+ o && ((r = n.onMessage) == null || r.call(n, o, { event: o, ...t }));
192
+ }
193
+ function G(e, t) {
194
+ var o, r, c, d;
195
+ if (e === g.ToolCallStarted) {
196
+ const s = t;
197
+ v.set(s.call_id, {
198
+ call: {
199
+ callId: s.call_id,
200
+ name: s.name,
201
+ executionMode: s.execution_mode === "async" ? "async" : "blocking"
202
+ },
203
+ interruptible: s.interruptible === !0,
204
+ turnId: s.turn_id ?? V
205
+ }), j(), z(), M = m.ToolActive, (o = n.onAgentActivityStateChange) == null || o.call(n, m.ToolActive), (r = n.onToolEvent) == null || r.call(n, g.ToolCallStarted, s);
206
+ return;
207
+ }
208
+ if (e === g.ToolCallDone) {
209
+ const s = t;
210
+ re(s.call_id), (c = n.onToolEvent) == null || c.call(n, g.ToolCallDone, s);
211
+ return;
212
+ }
213
+ if (e === g.ToolCallError) {
214
+ const s = t;
215
+ re(s.call_id), (d = n.onToolEvent) == null || d.call(n, g.ToolCallError, s);
216
+ }
217
+ }
218
+ function re(e) {
219
+ v.delete(e) && (j(), z());
220
+ }
221
+ function Me(e) {
222
+ let t = !1;
223
+ for (const [o, r] of v)
224
+ r.call.executionMode === "blocking" && (e !== null && r.turnId !== null && r.turnId !== e || (v.delete(o), t = !0));
225
+ t && (j(), z());
226
+ }
227
+ function j() {
228
+ var t;
229
+ const e = ![...v.values()].some(({ call: o }) => o.executionMode === "blocking");
230
+ e !== q && (q = e, (t = n.onInterruptibleChange) == null || t.call(n, e));
231
+ }
232
+ function z() {
233
+ var e;
234
+ (e = n.onRunningToolCallsChange) == null || e.call(
235
+ n,
236
+ v.size === 0 ? an : [...v.values()].map(({ call: t }) => t)
237
+ );
238
+ }
239
+ function ke(e, t) {
240
+ var o, r, c;
241
+ if (e === g.StreamVideoCreated) {
242
+ M = m.Talking, (o = n.onAgentActivityStateChange) == null || o.call(n, m.Talking), S == null || S.arm({
243
+ sttLatency: (r = t == null ? void 0 : t.stt) == null ? void 0 : r.latency,
244
+ serviceLatency: t == null ? void 0 : t.serviceLatency
245
+ });
246
+ return;
247
+ }
248
+ if (v.size > 0) {
249
+ M !== m.ToolActive && (M = m.ToolActive, (c = n.onAgentActivityStateChange) == null || c.call(n, m.ToolActive));
250
+ return;
251
+ }
252
+ }
253
+ function B(e, t) {
254
+ var d, s, p, y;
255
+ const o = ((s = (d = h == null ? void 0 : h.getReport()) == null ? void 0 : d.webRTCStats) == null ? void 0 : s.avgRtt) ?? 0, r = o > 0 ? Math.round(o / 2 * 1e3) : 0, c = { ...t, downstreamNetworkLatency: r };
256
+ u.debug && ((p = t == null ? void 0 : t.metadata) != null && p.sentiment) && (c.sentiment = {
257
+ id: t.metadata.sentiment.id,
258
+ name: t.metadata.sentiment.sentiment
259
+ }), (y = n.onMessage) == null || y.call(n, e, c), ke(e, t);
260
+ }
261
+ function Ie(e, t) {
262
+ var o;
263
+ (o = n.onMessage) == null || o.call(n, Q.Transcribe, { event: Q.Transcribe, ...t }), queueMicrotask(() => {
264
+ var r;
265
+ (r = n.onAgentActivityStateChange) == null || r.call(n, m.Loading);
266
+ });
267
+ }
268
+ function _e(e, t) {
269
+ var o;
270
+ V = (t == null ? void 0 : t.turn_id) ?? null, M = m.Loading, (o = n.onAgentActivityStateChange) == null || o.call(n, m.Loading);
271
+ }
272
+ function $e(e, t) {
273
+ var r;
274
+ const o = (t == null ? void 0 : t.turn_id) ?? null;
275
+ V !== null && o !== null && o < V || (Me(o), M = m.Idle, (r = n.onAgentActivityStateChange) == null || r.call(n, m.Idle));
276
+ }
277
+ const Ke = {
278
+ [g.ChatAnswer]: oe,
279
+ [g.ChatPartial]: oe,
280
+ [g.ToolCallStarted]: G,
281
+ [g.ToolCallDone]: G,
282
+ [g.ToolCallError]: G,
283
+ [g.StreamVideoCreated]: B,
284
+ [g.StreamVideoDone]: B,
285
+ [g.StreamVideoError]: B,
286
+ [g.StreamVideoRejected]: B,
287
+ [g.ChatAudioTranscribed]: Ie,
288
+ [g.TurnStarted]: _e,
289
+ [g.TurnEnded]: $e
290
+ };
291
+ function xe(e, t, o, r) {
292
+ const c = new TextDecoder().decode(e);
293
+ try {
294
+ const d = JSON.parse(c), s = r || d.subject;
295
+ if (i("Data received:", { subject: s, data: d }), !s) return;
296
+ const p = Ke[s];
297
+ p == null || p(s, d);
298
+ } catch (d) {
299
+ i("Failed to parse data channel message:", d);
300
+ }
301
+ }
302
+ function De(e) {
303
+ var t;
304
+ i("Media devices error:", e), (t = n.onError) == null || t.call(n, x(), { sessionId: T });
305
+ }
306
+ function Ve(e) {
307
+ var t;
308
+ i("Encryption error:", e), (t = n.onError) == null || t.call(n, x(), { sessionId: T });
309
+ }
310
+ function Fe(e, t, o) {
311
+ i("Track subscription failed:", { trackSid: e, participant: t, reason: o });
312
+ }
313
+ function Oe(e, t, o) {
314
+ for (const [r, c] of o)
315
+ if (c.source === t && c.track) {
316
+ const d = c.track.mediaStreamTrack;
317
+ if (d === e || (d == null ? void 0 : d.id) === e.id)
318
+ return c;
319
+ }
320
+ return null;
321
+ }
322
+ async function ae(e, t, o, r, c, d) {
323
+ var F, O, K;
324
+ if (!E || !a)
325
+ throw i(`Room is not connected, cannot publish ${r} stream`), new Error("Room is not connected");
326
+ if (e.isPublishing) {
327
+ i(`${r} publish already in progress, skipping`);
328
+ return;
329
+ }
330
+ const s = o(t);
331
+ if (s.length === 0)
332
+ throw new Error(`No ${r} track found in the provided MediaStream`);
333
+ const p = s[0], y = Oe(p, r, c());
334
+ if (y) {
335
+ i(`${r} track is already published, skipping`, {
336
+ trackId: p.id,
337
+ publishedTrackId: (O = (F = y.track) == null ? void 0 : F.mediaStreamTrack) == null ? void 0 : O.id
338
+ }), e.publication = y;
339
+ return;
340
+ }
341
+ if ((K = e.publication) != null && K.track) {
342
+ const w = e.publication.track.mediaStreamTrack;
343
+ w !== p && (w == null ? void 0 : w.id) !== p.id && (i(`Unpublishing existing ${r} track before publishing new one`), await d());
344
+ }
345
+ i(`Publishing ${r} track from provided MediaStream`, { trackId: p.id }), e.isPublishing = !0;
346
+ try {
347
+ e.publication = await a.localParticipant.publishTrack(p, { source: r }), i(`${r} track published successfully`, { trackSid: e.publication.trackSid });
348
+ } catch (w) {
349
+ throw i(`Failed to publish ${r} track:`, w), w;
350
+ } finally {
351
+ e.isPublishing = !1;
352
+ }
353
+ }
354
+ async function ce(e, t) {
355
+ if (!(!e.publication || !e.publication.track))
356
+ try {
357
+ a && (await a.localParticipant.unpublishTrack(e.publication.track, !1), i(`${t} track unpublished`));
358
+ } catch (o) {
359
+ i(`Error unpublishing ${t} track:`, o);
360
+ } finally {
361
+ e.publication = null;
362
+ }
363
+ }
364
+ async function Ne(e) {
365
+ return ae(
366
+ b,
367
+ e,
368
+ (t) => t.getAudioTracks(),
369
+ Y.Source.Microphone,
370
+ () => a.localParticipant.audioTrackPublications,
371
+ H
372
+ );
373
+ }
374
+ async function H() {
375
+ return ce(b, "Microphone");
376
+ }
377
+ async function Ue(e) {
378
+ if (!E || !a)
379
+ throw i("Cannot replace microphone track: room is not connected"), new Error("Room is not connected");
380
+ if (e.kind !== "audio")
381
+ throw i("Cannot replace microphone track: not an audio track", { kind: e.kind }), new Error("Microphone track must be an audio track");
382
+ if (b.isPublishing)
383
+ throw i("Cannot replace microphone track: publish in progress"), new Error("Microphone publish in progress");
384
+ const t = b.publication;
385
+ if (!t || !t.track)
386
+ throw i("Cannot replace microphone track: no publication to replace"), new Error("No microphone publication to replace");
387
+ try {
388
+ b.isPublishing = !0, await t.track.replaceTrack(e), i("Microphone track replaced", { trackId: e.id, trackSid: t.trackSid });
389
+ } finally {
390
+ b.isPublishing = !1;
391
+ }
392
+ }
393
+ async function je(e) {
394
+ return ae(
395
+ W,
396
+ e,
397
+ (t) => t.getVideoTracks(),
398
+ Y.Source.Camera,
399
+ () => a.localParticipant.videoTrackPublications,
400
+ X
401
+ );
402
+ }
403
+ async function X() {
404
+ return ce(W, "Camera");
405
+ }
406
+ function ze() {
407
+ P && (P.getTracks().forEach((e) => e.stop()), P = null);
408
+ }
409
+ async function J(e, t) {
410
+ var o, r;
411
+ if (!E || !a) {
412
+ i("Room is not connected for sending messages"), (o = n.onError) == null || o.call(n, x(), {
413
+ sessionId: T
414
+ });
415
+ return;
416
+ }
417
+ try {
418
+ await a.localParticipant.sendText(e, { topic: t }), i("Message sent successfully:", e);
419
+ } catch (c) {
420
+ i("Failed to send message:", c), (r = n.onError) == null || r.call(n, x(), { sessionId: T });
421
+ }
422
+ }
423
+ async function se(e) {
424
+ var t;
425
+ try {
426
+ const r = JSON.parse(e).topic;
427
+ return J("", r);
428
+ } catch (o) {
429
+ i("Failed to send data channel message:", o), (t = n.onError) == null || t.call(n, x(), { sessionId: T });
430
+ }
431
+ }
432
+ function Be(e) {
433
+ return J(
434
+ e,
435
+ "lk.chat"
436
+ /* Chat */
437
+ );
438
+ }
439
+ async function Z(e) {
440
+ var t, o;
441
+ L && (clearTimeout(L), L = null), S == null || S.destroy(), S = null, a && ((t = n.onConnectionStateChange) == null || t.call(n, A.Disconnecting, e), await Promise.all([H(), X()]), await a.disconnect()), ze(), E = !1, D = !1, v.size > 0 && (v.clear(), j(), z()), V = null, (o = n.onAgentActivityStateChange) == null || o.call(n, m.Idle), M = m.Idle;
442
+ }
443
+ return {
444
+ speak(e) {
445
+ const t = typeof e == "string" ? e : JSON.stringify(e);
446
+ return J(
447
+ t,
448
+ "did.speak"
449
+ /* Speak */
450
+ );
451
+ },
452
+ disconnect: () => Z("user:disconnect"),
453
+ async reconnect() {
454
+ var e, t;
455
+ if ((a == null ? void 0 : a.state) === I.Connected) {
456
+ i("Room is already connected");
457
+ return;
458
+ }
459
+ if (!a || !$ || !_)
460
+ throw i("Cannot reconnect: missing room, URL or token"), new Error("Cannot reconnect: session not available");
461
+ i("Reconnecting to LiveKit room, state:", a.state), D = !1, (e = n.onConnectionStateChange) == null || e.call(n, A.Connecting, "user:reconnect");
462
+ try {
463
+ if (await a.connect($, _), i("Room reconnected"), E = !0, a.remoteParticipants.size === 0) {
464
+ if (i("Waiting for agent to join..."), !await new Promise((r) => {
465
+ const c = setTimeout(() => {
466
+ a == null || a.off(f.ParticipantConnected, d), r(!1);
467
+ }, 5e3), d = () => {
468
+ clearTimeout(c), a == null || a.off(f.ParticipantConnected, d), r(!0);
469
+ };
470
+ a == null || a.on(f.ParticipantConnected, d);
471
+ }))
472
+ throw i("Agent did not join within timeout"), await a.disconnect(), new Error("Agent did not rejoin the room");
473
+ i("Agent joined, reconnection successful");
474
+ }
475
+ } catch (o) {
476
+ throw i("Failed to reconnect:", o), (t = n.onConnectionStateChange) == null || t.call(n, A.Fail, "user:reconnect-failed"), o;
477
+ }
478
+ },
479
+ sendDataChannelMessage: se,
480
+ sendTextMessage: Be,
481
+ publishMicrophoneStream: Ne,
482
+ unpublishMicrophoneStream: H,
483
+ replaceMicrophoneTrack: Ue,
484
+ publishCameraStream: je,
485
+ unpublishCameraStream: X,
486
+ interrupt(e) {
487
+ e !== "text" && se(JSON.stringify({
488
+ topic: "did.interrupt"
489
+ /* Interrupt */
490
+ }));
491
+ },
492
+ /**
493
+ * Switch the STT language mid-session.
494
+ * Only available for Expressive (V4) agents.
495
+ * @param language - Language name or BCP-47 code (e.g. "English" or "en-US").
496
+ * @returns Promise that resolves after the send attempt completes; failures are reported via onError.
497
+ */
498
+ setSttLanguage(e) {
499
+ return J(
500
+ JSON.stringify({ language: e }),
501
+ "did.stt-language"
502
+ /* SttLanguage */
503
+ );
504
+ },
505
+ registerRpcMethod(e, t) {
506
+ a == null || a.registerRpcMethod(e, t);
507
+ },
508
+ unregisterRpcMethod(e) {
509
+ a == null || a.unregisterRpcMethod(e);
510
+ },
511
+ sessionId: T,
512
+ streamId: T,
513
+ streamType: ne,
514
+ interruptAvailable: te,
515
+ isInterruptible: q
516
+ };
517
+ }
518
+ export {
519
+ dn as createLiveKitStreamingManager,
520
+ me as handleInitError
521
+ };
@@ -2,4 +2,5 @@ export * from './errors';
2
2
  export * from './services/agent-manager';
3
3
  export * from './types';
4
4
  export { parseMessageParts } from './utils/content-parser';
5
+ export { isAwaitingTool } from './utils/tool-calls';
5
6
  export { SDK_VERSION } from './version';
@@ -87,6 +87,13 @@ export type StreamingManager<T extends CreateStreamOptions | CreateSessionV2Opti
87
87
  * `did.interrupt` and ignores `text` interrupts to avoid races).
88
88
  */
89
89
  interrupt(type: Interrupt['type']): void;
90
+ /**
91
+ * Switch the STT language mid-session.
92
+ * Only available for Expressive (V4) agents.
93
+ * supported only for livekit manager
94
+ * @param language Language name or BCP-47 code (e.g. "English" or "en-US")
95
+ */
96
+ setSttLanguage?(language: string): Promise<void>;
90
97
  /**
91
98
  * Register an RPC method handler on the LiveKit room.
92
99
  * Used internally by the agent-manager for client tool delegation.
@@ -4,7 +4,8 @@ import { StreamingManager } from './common';
4
4
  export declare enum DataChannelTopic {
5
5
  Chat = "lk.chat",
6
6
  Speak = "did.speak",
7
- Interrupt = "did.interrupt"
7
+ Interrupt = "did.interrupt",
8
+ SttLanguage = "did.stt-language"
8
9
  }
9
10
  export declare function handleInitError(error: unknown, log: (message?: any, ...optionalParams: any[]) => void, callbacks: StreamingManagerOptions['callbacks']): void;
10
11
  export declare function createLiveKitStreamingManager<T extends CreateSessionV2Options>(agentId: string, sessionOptions: CreateSessionV2Options, options: StreamingManagerOptions): Promise<StreamingManager<T> & {
@@ -103,6 +103,12 @@ interface ManagerCallbacks {
103
103
  * @param interruptible - Whether the agent can be interrupted by the user
104
104
  */
105
105
  onInterruptibleChange?: StreamManagerCallbacks['onInterruptibleChange'];
106
+ /**
107
+ * Optional callback function that will be triggered when the set of running tool calls changes,
108
+ * including an empty array on disconnect.
109
+ * @param calls - The tool calls currently running
110
+ */
111
+ onRunningToolCallsChange?: StreamManagerCallbacks['onRunningToolCallsChange'];
106
112
  }
107
113
  interface StreamOptions {
108
114
  /**
@@ -280,6 +286,12 @@ export interface AgentManager {
280
286
  * Only available for Fluent streams and when there's an active video to interrupt
281
287
  */
282
288
  interrupt: (interrupt: Interrupt) => void;
289
+ /**
290
+ * Switch the STT language mid-session
291
+ * Only available for Expressive (V4) agents
292
+ * @param language - Language name or BCP-47 code (e.g. "English" or "en-US")
293
+ */
294
+ setSttLanguage: (language: string) => Promise<void>;
283
295
  /**
284
296
  * Register a handler for a client tool. When the agent's LLM calls this tool,
285
297
  * the handler executes on the client and returns the result to the LLM.
@@ -72,6 +72,7 @@ export interface ManagerCallbacks {
72
72
  onStreamReady?: () => void;
73
73
  onToolEvent?: ToolEventCallback;
74
74
  onInterruptibleChange?: (interruptible: boolean) => void;
75
+ onRunningToolCallsChange?: (calls: readonly RunningToolCall[]) => void;
75
76
  onFirstAudioDetected?: (metrics: AudioDetectionMetrics) => void;
76
77
  }
77
78
  export interface AudioDetectionMetrics {
@@ -181,12 +182,25 @@ export interface StreamInterruptPayload {
181
182
  timestamp: number;
182
183
  }
183
184
  export type ClientToolHandler = (args: Record<string, unknown>) => Promise<string>;
185
+ export type ToolExecutionMode = 'blocking' | 'async';
186
+ /** A tool call currently running in the session. */
187
+ export interface RunningToolCall {
188
+ callId: string;
189
+ name: string;
190
+ /**
191
+ * 'blocking' - the agent waits for the result before it can continue.
192
+ * 'async' - the agent keeps talking while the call runs.
193
+ */
194
+ executionMode: ToolExecutionMode;
195
+ }
184
196
  export interface ToolCallStartedPayload {
185
197
  call_id: string;
186
198
  name: string;
187
199
  input: Record<string, unknown>;
188
200
  output: Record<string, unknown>;
189
201
  interruptible: boolean;
202
+ execution_mode?: ToolExecutionMode;
203
+ turn_id?: number | null;
190
204
  timestamp: string;
191
205
  }
192
206
  export interface ToolCallDonePayload {
@@ -0,0 +1,8 @@
1
+ import { RunningToolCall } from '../types';
2
+
3
+ /**
4
+ * Whether the agent is waiting on a tool call before it can continue.
5
+ * True while any running call is 'blocking'. False when nothing is running,
6
+ * or when everything running is 'async' and the agent is still available.
7
+ */
8
+ export declare function isAwaitingTool(calls: readonly RunningToolCall[]): boolean;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@d-id/client-sdk",
3
3
  "private": false,
4
- "version": "2.0.5",
4
+ "version": "2.0.6",
5
5
  "type": "module",
6
6
  "description": "d-id client sdk",
7
7
  "repository": {