@memberjunction/livekit-room-server 6.2.0-edge.2 → 6.2.0-edge.4
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/README.md +85 -0
- package/dist/index.d.ts +18 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/livekit-agent-room-coordinator.d.ts +220 -13
- package/dist/livekit-agent-room-coordinator.d.ts.map +1 -1
- package/dist/livekit-agent-room-coordinator.js +409 -65
- package/dist/livekit-agent-room-coordinator.js.map +1 -1
- package/dist/livekit-egress-service.d.ts +7 -0
- package/dist/livekit-egress-service.d.ts.map +1 -1
- package/dist/livekit-egress-service.js +11 -0
- package/dist/livekit-egress-service.js.map +1 -1
- package/dist/livekit-native-module.d.ts +18 -0
- package/dist/livekit-native-module.d.ts.map +1 -0
- package/dist/livekit-native-module.js +27 -0
- package/dist/livekit-native-module.js.map +1 -0
- package/dist/livekit-participant-service.d.ts +47 -0
- package/dist/livekit-participant-service.d.ts.map +1 -0
- package/dist/livekit-participant-service.js +64 -0
- package/dist/livekit-participant-service.js.map +1 -0
- package/dist/livekit-sip-service.d.ts +141 -0
- package/dist/livekit-sip-service.d.ts.map +1 -0
- package/dist/livekit-sip-service.js +169 -0
- package/dist/livekit-sip-service.js.map +1 -0
- package/dist/livekit-token-service.d.ts +26 -5
- package/dist/livekit-token-service.d.ts.map +1 -1
- package/dist/livekit-token-service.js +22 -7
- package/dist/livekit-token-service.js.map +1 -1
- package/dist/livekit-webhook.d.ts +65 -0
- package/dist/livekit-webhook.d.ts.map +1 -0
- package/dist/livekit-webhook.js +65 -0
- package/dist/livekit-webhook.js.map +1 -0
- package/dist/meeting-dial-in-service.d.ts +83 -0
- package/dist/meeting-dial-in-service.d.ts.map +1 -0
- package/dist/meeting-dial-in-service.js +202 -0
- package/dist/meeting-dial-in-service.js.map +1 -0
- package/dist/room-audio/audio-decoder.d.ts +40 -0
- package/dist/room-audio/audio-decoder.d.ts.map +1 -0
- package/dist/room-audio/audio-decoder.js +205 -0
- package/dist/room-audio/audio-decoder.js.map +1 -0
- package/dist/room-audio/comfort-tone.d.ts +23 -0
- package/dist/room-audio/comfort-tone.d.ts.map +1 -0
- package/dist/room-audio/comfort-tone.js +70 -0
- package/dist/room-audio/comfort-tone.js.map +1 -0
- package/dist/room-audio/pcm-frame-pump.d.ts +134 -0
- package/dist/room-audio/pcm-frame-pump.d.ts.map +1 -0
- package/dist/room-audio/pcm-frame-pump.js +253 -0
- package/dist/room-audio/pcm-frame-pump.js.map +1 -0
- package/dist/room-audio/room-audio-decode-cache.d.ts +37 -0
- package/dist/room-audio/room-audio-decode-cache.d.ts.map +1 -0
- package/dist/room-audio/room-audio-decode-cache.js +75 -0
- package/dist/room-audio/room-audio-decode-cache.js.map +1 -0
- package/dist/room-audio/room-audio-player.d.ts +178 -0
- package/dist/room-audio/room-audio-player.d.ts.map +1 -0
- package/dist/room-audio/room-audio-player.js +404 -0
- package/dist/room-audio/room-audio-player.js.map +1 -0
- package/dist/room-audio/room-audio-sources.d.ts +47 -0
- package/dist/room-audio/room-audio-sources.d.ts.map +1 -0
- package/dist/room-audio/room-audio-sources.js +116 -0
- package/dist/room-audio/room-audio-sources.js.map +1 -0
- package/dist/room-audio/room-speech-synthesizer.d.ts +55 -0
- package/dist/room-audio/room-speech-synthesizer.d.ts.map +1 -0
- package/dist/room-audio/room-speech-synthesizer.js +56 -0
- package/dist/room-audio/room-speech-synthesizer.js.map +1 -0
- package/dist/room-authorization.d.ts +58 -0
- package/dist/room-authorization.d.ts.map +1 -0
- package/dist/room-authorization.js +212 -0
- package/dist/room-authorization.js.map +1 -0
- package/dist/room-handoff/handoff-offer-registry.d.ts +147 -0
- package/dist/room-handoff/handoff-offer-registry.d.ts.map +1 -0
- package/dist/room-handoff/handoff-offer-registry.js +548 -0
- package/dist/room-handoff/handoff-offer-registry.js.map +1 -0
- package/dist/room-handoff/handoff-types.d.ts +172 -0
- package/dist/room-handoff/handoff-types.d.ts.map +1 -0
- package/dist/room-handoff/handoff-types.js +16 -0
- package/dist/room-handoff/handoff-types.js.map +1 -0
- package/dist/room-handoff/room-handoff-engine.d.ts +149 -0
- package/dist/room-handoff/room-handoff-engine.d.ts.map +1 -0
- package/dist/room-handoff/room-handoff-engine.js +563 -0
- package/dist/room-handoff/room-handoff-engine.js.map +1 -0
- package/package.json +15 -9
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared types for bringing a person (or another agent) into a LiveKit room conversation.
|
|
3
|
+
*
|
|
4
|
+
* A **handoff** moves a conversation from the AI agent that is in a room to someone else, without the caller
|
|
5
|
+
* leaving the room: a person at an Explorer console (who is first OFFERED the conversation and may accept or
|
|
6
|
+
* decline), a phone number the room dials out to, or another AI agent. The caller stays in the room throughout;
|
|
7
|
+
* only the AI agent leaves, and only once the new party is actually present.
|
|
8
|
+
*
|
|
9
|
+
* The types here are the engine's vocabulary. Where a destination comes from (a named entry in the operator's
|
|
10
|
+
* transfer directory, a user looked up by email) is the caller's concern: by the time a request reaches the engine
|
|
11
|
+
* the destination is already resolved to an id or a validated number.
|
|
12
|
+
*
|
|
13
|
+
* @module @memberjunction/livekit-room-server
|
|
14
|
+
*/
|
|
15
|
+
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
16
|
+
/**
|
|
17
|
+
* How the AI agent leaves the conversation.
|
|
18
|
+
* - `warm`: the AI briefs the new party in a sentence or two (aloud, in the room), then leaves.
|
|
19
|
+
* - `blind`: the AI leaves as soon as the new party is present, with no briefing.
|
|
20
|
+
*/
|
|
21
|
+
export type HandoffMode = 'warm' | 'blind';
|
|
22
|
+
/** A resolved place to hand the conversation to. */
|
|
23
|
+
export type HandoffDestination = {
|
|
24
|
+
Kind: 'user';
|
|
25
|
+
/** The `MJ: Users` id of the person who is offered the conversation. */
|
|
26
|
+
UserID: string;
|
|
27
|
+
/** A name the AI can say (and the console can show). */
|
|
28
|
+
DisplayName: string;
|
|
29
|
+
/** E.164 number the room dials into the call when the person declines or does not answer in time. */
|
|
30
|
+
FallbackNumber?: string;
|
|
31
|
+
} | {
|
|
32
|
+
Kind: 'number';
|
|
33
|
+
/** E.164 number the room dials. The caller of the engine has already checked it against the outbound policy. */
|
|
34
|
+
Number: string;
|
|
35
|
+
DisplayName: string;
|
|
36
|
+
/** Optional outbound caller ID to present when dialing. */
|
|
37
|
+
FromNumber?: string;
|
|
38
|
+
} | {
|
|
39
|
+
Kind: 'agent';
|
|
40
|
+
/** The `MJ: AI Agents` id of the agent that takes over. */
|
|
41
|
+
AgentID: string;
|
|
42
|
+
AgentName: string;
|
|
43
|
+
};
|
|
44
|
+
/** One request to hand the conversation over. */
|
|
45
|
+
export interface HandoffRequest {
|
|
46
|
+
Mode: HandoffMode;
|
|
47
|
+
Destination: HandoffDestination;
|
|
48
|
+
/** A short summary of the conversation so far, written by the AI. Shown on the offer and given to a taking-over agent. */
|
|
49
|
+
Summary: string;
|
|
50
|
+
}
|
|
51
|
+
/** Where a handoff offer stands. */
|
|
52
|
+
export type HandoffOfferStatus = 'Pending' | 'Accepted' | 'Declined' | 'Expired' | 'Cancelled';
|
|
53
|
+
/** What the console is shown about an offer. Never carries server-only fields (the target user id, the bridge id). */
|
|
54
|
+
export interface HandoffOfferView {
|
|
55
|
+
OfferID: string;
|
|
56
|
+
RoomName: string;
|
|
57
|
+
Mode: HandoffMode;
|
|
58
|
+
/** The AI's summary of the conversation so far. */
|
|
59
|
+
Summary: string;
|
|
60
|
+
/** Who is on the other end, in words the person can use (a masked number, "Web visitor"). */
|
|
61
|
+
CallerLabel: string;
|
|
62
|
+
/** The AI agent that is in the room. */
|
|
63
|
+
AgentName: string;
|
|
64
|
+
Status: HandoffOfferStatus;
|
|
65
|
+
/** ISO-8601 UTC. */
|
|
66
|
+
CreatedAt: string;
|
|
67
|
+
/** ISO-8601 UTC; after this the offer can no longer be accepted. */
|
|
68
|
+
ExpiresAt: string;
|
|
69
|
+
/** The MJ interaction ID associated with this conversation/room, if known. */
|
|
70
|
+
InteractionID?: string | null;
|
|
71
|
+
}
|
|
72
|
+
/** One change to an offer, as published to the person it was offered to. */
|
|
73
|
+
export interface HandoffOfferEvent {
|
|
74
|
+
/** The person the offer belongs to. A server-side delivery key: subscribers only ever see their own. */
|
|
75
|
+
UserID: string;
|
|
76
|
+
/** `offered` for a new offer; `updated` when it was accepted, declined, expired or cancelled. */
|
|
77
|
+
Kind: 'offered' | 'updated';
|
|
78
|
+
Offer: HandoffOfferView;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The live room call one AI agent is part of, as the engine needs to act on it. The host builds one per agent
|
|
82
|
+
* session and hands it to {@link RoomHandoffEngine.RequestHandoff}.
|
|
83
|
+
*/
|
|
84
|
+
export interface RoomHandoffAgentContext {
|
|
85
|
+
RoomName: string;
|
|
86
|
+
/** The agent's own name (said to the caller, shown on the offer). */
|
|
87
|
+
AgentName: string;
|
|
88
|
+
/** Who is on the other end of the room. */
|
|
89
|
+
CallerLabel: string;
|
|
90
|
+
/** The user the call runs as (a taking-over agent runs as the same user). */
|
|
91
|
+
ContextUser: UserInfo;
|
|
92
|
+
Provider: IMetadataProvider;
|
|
93
|
+
/** Removes THIS agent from the room. The room, and the caller, stay. */
|
|
94
|
+
LeaveRoom: () => Promise<void>;
|
|
95
|
+
/** Tells THIS agent's model something that happened out-of-band, so it can say it aloud. */
|
|
96
|
+
NotifyModel: (note: string) => void;
|
|
97
|
+
}
|
|
98
|
+
/** What the engine tells the host synchronously when a handoff is requested. */
|
|
99
|
+
export type HandoffStartResult = {
|
|
100
|
+
Ok: true;
|
|
101
|
+
Status: 'offered' | 'dialing' | 'agent-joining';
|
|
102
|
+
} | {
|
|
103
|
+
Ok: false;
|
|
104
|
+
Error: string;
|
|
105
|
+
};
|
|
106
|
+
/** Delivers a new offer to the person it was made to, outside the live subscription (in-app notification, email). */
|
|
107
|
+
export interface IHandoffNotifier {
|
|
108
|
+
NotifyOffer(offer: HandoffOfferView, targetUserID: string, contextUser: UserInfo, provider: IMetadataProvider): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
/** Pushes offer changes to the person's open console. */
|
|
111
|
+
export interface IHandoffPublisher {
|
|
112
|
+
Publish(event: HandoffOfferEvent): void;
|
|
113
|
+
}
|
|
114
|
+
/** Whether a participant is currently in a room. */
|
|
115
|
+
export interface IRoomPresence {
|
|
116
|
+
IsParticipantPresent(roomName: string, identity: string): Promise<boolean>;
|
|
117
|
+
}
|
|
118
|
+
/** What a dial-out into the room needs. */
|
|
119
|
+
export interface DialIntoRoomRequest {
|
|
120
|
+
RoomName: string;
|
|
121
|
+
Number: string;
|
|
122
|
+
ParticipantIdentity: string;
|
|
123
|
+
DisplayName?: string;
|
|
124
|
+
/** Caller ID / outbound from number (overrides default outbound from number). */
|
|
125
|
+
FromNumber?: string;
|
|
126
|
+
/** Seconds to let the number ring. */
|
|
127
|
+
RingTimeoutSeconds?: number;
|
|
128
|
+
}
|
|
129
|
+
/** Dials a phone number into a room as a participant. */
|
|
130
|
+
export interface IRoomDialer {
|
|
131
|
+
DialIntoRoom(request: DialIntoRoomRequest): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
/** Asks the host to put an AI agent into the room, either to take a conversation over or to start one. */
|
|
134
|
+
export interface StartRoomAgentRequest {
|
|
135
|
+
RoomName: string;
|
|
136
|
+
/** The agent the caller is to talk to (the persona; the host resolves the voice front-end that speaks as it). */
|
|
137
|
+
AgentID: string;
|
|
138
|
+
AgentName: string;
|
|
139
|
+
/** When taking over: what the agent that is leaving says about the conversation. Absent when starting a conversation. */
|
|
140
|
+
Brief?: string;
|
|
141
|
+
/** When taking over: the agent that is handing over. */
|
|
142
|
+
PreviousAgentName?: string;
|
|
143
|
+
CallerLabel: string;
|
|
144
|
+
ContextUser: UserInfo;
|
|
145
|
+
Provider: IMetadataProvider;
|
|
146
|
+
/** Optional per-session realtime model override (a developer's choice in the Meet UI). */
|
|
147
|
+
RealtimeModelID?: string;
|
|
148
|
+
/** Optional per-session voice override. */
|
|
149
|
+
RealtimeVoice?: string;
|
|
150
|
+
}
|
|
151
|
+
/** Handoff lifecycle event payload. */
|
|
152
|
+
export interface RoomHandoffEvent {
|
|
153
|
+
RoomName: string;
|
|
154
|
+
EventType: 'Offered' | 'Accepted' | 'Declined' | 'Transferred' | 'Escalated';
|
|
155
|
+
ActorUserID?: string;
|
|
156
|
+
ActorAgentID?: string;
|
|
157
|
+
Details?: Record<string, unknown>;
|
|
158
|
+
ContextUser?: UserInfo;
|
|
159
|
+
Provider?: IMetadataProvider;
|
|
160
|
+
}
|
|
161
|
+
/** Observer for handoff lifecycle events (offered, accepted, declined, transferred, escalated). */
|
|
162
|
+
export interface IRoomHandoffObserver {
|
|
163
|
+
OnHandoffEvent?: (event: RoomHandoffEvent) => void | Promise<void>;
|
|
164
|
+
}
|
|
165
|
+
/** What the host reports back once the agent is in the room. */
|
|
166
|
+
export interface StartedRoomAgent {
|
|
167
|
+
/** The `MJ: AI Agent Session Bridges` row id (use it to stop that agent). */
|
|
168
|
+
SessionBridgeID: string;
|
|
169
|
+
}
|
|
170
|
+
/** Puts an AI agent into the room (the host owns the realtime session, tools and capacity for it). */
|
|
171
|
+
export type RoomAgentStarter = (request: StartRoomAgentRequest) => Promise<StartedRoomAgent>;
|
|
172
|
+
//# sourceMappingURL=handoff-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-types.d.ts","sourceRoot":"","sources":["../../src/room-handoff/handoff-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared types for bringing a person (or another agent) into a LiveKit room conversation.
|
|
3
|
+
*
|
|
4
|
+
* A **handoff** moves a conversation from the AI agent that is in a room to someone else, without the caller
|
|
5
|
+
* leaving the room: a person at an Explorer console (who is first OFFERED the conversation and may accept or
|
|
6
|
+
* decline), a phone number the room dials out to, or another AI agent. The caller stays in the room throughout;
|
|
7
|
+
* only the AI agent leaves, and only once the new party is actually present.
|
|
8
|
+
*
|
|
9
|
+
* The types here are the engine's vocabulary. Where a destination comes from (a named entry in the operator's
|
|
10
|
+
* transfer directory, a user looked up by email) is the caller's concern: by the time a request reaches the engine
|
|
11
|
+
* the destination is already resolved to an id or a validated number.
|
|
12
|
+
*
|
|
13
|
+
* @module @memberjunction/livekit-room-server
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=handoff-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-types.js","sourceRoot":"","sources":["../../src/room-handoff/handoff-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,149 @@
|
|
|
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 { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
28
|
+
import { BaseSingleton } from '@memberjunction/global';
|
|
29
|
+
import type { HandoffOfferView, HandoffRequest, HandoffStartResult, IHandoffNotifier, IHandoffPublisher, IRoomDialer, IRoomHandoffObserver, IRoomPresence, RoomAgentStarter, RoomHandoffAgentContext, RoomHandoffEvent } from './handoff-types.js';
|
|
30
|
+
/** The tool the AI calls after briefing the new party, to say it is done and can leave. */
|
|
31
|
+
export declare const FINISH_HANDOFF_TOOL = "finish_handoff";
|
|
32
|
+
/** How long a person who accepted an offer has to actually appear in the room. */
|
|
33
|
+
export declare const HANDOFF_JOIN_WAIT_MS = 90000;
|
|
34
|
+
/** How often the room is checked for the new party. */
|
|
35
|
+
export declare const HANDOFF_PRESENCE_POLL_MS = 1000;
|
|
36
|
+
/** The longest the AI is given to brief the new party before it is removed anyway. */
|
|
37
|
+
export declare const HANDOFF_BRIEF_MAX_MS = 45000;
|
|
38
|
+
/** How long the AI's last words are given to play after it calls {@link FINISH_HANDOFF_TOOL}. */
|
|
39
|
+
export declare const HANDOFF_LEAVE_SETTLE_MS = 3000;
|
|
40
|
+
/** How long after a blind handoff's new party appears the AI leaves. */
|
|
41
|
+
export declare const HANDOFF_BLIND_LEAVE_DELAY_MS = 1500;
|
|
42
|
+
/** How long a number the room dials is allowed to ring. */
|
|
43
|
+
export declare const HANDOFF_DIAL_RING_SECONDS = 30;
|
|
44
|
+
/** The longest summary kept (it is shown on the offer and given to a taking-over agent). */
|
|
45
|
+
export declare const MAX_HANDOFF_SUMMARY_CHARS = 600;
|
|
46
|
+
/** The collaborators the engine uses. All optional: a handoff kind whose collaborator is missing is refused clearly. */
|
|
47
|
+
export interface RoomHandoffDeps {
|
|
48
|
+
Presence?: IRoomPresence;
|
|
49
|
+
Dialer?: IRoomDialer;
|
|
50
|
+
Notifier?: IHandoffNotifier;
|
|
51
|
+
Publisher?: IHandoffPublisher;
|
|
52
|
+
AgentStarter?: RoomAgentStarter;
|
|
53
|
+
Observer?: IRoomHandoffObserver;
|
|
54
|
+
}
|
|
55
|
+
/** Brings a person, a number or another agent into a room conversation and takes the AI out. */
|
|
56
|
+
export declare class RoomHandoffEngine extends BaseSingleton<RoomHandoffEngine> {
|
|
57
|
+
private deps;
|
|
58
|
+
private readonly flows;
|
|
59
|
+
private readonly registeredObservers;
|
|
60
|
+
private nextFlowID;
|
|
61
|
+
protected constructor();
|
|
62
|
+
/** The process-wide engine. */
|
|
63
|
+
static get Instance(): RoomHandoffEngine;
|
|
64
|
+
/** Sets (merges) the collaborators. Called once at startup by the host that owns each one. */
|
|
65
|
+
Configure(deps: RoomHandoffDeps): void;
|
|
66
|
+
/** Registers an observer for handoff lifecycle events without replacing the primary collaborator. */
|
|
67
|
+
RegisterObserver(observer: IRoomHandoffObserver): {
|
|
68
|
+
Unregister: () => void;
|
|
69
|
+
};
|
|
70
|
+
/** The collaborators currently set (a `Pick` for diagnostics; tests read it). */
|
|
71
|
+
get Deps(): Readonly<RoomHandoffDeps>;
|
|
72
|
+
/** Drops every flow and every collaborator (tests, shutdown). */
|
|
73
|
+
Reset(): void;
|
|
74
|
+
/** Emits a handoff event to all registered observers and the primary observer. */
|
|
75
|
+
EmitHandoffEvent(event: RoomHandoffEvent): void;
|
|
76
|
+
private emitHandoffEvent;
|
|
77
|
+
/**
|
|
78
|
+
* Starts handing the conversation over. Returns at once; what happens next is reported to the model through
|
|
79
|
+
* {@link RoomHandoffAgentContext.NotifyModel}.
|
|
80
|
+
*/
|
|
81
|
+
RequestHandoff(agent: RoomHandoffAgentContext, request: HandoffRequest): Promise<HandoffStartResult>;
|
|
82
|
+
/** The AI says it has finished briefing and is ready to leave. Returns whether a handoff was waiting for that. */
|
|
83
|
+
AgentReadyToLeave(roomName: string): boolean;
|
|
84
|
+
/** Whether a handoff is in progress for the room. */
|
|
85
|
+
HasHandoff(roomName: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The room's call ended or the agent left for another reason: abandon its handoff and withdraw its offer. A flow
|
|
88
|
+
* that is already leaving is finished, not cancelled.
|
|
89
|
+
*/
|
|
90
|
+
CancelRoom(roomName: string): void;
|
|
91
|
+
/** The offers to show a person (pending ones and recently resolved ones). */
|
|
92
|
+
ListOffersForUser(userID: string, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<HandoffOfferView[]>;
|
|
93
|
+
/**
|
|
94
|
+
* A person accepts an offer. Authorised by the offer's target; anything else answers as a missing offer. On success
|
|
95
|
+
* the console should join the room; the engine watches for them and takes the AI out once they are there.
|
|
96
|
+
*/
|
|
97
|
+
AcceptOffer(offerID: string, userID: string, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<{
|
|
98
|
+
Ok: true;
|
|
99
|
+
Offer: HandoffOfferView;
|
|
100
|
+
} | {
|
|
101
|
+
Ok: false;
|
|
102
|
+
Reason: string;
|
|
103
|
+
}>;
|
|
104
|
+
/** A person declines an offer. Authorised the same way as {@link AcceptOffer}. */
|
|
105
|
+
DeclineOffer(offerID: string, userID: string, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<{
|
|
106
|
+
Ok: true;
|
|
107
|
+
} | {
|
|
108
|
+
Ok: false;
|
|
109
|
+
Reason: string;
|
|
110
|
+
}>;
|
|
111
|
+
/**
|
|
112
|
+
* Handles an offer update forwarded from another cluster instance via cross-instance pub/sub.
|
|
113
|
+
*/
|
|
114
|
+
OnRemoteOfferChange(payload: {
|
|
115
|
+
UserID: string;
|
|
116
|
+
Kind: string;
|
|
117
|
+
Offer: HandoffOfferView;
|
|
118
|
+
}): void;
|
|
119
|
+
/** Checks the request and that the collaborators its kind needs are present. */
|
|
120
|
+
private prepare;
|
|
121
|
+
private begin;
|
|
122
|
+
private offerToUser;
|
|
123
|
+
private onOfferTimeout;
|
|
124
|
+
private waitForUserToJoin;
|
|
125
|
+
/** Dials a number into the room and waits for it to appear. Used for a number target and for a person's fallback. */
|
|
126
|
+
private dialAndAwait;
|
|
127
|
+
private startAgent;
|
|
128
|
+
/** The person did not take it. Fall back to their phone when one is configured, otherwise tell the model. */
|
|
129
|
+
private onPartyUnavailable;
|
|
130
|
+
/** The handoff failed for good: tell the model so it can tell the caller, and let the call carry on with the AI. */
|
|
131
|
+
private finishUnavailable;
|
|
132
|
+
/** The new party is in the room. Blind: the AI leaves. Warm: the AI briefs them, then leaves. */
|
|
133
|
+
private onPartyPresent;
|
|
134
|
+
/** Takes the AI out of the room. The flow is removed first, so the agent's own teardown does not read as a cancellation. */
|
|
135
|
+
private leave;
|
|
136
|
+
/** Checks the room for a participant until it is there, the flow is cancelled, or the time is up. */
|
|
137
|
+
private pollPresence;
|
|
138
|
+
private isPresent;
|
|
139
|
+
private notify;
|
|
140
|
+
private publishUpdate;
|
|
141
|
+
private publish;
|
|
142
|
+
private flowForOffer;
|
|
143
|
+
private removeFlow;
|
|
144
|
+
/** Stops a flow's timers and withdraws its offer. */
|
|
145
|
+
private cancelFlow;
|
|
146
|
+
private armTimer;
|
|
147
|
+
private clearTimers;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=room-handoff-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-handoff-engine.d.ts","sourceRoot":"","sources":["../../src/room-handoff/room-handoff-engine.ts"],"names":[],"mappings":"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"}
|