@memberjunction/livekit-room-server 6.2.0-edge.1 → 6.2.0-edge.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.
Files changed (78) hide show
  1. package/README.md +85 -0
  2. package/dist/index.d.ts +17 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +17 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/livekit-agent-room-coordinator.d.ts +105 -8
  7. package/dist/livekit-agent-room-coordinator.d.ts.map +1 -1
  8. package/dist/livekit-agent-room-coordinator.js +125 -25
  9. package/dist/livekit-agent-room-coordinator.js.map +1 -1
  10. package/dist/livekit-egress-service.d.ts +7 -0
  11. package/dist/livekit-egress-service.d.ts.map +1 -1
  12. package/dist/livekit-egress-service.js +11 -0
  13. package/dist/livekit-egress-service.js.map +1 -1
  14. package/dist/livekit-native-module.d.ts +18 -0
  15. package/dist/livekit-native-module.d.ts.map +1 -0
  16. package/dist/livekit-native-module.js +20 -0
  17. package/dist/livekit-native-module.js.map +1 -0
  18. package/dist/livekit-sip-service.d.ts +141 -0
  19. package/dist/livekit-sip-service.d.ts.map +1 -0
  20. package/dist/livekit-sip-service.js +169 -0
  21. package/dist/livekit-sip-service.js.map +1 -0
  22. package/dist/livekit-token-service.d.ts +6 -0
  23. package/dist/livekit-token-service.d.ts.map +1 -1
  24. package/dist/livekit-token-service.js +8 -0
  25. package/dist/livekit-token-service.js.map +1 -1
  26. package/dist/livekit-webhook.d.ts +65 -0
  27. package/dist/livekit-webhook.d.ts.map +1 -0
  28. package/dist/livekit-webhook.js +65 -0
  29. package/dist/livekit-webhook.js.map +1 -0
  30. package/dist/meeting-dial-in-service.d.ts +75 -0
  31. package/dist/meeting-dial-in-service.d.ts.map +1 -0
  32. package/dist/meeting-dial-in-service.js +175 -0
  33. package/dist/meeting-dial-in-service.js.map +1 -0
  34. package/dist/room-audio/audio-decoder.d.ts +40 -0
  35. package/dist/room-audio/audio-decoder.d.ts.map +1 -0
  36. package/dist/room-audio/audio-decoder.js +205 -0
  37. package/dist/room-audio/audio-decoder.js.map +1 -0
  38. package/dist/room-audio/comfort-tone.d.ts +23 -0
  39. package/dist/room-audio/comfort-tone.d.ts.map +1 -0
  40. package/dist/room-audio/comfort-tone.js +70 -0
  41. package/dist/room-audio/comfort-tone.js.map +1 -0
  42. package/dist/room-audio/pcm-frame-pump.d.ts +134 -0
  43. package/dist/room-audio/pcm-frame-pump.d.ts.map +1 -0
  44. package/dist/room-audio/pcm-frame-pump.js +253 -0
  45. package/dist/room-audio/pcm-frame-pump.js.map +1 -0
  46. package/dist/room-audio/room-audio-decode-cache.d.ts +37 -0
  47. package/dist/room-audio/room-audio-decode-cache.d.ts.map +1 -0
  48. package/dist/room-audio/room-audio-decode-cache.js +75 -0
  49. package/dist/room-audio/room-audio-decode-cache.js.map +1 -0
  50. package/dist/room-audio/room-audio-player.d.ts +178 -0
  51. package/dist/room-audio/room-audio-player.d.ts.map +1 -0
  52. package/dist/room-audio/room-audio-player.js +404 -0
  53. package/dist/room-audio/room-audio-player.js.map +1 -0
  54. package/dist/room-audio/room-audio-sources.d.ts +47 -0
  55. package/dist/room-audio/room-audio-sources.d.ts.map +1 -0
  56. package/dist/room-audio/room-audio-sources.js +116 -0
  57. package/dist/room-audio/room-audio-sources.js.map +1 -0
  58. package/dist/room-audio/room-speech-synthesizer.d.ts +55 -0
  59. package/dist/room-audio/room-speech-synthesizer.d.ts.map +1 -0
  60. package/dist/room-audio/room-speech-synthesizer.js +56 -0
  61. package/dist/room-audio/room-speech-synthesizer.js.map +1 -0
  62. package/dist/room-authorization.d.ts +58 -0
  63. package/dist/room-authorization.d.ts.map +1 -0
  64. package/dist/room-authorization.js +212 -0
  65. package/dist/room-authorization.js.map +1 -0
  66. package/dist/room-handoff/handoff-offer-registry.d.ts +137 -0
  67. package/dist/room-handoff/handoff-offer-registry.d.ts.map +1 -0
  68. package/dist/room-handoff/handoff-offer-registry.js +521 -0
  69. package/dist/room-handoff/handoff-offer-registry.js.map +1 -0
  70. package/dist/room-handoff/handoff-types.d.ts +170 -0
  71. package/dist/room-handoff/handoff-types.d.ts.map +1 -0
  72. package/dist/room-handoff/handoff-types.js +16 -0
  73. package/dist/room-handoff/handoff-types.js.map +1 -0
  74. package/dist/room-handoff/room-handoff-engine.d.ts +141 -0
  75. package/dist/room-handoff/room-handoff-engine.d.ts.map +1 -0
  76. package/dist/room-handoff/room-handoff-engine.js +530 -0
  77. package/dist/room-handoff/room-handoff-engine.js.map +1 -0
  78. package/package.json +14 -9
@@ -0,0 +1,530 @@
1
+ /**
2
+ * @fileoverview {@link RoomHandoffEngine}: moves a LiveKit room conversation from the AI agent that is in it to a
3
+ * person, a phone number, or another AI agent, while the caller stays in the room.
4
+ *
5
+ * The room is the shared plane. A handoff never transfers the caller; it adds the new party to the room the caller
6
+ * is already in and then takes the AI out. That is what makes "warm" possible (the AI can say a sentence to the new
7
+ * party with the caller listening) and what makes a failed handoff harmless (nobody is moved, so the AI just carries on).
8
+ *
9
+ * The flow for each destination:
10
+ * - **person**: an offer is created and pushed to their console. If they accept, the console joins the room; the engine
11
+ * watches the room until they are actually present, then runs the leave step. If they decline, or do not answer in time
12
+ * (or accept but never appear), the engine dials the person's fallback number into the room when one is configured, and
13
+ * otherwise tells the model nobody is available.
14
+ * - **number**: the room dials the number; when it answers and is present, the leave step runs.
15
+ * - **agent**: the host starts the other agent in the room; when it is up, the leave step runs.
16
+ *
17
+ * The leave step is where warm and blind differ. Blind: the AI leaves as soon as the new party is present. Warm: the AI is
18
+ * told the party has joined and to introduce them in a sentence or two, then to call `finish_handoff`; it leaves a moment
19
+ * after that call (so its last words are heard), or after a ceiling if it never calls.
20
+ *
21
+ * Everything the engine touches the outside world with is an injected seam (presence, dialer, notifier, publisher, agent
22
+ * starter), so the whole flow is unit-tested with fakes. One handoff runs per room at a time. State is in memory and per
23
+ * process: see {@link HandoffOfferRegistry} for what a multi-instance deployment needs.
24
+ *
25
+ * @module @memberjunction/livekit-room-server
26
+ */
27
+ import { LogError, LogStatus } from '@memberjunction/core';
28
+ import { BaseSingleton } from '@memberjunction/global';
29
+ import { LiveKitUserIdentity } from '../livekit-token-service.js';
30
+ import { HandoffOfferRegistry, ToOfferView } from './handoff-offer-registry.js';
31
+ /** The tool the AI calls after briefing the new party, to say it is done and can leave. */
32
+ export const FINISH_HANDOFF_TOOL = 'finish_handoff';
33
+ /** How long a person who accepted an offer has to actually appear in the room. */
34
+ export const HANDOFF_JOIN_WAIT_MS = 90_000;
35
+ /** How often the room is checked for the new party. */
36
+ export const HANDOFF_PRESENCE_POLL_MS = 1_000;
37
+ /** The longest the AI is given to brief the new party before it is removed anyway. */
38
+ export const HANDOFF_BRIEF_MAX_MS = 45_000;
39
+ /** How long the AI's last words are given to play after it calls {@link FINISH_HANDOFF_TOOL}. */
40
+ export const HANDOFF_LEAVE_SETTLE_MS = 3_000;
41
+ /** How long after a blind handoff's new party appears the AI leaves. */
42
+ export const HANDOFF_BLIND_LEAVE_DELAY_MS = 1_500;
43
+ /** How long a number the room dials is allowed to ring. */
44
+ export const HANDOFF_DIAL_RING_SECONDS = 30;
45
+ /** The longest summary kept (it is shown on the offer and given to a taking-over agent). */
46
+ export const MAX_HANDOFF_SUMMARY_CHARS = 600;
47
+ /** Brings a person, a number or another agent into a room conversation and takes the AI out. */
48
+ export class RoomHandoffEngine extends BaseSingleton {
49
+ constructor() {
50
+ super();
51
+ this.deps = {};
52
+ this.flows = new Map();
53
+ this.nextFlowID = 1;
54
+ }
55
+ /** The process-wide engine. */
56
+ static get Instance() {
57
+ return super.getInstance();
58
+ }
59
+ /** Sets (merges) the collaborators. Called once at startup by the host that owns each one. */
60
+ Configure(deps) {
61
+ this.deps = { ...this.deps, ...deps };
62
+ HandoffOfferRegistry.Instance.Configure({
63
+ Publisher: (evt) => this.publish(evt),
64
+ });
65
+ }
66
+ /** The collaborators currently set (a `Pick` for diagnostics; tests read it). */
67
+ get Deps() {
68
+ return this.deps;
69
+ }
70
+ /** Drops every flow and every collaborator (tests, shutdown). */
71
+ Reset() {
72
+ for (const flow of this.flows.values()) {
73
+ this.cancelFlow(flow, 'Cancelled');
74
+ }
75
+ this.flows.clear();
76
+ this.deps = {};
77
+ }
78
+ /**
79
+ * Starts handing the conversation over. Returns at once; what happens next is reported to the model through
80
+ * {@link RoomHandoffAgentContext.NotifyModel}.
81
+ */
82
+ async RequestHandoff(agent, request) {
83
+ const key = roomKey(agent.RoomName);
84
+ if (this.flows.has(key)) {
85
+ return { Ok: false, Error: 'A handoff is already in progress for this call.' };
86
+ }
87
+ const prepared = this.prepare(request);
88
+ if (!prepared.Ok) {
89
+ return prepared;
90
+ }
91
+ const flow = { FlowID: this.nextFlowID++, Agent: agent, Request: prepared.Request, Phase: 'offering', Cancelled: false, Timers: new Set() };
92
+ const started = await this.begin(flow);
93
+ if (started.Ok) {
94
+ this.flows.set(key, flow);
95
+ }
96
+ return started;
97
+ }
98
+ /** The AI says it has finished briefing and is ready to leave. Returns whether a handoff was waiting for that. */
99
+ AgentReadyToLeave(roomName) {
100
+ const flow = this.flows.get(roomKey(roomName));
101
+ if (!flow || flow.Phase !== 'awaiting-leave') {
102
+ return false;
103
+ }
104
+ flow.Phase = 'leaving';
105
+ this.armTimer(flow, HANDOFF_LEAVE_SETTLE_MS, () => this.leave(flow));
106
+ return true;
107
+ }
108
+ /** Whether a handoff is in progress for the room. */
109
+ HasHandoff(roomName) {
110
+ return this.flows.has(roomKey(roomName));
111
+ }
112
+ /**
113
+ * The room's call ended or the agent left for another reason: abandon its handoff and withdraw its offer. A flow
114
+ * that is already leaving is finished, not cancelled.
115
+ */
116
+ CancelRoom(roomName) {
117
+ const key = roomKey(roomName);
118
+ const flow = this.flows.get(key);
119
+ if (!flow || flow.Phase === 'leaving') {
120
+ return;
121
+ }
122
+ this.flows.delete(key);
123
+ this.cancelFlow(flow, 'Cancelled');
124
+ }
125
+ /** The offers to show a person (pending ones and recently resolved ones). */
126
+ async ListOffersForUser(userID, contextUser, provider) {
127
+ const offers = await HandoffOfferRegistry.Instance.ListForUser(userID, contextUser, provider);
128
+ return offers.map(ToOfferView);
129
+ }
130
+ /**
131
+ * A person accepts an offer. Authorised by the offer's target; anything else answers as a missing offer. On success
132
+ * the console should join the room; the engine watches for them and takes the AI out once they are there.
133
+ */
134
+ async AcceptOffer(offerID, userID, contextUser, provider) {
135
+ const resolved = await HandoffOfferRegistry.Instance.ResolveForUser(offerID, userID, 'Accepted', contextUser, provider);
136
+ if (!resolved.Ok) {
137
+ return resolved;
138
+ }
139
+ this.publishUpdate(resolved.Offer);
140
+ const flow = this.flowForOffer(resolved.Offer);
141
+ if (flow) {
142
+ this.deps.Observer?.OnHandoffEvent?.({
143
+ RoomName: resolved.Offer.RoomName,
144
+ EventType: 'Accepted',
145
+ ActorUserID: userID,
146
+ Details: { OfferID: offerID },
147
+ ContextUser: flow.Agent.ContextUser,
148
+ Provider: flow.Agent.Provider,
149
+ });
150
+ this.clearTimers(flow);
151
+ flow.Phase = 'joining';
152
+ void this.waitForUserToJoin(flow, userID);
153
+ }
154
+ return { Ok: true, Offer: ToOfferView(resolved.Offer) };
155
+ }
156
+ /** A person declines an offer. Authorised the same way as {@link AcceptOffer}. */
157
+ async DeclineOffer(offerID, userID, contextUser, provider) {
158
+ const resolved = await HandoffOfferRegistry.Instance.ResolveForUser(offerID, userID, 'Declined', contextUser, provider);
159
+ if (!resolved.Ok) {
160
+ return resolved;
161
+ }
162
+ this.publishUpdate(resolved.Offer);
163
+ const flow = this.flowForOffer(resolved.Offer);
164
+ if (flow) {
165
+ this.deps.Observer?.OnHandoffEvent?.({
166
+ RoomName: resolved.Offer.RoomName,
167
+ EventType: 'Declined',
168
+ ActorUserID: userID,
169
+ Details: { OfferID: offerID },
170
+ ContextUser: flow.Agent.ContextUser,
171
+ Provider: flow.Agent.Provider,
172
+ });
173
+ this.clearTimers(flow);
174
+ this.onPartyUnavailable(flow, 'declined the conversation');
175
+ }
176
+ return { Ok: true };
177
+ }
178
+ /**
179
+ * Handles an offer update forwarded from another cluster instance via cross-instance pub/sub.
180
+ */
181
+ OnRemoteOfferChange(payload) {
182
+ const flow = this.flows.get(roomKey(payload.Offer.RoomName));
183
+ if (!flow || flow.OfferID !== payload.Offer.OfferID) {
184
+ return;
185
+ }
186
+ if (payload.Offer.Status === 'Accepted') {
187
+ this.deps.Observer?.OnHandoffEvent?.({
188
+ RoomName: flow.Agent.RoomName,
189
+ EventType: 'Accepted',
190
+ ActorUserID: payload.UserID,
191
+ Details: { OfferID: payload.Offer.OfferID },
192
+ ContextUser: flow.Agent.ContextUser,
193
+ Provider: flow.Agent.Provider,
194
+ });
195
+ this.clearTimers(flow);
196
+ flow.Phase = 'joining';
197
+ void this.waitForUserToJoin(flow, payload.UserID);
198
+ }
199
+ else if (payload.Offer.Status === 'Declined') {
200
+ this.deps.Observer?.OnHandoffEvent?.({
201
+ RoomName: flow.Agent.RoomName,
202
+ EventType: 'Declined',
203
+ ActorUserID: payload.UserID,
204
+ Details: { OfferID: payload.Offer.OfferID },
205
+ ContextUser: flow.Agent.ContextUser,
206
+ Provider: flow.Agent.Provider,
207
+ });
208
+ this.clearTimers(flow);
209
+ this.onPartyUnavailable(flow, 'declined the conversation');
210
+ }
211
+ else if (payload.Offer.Status === 'Cancelled') {
212
+ this.cancelFlow(flow, 'Cancelled');
213
+ }
214
+ }
215
+ // ── starting ─────────────────────────────────────────────────────────────────
216
+ /** Checks the request and that the collaborators its kind needs are present. */
217
+ prepare(request) {
218
+ const summary = (request.Summary ?? '').trim().slice(0, MAX_HANDOFF_SUMMARY_CHARS);
219
+ if (!summary) {
220
+ return { Ok: false, Error: 'A short summary of the conversation is required.' };
221
+ }
222
+ const destination = request.Destination;
223
+ if (destination.Kind === 'agent' && !this.deps.AgentStarter) {
224
+ return { Ok: false, Error: 'Handing over to another agent is not available on this server.' };
225
+ }
226
+ if (destination.Kind === 'number' && (!this.deps.Dialer || !this.deps.Presence)) {
227
+ return { Ok: false, Error: 'Dialing a number into the call is not available on this server.' };
228
+ }
229
+ if (destination.Kind === 'user' && !this.deps.Presence) {
230
+ return { Ok: false, Error: 'Bringing a person into the call is not available on this server.' };
231
+ }
232
+ return { Ok: true, Request: { ...request, Summary: summary } };
233
+ }
234
+ async begin(flow) {
235
+ const destination = flow.Request.Destination;
236
+ switch (destination.Kind) {
237
+ case 'user':
238
+ return await this.offerToUser(flow);
239
+ case 'number':
240
+ flow.Phase = 'dialing';
241
+ void this.dialAndAwait(flow, destination.Number, destination.DisplayName, 'the number');
242
+ return { Ok: true, Status: 'dialing' };
243
+ case 'agent':
244
+ flow.Phase = 'agent-joining';
245
+ void this.startAgent(flow);
246
+ return { Ok: true, Status: 'agent-joining' };
247
+ }
248
+ }
249
+ async offerToUser(flow) {
250
+ const destination = flow.Request.Destination;
251
+ if (destination.Kind !== 'user') {
252
+ return { Ok: false, Error: 'Not a person.' };
253
+ }
254
+ const offer = await HandoffOfferRegistry.Instance.Create({
255
+ RoomName: flow.Agent.RoomName,
256
+ TargetUserID: destination.UserID,
257
+ Mode: flow.Request.Mode,
258
+ Summary: flow.Request.Summary,
259
+ CallerLabel: flow.Agent.CallerLabel,
260
+ AgentName: flow.Agent.AgentName,
261
+ InteractionID: flow.Agent.InteractionID,
262
+ OfferedByAgentID: flow.Agent.AgentID,
263
+ ContextUser: flow.Agent.ContextUser,
264
+ Provider: flow.Agent.Provider,
265
+ });
266
+ if (!offer) {
267
+ return { Ok: false, Error: `${destination.DisplayName} has too many open conversation offers right now.` };
268
+ }
269
+ flow.OfferID = offer.OfferID;
270
+ this.publish({ UserID: offer.TargetUserID, Kind: 'offered', Offer: ToOfferView(offer) });
271
+ void this.notify(offer, flow);
272
+ this.deps.Observer?.OnHandoffEvent?.({
273
+ RoomName: flow.Agent.RoomName,
274
+ EventType: 'Offered',
275
+ ActorUserID: destination.UserID,
276
+ Details: { OfferID: offer.OfferID, Summary: flow.Request.Summary, Mode: flow.Request.Mode },
277
+ ContextUser: flow.Agent.ContextUser,
278
+ Provider: flow.Agent.Provider,
279
+ });
280
+ this.deps.Observer?.OnHandoffEvent?.({
281
+ RoomName: flow.Agent.RoomName,
282
+ EventType: 'Escalated',
283
+ ActorUserID: destination.UserID,
284
+ Details: { OfferID: offer.OfferID, Summary: flow.Request.Summary },
285
+ ContextUser: flow.Agent.ContextUser,
286
+ Provider: flow.Agent.Provider,
287
+ });
288
+ this.armTimer(flow, offer.ExpiresAtMs - offer.CreatedAtMs, () => this.onOfferTimeout(flow));
289
+ return { Ok: true, Status: 'offered' };
290
+ }
291
+ // ── person: waiting for the answer ───────────────────────────────────────────
292
+ async onOfferTimeout(flow) {
293
+ if (flow.Cancelled || !flow.OfferID) {
294
+ return;
295
+ }
296
+ const closed = await HandoffOfferRegistry.Instance.Close(flow.OfferID, 'Expired', flow.Agent.ContextUser, flow.Agent.Provider);
297
+ if (!closed) {
298
+ return; // accepted or declined in the same instant
299
+ }
300
+ this.publishUpdate(closed);
301
+ this.onPartyUnavailable(flow, 'did not answer in time');
302
+ }
303
+ async waitForUserToJoin(flow, userID) {
304
+ const joined = await this.pollPresence(flow, LiveKitUserIdentity(userID), HANDOFF_JOIN_WAIT_MS);
305
+ if (flow.Cancelled) {
306
+ return;
307
+ }
308
+ if (joined) {
309
+ this.onPartyPresent(flow);
310
+ }
311
+ else {
312
+ this.onPartyUnavailable(flow, 'accepted but did not join the call');
313
+ }
314
+ }
315
+ // ── number and fallback: dialing ─────────────────────────────────────────────
316
+ /** Dials a number into the room and waits for it to appear. Used for a number target and for a person's fallback. */
317
+ async dialAndAwait(flow, number, displayName, what) {
318
+ const identity = `sip-handoff-${flow.FlowID}`;
319
+ flow.Phase = 'dialing';
320
+ try {
321
+ await this.deps.Dialer?.DialIntoRoom({
322
+ RoomName: flow.Agent.RoomName,
323
+ Number: number,
324
+ ParticipantIdentity: identity,
325
+ DisplayName: displayName,
326
+ FromNumber: flow.Request.Destination.Kind === 'number' ? flow.Request.Destination.FromNumber : undefined,
327
+ RingTimeoutSeconds: HANDOFF_DIAL_RING_SECONDS,
328
+ });
329
+ }
330
+ catch (e) {
331
+ LogError(`[RoomHandoff] dialing ${what} into room ${flow.Agent.RoomName} failed: ${e instanceof Error ? e.message : String(e)}`);
332
+ this.finishUnavailable(flow, `${displayName} could not be reached by phone`);
333
+ return;
334
+ }
335
+ const answered = await this.pollPresence(flow, identity, HANDOFF_JOIN_WAIT_MS);
336
+ if (flow.Cancelled) {
337
+ return;
338
+ }
339
+ if (answered) {
340
+ this.onPartyPresent(flow);
341
+ }
342
+ else {
343
+ this.finishUnavailable(flow, `${displayName} did not pick up`);
344
+ }
345
+ }
346
+ // ── agent: starting another agent ────────────────────────────────────────────
347
+ async startAgent(flow) {
348
+ const destination = flow.Request.Destination;
349
+ if (destination.Kind !== 'agent' || !this.deps.AgentStarter) {
350
+ return;
351
+ }
352
+ try {
353
+ await this.deps.AgentStarter({
354
+ RoomName: flow.Agent.RoomName,
355
+ AgentID: destination.AgentID,
356
+ AgentName: destination.AgentName,
357
+ Brief: flow.Request.Summary,
358
+ PreviousAgentName: flow.Agent.AgentName,
359
+ CallerLabel: flow.Agent.CallerLabel,
360
+ ContextUser: flow.Agent.ContextUser,
361
+ Provider: flow.Agent.Provider,
362
+ });
363
+ }
364
+ catch (e) {
365
+ LogError(`[RoomHandoff] starting agent ${destination.AgentName} in room ${flow.Agent.RoomName} failed: ${e instanceof Error ? e.message : String(e)}`);
366
+ this.finishUnavailable(flow, `${destination.AgentName} could not be started`);
367
+ return;
368
+ }
369
+ if (!flow.Cancelled) {
370
+ this.onPartyPresent(flow);
371
+ }
372
+ }
373
+ // ── the new party is (not) there ─────────────────────────────────────────────
374
+ /** The person did not take it. Fall back to their phone when one is configured, otherwise tell the model. */
375
+ onPartyUnavailable(flow, why) {
376
+ const destination = flow.Request.Destination;
377
+ if (destination.Kind === 'user' && destination.FallbackNumber && this.deps.Dialer && this.deps.Presence) {
378
+ flow.Agent.NotifyModel(`[handoff] ${destination.DisplayName} ${why}. You are now trying their phone. Keep the caller company, and say you are still working on connecting them.`);
379
+ void this.dialAndAwait(flow, destination.FallbackNumber, destination.DisplayName, 'the fallback number');
380
+ return;
381
+ }
382
+ this.finishUnavailable(flow, `${displayNameOf(flow)} ${why}`);
383
+ }
384
+ /** The handoff failed for good: tell the model so it can tell the caller, and let the call carry on with the AI. */
385
+ finishUnavailable(flow, why) {
386
+ if (flow.Cancelled) {
387
+ return;
388
+ }
389
+ this.removeFlow(flow);
390
+ flow.Agent.NotifyModel(`[handoff] Nobody could take the conversation: ${why}. Tell the caller honestly that nobody is available right now, ` +
391
+ 'and offer to keep helping, or to take a message. Do not say you are transferring them.');
392
+ LogStatus(`[RoomHandoff] handoff in room ${flow.Agent.RoomName} did not complete: ${why}.`);
393
+ }
394
+ /** The new party is in the room. Blind: the AI leaves. Warm: the AI briefs them, then leaves. */
395
+ onPartyPresent(flow) {
396
+ if (flow.Cancelled) {
397
+ return;
398
+ }
399
+ const name = displayNameOf(flow);
400
+ this.deps.Observer?.OnHandoffEvent?.({
401
+ RoomName: flow.Agent.RoomName,
402
+ EventType: 'Transferred',
403
+ Details: {
404
+ Target: name,
405
+ Kind: flow.Request.Destination.Kind,
406
+ Mode: flow.Request.Mode,
407
+ },
408
+ ContextUser: flow.Agent.ContextUser,
409
+ Provider: flow.Agent.Provider,
410
+ });
411
+ if (flow.Request.Mode === 'blind') {
412
+ flow.Phase = 'leaving';
413
+ this.armTimer(flow, HANDOFF_BLIND_LEAVE_DELAY_MS, () => this.leave(flow));
414
+ return;
415
+ }
416
+ flow.Phase = 'awaiting-leave';
417
+ flow.Agent.NotifyModel(`[handoff] ${name} has joined the call. In one or two short sentences, introduce ${name} to the caller and tell ${name} the key points: ` +
418
+ `${flow.Request.Summary} Then call ${FINISH_HANDOFF_TOOL}. Do not carry on the conversation yourself after that.`);
419
+ this.armTimer(flow, HANDOFF_BRIEF_MAX_MS, () => this.leave(flow));
420
+ }
421
+ /** Takes the AI out of the room. The flow is removed first, so the agent's own teardown does not read as a cancellation. */
422
+ async leave(flow) {
423
+ if (flow.Cancelled) {
424
+ return;
425
+ }
426
+ this.removeFlow(flow);
427
+ try {
428
+ await flow.Agent.LeaveRoom();
429
+ LogStatus(`[RoomHandoff] ${flow.Agent.AgentName} left room ${flow.Agent.RoomName} after the handoff.`);
430
+ }
431
+ catch (e) {
432
+ LogError(`[RoomHandoff] ${flow.Agent.AgentName} could not leave room ${flow.Agent.RoomName}: ${e instanceof Error ? e.message : String(e)}`);
433
+ }
434
+ }
435
+ // ── plumbing ─────────────────────────────────────────────────────────────────
436
+ /** Checks the room for a participant until it is there, the flow is cancelled, or the time is up. */
437
+ async pollPresence(flow, identity, maxMs) {
438
+ const polls = Math.max(1, Math.ceil(maxMs / HANDOFF_PRESENCE_POLL_MS));
439
+ for (let i = 0; i < polls; i++) {
440
+ if (flow.Cancelled) {
441
+ return false;
442
+ }
443
+ if (await this.isPresent(flow.Agent.RoomName, identity)) {
444
+ return true;
445
+ }
446
+ await sleep(HANDOFF_PRESENCE_POLL_MS);
447
+ }
448
+ return false;
449
+ }
450
+ async isPresent(roomName, identity) {
451
+ try {
452
+ return (await this.deps.Presence?.IsParticipantPresent(roomName, identity)) === true;
453
+ }
454
+ catch (e) {
455
+ LogError(`[RoomHandoff] checking room ${roomName} for ${identity} failed: ${e instanceof Error ? e.message : String(e)}`);
456
+ return false;
457
+ }
458
+ }
459
+ async notify(offer, flow) {
460
+ try {
461
+ await this.deps.Notifier?.NotifyOffer(ToOfferView(offer), offer.TargetUserID, flow.Agent.ContextUser, flow.Agent.Provider);
462
+ }
463
+ catch (e) {
464
+ LogError(`[RoomHandoff] notifying about offer ${offer.OfferID} failed (the live console still receives it): ${e instanceof Error ? e.message : String(e)}`);
465
+ }
466
+ }
467
+ publishUpdate(offer) {
468
+ this.publish({ UserID: offer.TargetUserID, Kind: 'updated', Offer: ToOfferView(offer) });
469
+ }
470
+ publish(event) {
471
+ try {
472
+ this.deps.Publisher?.Publish(event);
473
+ }
474
+ catch (e) {
475
+ LogError(`[RoomHandoff] publishing an offer change failed: ${e instanceof Error ? e.message : String(e)}`);
476
+ }
477
+ }
478
+ flowForOffer(offer) {
479
+ const flow = this.flows.get(roomKey(offer.RoomName));
480
+ return flow && flow.OfferID === offer.OfferID ? flow : undefined;
481
+ }
482
+ removeFlow(flow) {
483
+ this.clearTimers(flow);
484
+ const key = roomKey(flow.Agent.RoomName);
485
+ if (this.flows.get(key) === flow) {
486
+ this.flows.delete(key);
487
+ }
488
+ }
489
+ /** Stops a flow's timers and withdraws its offer. */
490
+ cancelFlow(flow, status) {
491
+ flow.Cancelled = true;
492
+ this.clearTimers(flow);
493
+ if (flow.OfferID) {
494
+ void HandoffOfferRegistry.Instance.Close(flow.OfferID, status, flow.Agent.ContextUser, flow.Agent.Provider).then((closed) => {
495
+ if (closed) {
496
+ this.publishUpdate(closed);
497
+ }
498
+ });
499
+ }
500
+ }
501
+ armTimer(flow, ms, work) {
502
+ const timer = setTimeout(() => {
503
+ flow.Timers.delete(timer);
504
+ void Promise.resolve(work()).catch((e) => LogError(`[RoomHandoff] a handoff timer failed: ${e instanceof Error ? e.message : String(e)}`));
505
+ }, ms);
506
+ timer.unref?.();
507
+ flow.Timers.add(timer);
508
+ }
509
+ clearTimers(flow) {
510
+ for (const timer of flow.Timers) {
511
+ clearTimeout(timer);
512
+ }
513
+ flow.Timers.clear();
514
+ }
515
+ }
516
+ function roomKey(roomName) {
517
+ return roomName.trim().toLowerCase();
518
+ }
519
+ /** What the AI and the logs call the party being brought in. */
520
+ function displayNameOf(flow) {
521
+ const destination = flow.Request.Destination;
522
+ return destination.Kind === 'agent' ? destination.AgentName : destination.DisplayName;
523
+ }
524
+ function sleep(ms) {
525
+ return new Promise((resolve) => {
526
+ const timer = setTimeout(resolve, ms);
527
+ timer.unref?.();
528
+ });
529
+ }
530
+ //# sourceMappingURL=room-handoff-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-handoff-engine.js","sourceRoot":"","sources":["../../src/room-handoff/room-handoff-engine.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@memberjunction/livekit-room-server",
3
3
  "type": "module",
4
- "version": "6.2.0-edge.1",
4
+ "version": "6.2.0-edge.3",
5
5
  "description": "MemberJunction: Server-side LiveKit room support — mints scoped client/bot access tokens (livekit-server-sdk) and provides the session-start coordinator that opens a realtime model session and bridges it into a LiveKit room via AIBridgeEngine. The MJ realtime-bridge ↔ LiveKit UI seam.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -11,14 +11,19 @@
11
11
  "author": "MemberJunction.com",
12
12
  "license": "BUSL-1.1",
13
13
  "dependencies": {
14
- "@memberjunction/core": "6.2.0-edge.1",
15
- "@memberjunction/global": "6.2.0-edge.1",
16
- "@memberjunction/core-entities": "6.2.0-edge.1",
17
- "@memberjunction/ai": "6.2.0-edge.1",
18
- "@memberjunction/ai-bridge-base": "6.2.0-edge.1",
19
- "@memberjunction/ai-bridge-server": "6.2.0-edge.1",
20
- "@memberjunction/ai-bridge-livekit": "6.2.0-edge.1",
21
- "livekit-server-sdk": "^2.9.7"
14
+ "@memberjunction/core": "6.2.0-edge.3",
15
+ "@memberjunction/global": "6.2.0-edge.3",
16
+ "@memberjunction/core-entities": "6.2.0-edge.3",
17
+ "@memberjunction/ai": "6.2.0-edge.3",
18
+ "@memberjunction/ai-bridge-base": "6.2.0-edge.3",
19
+ "@memberjunction/ai-bridge-server": "6.2.0-edge.3",
20
+ "@memberjunction/ai-bridge-livekit": "6.2.0-edge.3",
21
+ "@memberjunction/ai-bridge-livekit-native": "6.2.0-edge.3",
22
+ "livekit-server-sdk": "^2.9.7",
23
+ "@memberjunction/storage": "6.2.0-edge.3",
24
+ "@memberjunction/ai-prompts": "6.2.0-edge.3",
25
+ "mpg123-decoder": "^1.0.3",
26
+ "@memberjunction/network-utils": "6.2.0-edge.3"
22
27
  },
23
28
  "devDependencies": {
24
29
  "@types/node": "24.10.11",