@convai/web-sdk 1.7.0-beta.0 → 1.7.0-beta.1
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 +40 -6
- package/dist/core/ConvaiClient.d.ts +1 -31
- package/dist/core/ConvaiClient.d.ts.map +1 -1
- package/dist/core/ConvaiClient.js +8 -200
- package/dist/core/ConvaiClient.js.map +1 -1
- package/dist/core/MessageHandler.d.ts.map +1 -1
- package/dist/core/MessageHandler.js +4 -26
- package/dist/core/MessageHandler.js.map +1 -1
- package/dist/core/connectRequest.d.ts +2 -2
- package/dist/core/connectRequest.js +3 -3
- package/dist/core/connectRequest.js.map +1 -1
- package/dist/core/types.d.ts +9 -163
- package/dist/core/types.d.ts.map +1 -1
- package/dist/react/hooks/useConvaiClient.d.ts.map +1 -1
- package/dist/react/hooks/useConvaiClient.js +0 -3
- package/dist/react/hooks/useConvaiClient.js.map +1 -1
- package/dist/vanilla/types.d.ts +2 -2
- package/dist/vanilla/types.d.ts.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/package.json +6 -5
- package/dist/core/CharacterRoster.d.ts +0 -68
- package/dist/core/CharacterRoster.d.ts.map +0 -1
- package/dist/core/CharacterRoster.js +0 -235
- package/dist/core/CharacterRoster.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Real-time conversational AI characters for the web.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@convai/web-sdk)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
|
|
@@ -10,14 +10,18 @@ TypeScript-first SDK for embedding Convai AI characters into React and vanilla J
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## What's new in 1.
|
|
13
|
+
## What's new in 1.7.0
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- **Character state of mind** — set a temporary generation mood with the `stateOfMind` config option, and change it mid-session with `updateEmotion()` without triggering a response. [Usage below.](#character-state-of-mind)
|
|
16
|
+
- **Send-ahead enabled by default** — NeuroSync lipsync ahead-delivery is now on by default, reversing the 1.6.0 opt-in. Fall back to the legacy paced path with `blendshapeConfig.deliver_chunks_ahead: false`.
|
|
17
|
+
- **Lipsync naturalness pipeline** — modular naturalness processing with a tuned MetaHuman profile.
|
|
18
|
+
- **Adaptive glass widget styling** — `ConvaiWidget` adapts to light and dark backgrounds.
|
|
19
|
+
|
|
20
|
+
### Previously in 1.6.0
|
|
16
21
|
|
|
17
22
|
- **Narrative Design template keys** — personalize one narrative graph per session: seed values at connect with the `narrativeTemplateKeys` config option, replace them mid-session with `updateTemplateKeys()`. [Usage below.](#narrative-design-template-keys)
|
|
18
23
|
- **Typed parameterized actions** — `actionResponse` is now typed via the exported `ConvaiAction` / `ActionResponseEvent`, including the `target` of parameterized actions. [Usage below.](#actions)
|
|
19
24
|
- **Vision dynamic context** — camera, screen, canvas, and custom tracks feed unified vision context on WebRTC, with hardened WebSocket vision handling. [Usage below.](#vision-dynamic-context-beta)
|
|
20
|
-
- **Send-ahead disabled by default** — lipsync send-ahead is now opt-in.
|
|
21
25
|
|
|
22
26
|
---
|
|
23
27
|
|
|
@@ -26,7 +30,7 @@ TypeScript-first SDK for embedding Convai AI characters into React and vanilla J
|
|
|
26
30
|
- **React & vanilla JS** — `useConvaiClient` hook, `ConvaiWidget`, and a framework-agnostic core
|
|
27
31
|
- **Real-time audio/video** — full-duplex WebRTC with echo cancellation, camera, and screen share
|
|
28
32
|
- **Lipsync** — ARKit and MetaHuman blendshape streams for facial animation
|
|
29
|
-
- **Emotions** — per-turn emotion detection with intensity scale
|
|
33
|
+
- **Emotions & state of mind** — per-turn emotion detection with intensity scale, plus a settable generation mood
|
|
30
34
|
- **Dynamic context & vision** — inject text state, scene metadata, and LiveKit video frames mid-session
|
|
31
35
|
- **Actions & Narrative Design** — typed action decisions with parameterized targets, named triggers, and per-session template keys
|
|
32
36
|
- **Long-term memory** — persistent cross-session memories scoped to each end user
|
|
@@ -101,7 +105,7 @@ Full documentation is at **<a href="https://docs.convai.com/api-docs/plugins-and
|
|
|
101
105
|
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk" target="_blank" rel="noopener noreferrer">Vanilla JS</a> | `ConvaiClient`, `createConvaiWidget`, and audio setup |
|
|
102
106
|
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk/event-reference" target="_blank" rel="noopener noreferrer">Events</a> | Full event reference — `botReady`, `stateChange`, `messagesChange`, `interactionCreated`, and more |
|
|
103
107
|
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk/dynamic-context" target="_blank" rel="noopener noreferrer">Context Management</a> | Dynamic context, `updateContext`, file upload, session management |
|
|
104
|
-
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk/emotions" target="_blank" rel="noopener noreferrer">Emotions</a> | Per-turn emotion detection
|
|
108
|
+
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk/emotions" target="_blank" rel="noopener noreferrer">Emotions</a> | Per-turn emotion detection, provider options, and `stateOfMind` / `updateEmotion()` |
|
|
105
109
|
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk" target="_blank" rel="noopener noreferrer">Lipsync</a> | ARKit / MetaHuman blendshape streams and `BlendshapeQueue` API |
|
|
106
110
|
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk/actions" target="_blank" rel="noopener noreferrer">Actions</a> | Trigger character behaviors and scene actions |
|
|
107
111
|
| <a href="https://docs.convai.com/api-docs/plugins-and-integrations/web-plugins/convai-web-sdk/long-term-memory" target="_blank" rel="noopener noreferrer">Memory</a> | Long-term memory scoped to end users |
|
|
@@ -236,6 +240,36 @@ Requires Narrative Design on the character; `updateTemplateKeys` is a full repla
|
|
|
236
240
|
|
|
237
241
|
---
|
|
238
242
|
|
|
243
|
+
## Character state of mind
|
|
244
|
+
|
|
245
|
+
Set a temporary generation mood that shapes tone and pacing for the next response. This is separate from `enableEmotion`, which reports the character's detected emotion *after* a turn.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
const client = new ConvaiClient({
|
|
249
|
+
apiKey: "...",
|
|
250
|
+
characterId: "...",
|
|
251
|
+
stateOfMind: "anticipation",
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Mid-session. Affects the next response; does not trigger one.
|
|
255
|
+
client.updateEmotion("joy");
|
|
256
|
+
client.updateEmotion(null); // clear — "neutral" and "" clear it too
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Values are trimmed and lowercased. The runtime value carries into the next connect, including a reconnect; an explicit `stateOfMind` in the connect config takes precedence.
|
|
260
|
+
|
|
261
|
+
Requires backend support — live on production as of 2026-08-20. On a backend without it, the server replies with an `Unknown message type` error on `serverResponse`. Because `/connect` silently ignores unknown fields, a successful connect alone does not prove `state_of_mind` was applied, so watch the ack:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
client.on("serverResponse", (r) => {
|
|
265
|
+
if (r.event_type === "update-emotion" && r.status !== "success") {
|
|
266
|
+
console.warn("state of mind unsupported by this backend:", r.message);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
239
273
|
## License
|
|
240
274
|
|
|
241
275
|
Licensed under the [Apache License 2.0](./LICENSE). Copyright 2025 Convai.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Room } from "livekit-client";
|
|
2
|
-
import { ConvaiConfig, ConvaiClientState, ChatMessage, IConvaiClient, AudioControls, VideoControls, ScreenShareControls, DynamicInfo, ContextUpdateOptions, UploadFileOptions, WebSocketSessionFactory, RespondModeUpdateOptions, UpdateSceneMetadataOptions, VisionStatusOptions, VisionTriggerOptions
|
|
2
|
+
import { ConvaiConfig, ConvaiClientState, ChatMessage, IConvaiClient, AudioControls, VideoControls, ScreenShareControls, DynamicInfo, ContextUpdateOptions, UploadFileOptions, WebSocketSessionFactory, RespondModeUpdateOptions, UpdateSceneMetadataOptions, VisionStatusOptions, VisionTriggerOptions } from "./types";
|
|
3
3
|
import { EventEmitter } from "./EventEmitter";
|
|
4
4
|
import { BlendshapeQueue } from "./BlendshapeQueue";
|
|
5
5
|
import { MemoryManager } from "./MemoryManager";
|
|
@@ -46,7 +46,6 @@ export declare class ConvaiClient extends EventEmitter implements IConvaiClient
|
|
|
46
46
|
private _apiKey;
|
|
47
47
|
private _authToken;
|
|
48
48
|
private _characterId;
|
|
49
|
-
private _speakerId;
|
|
50
49
|
private _characterSessionId;
|
|
51
50
|
private _isBotReady;
|
|
52
51
|
private _participantSid;
|
|
@@ -57,11 +56,6 @@ export declare class ConvaiClient extends EventEmitter implements IConvaiClient
|
|
|
57
56
|
* so updateEmotion() called before any config is stored is not lost.
|
|
58
57
|
*/
|
|
59
58
|
private _stateOfMind;
|
|
60
|
-
/** Roster state for multi-character rooms. Empty for single-character sessions. */
|
|
61
|
-
private _roster;
|
|
62
|
-
/** Pending setInteractionTarget/updateCharacterRoster commands, keyed by command_id. */
|
|
63
|
-
private _pendingRosterCommands;
|
|
64
|
-
private _rosterCommandSeq;
|
|
65
59
|
private _endUserId;
|
|
66
60
|
private _endUserMetadata;
|
|
67
61
|
private _wsSession;
|
|
@@ -93,7 +87,6 @@ export declare class ConvaiClient extends EventEmitter implements IConvaiClient
|
|
|
93
87
|
get apiKey(): string | null;
|
|
94
88
|
get authToken(): string | null;
|
|
95
89
|
get characterId(): string | null;
|
|
96
|
-
get speakerId(): string | null;
|
|
97
90
|
get room(): Room;
|
|
98
91
|
get chatMessages(): ChatMessage[];
|
|
99
92
|
get userTranscription(): string;
|
|
@@ -224,29 +217,6 @@ export declare class ConvaiClient extends EventEmitter implements IConvaiClient
|
|
|
224
217
|
* This is silent: it affects the next response and does not trigger one.
|
|
225
218
|
*/
|
|
226
219
|
updateEmotion(stateOfMind: string | null): void;
|
|
227
|
-
/** Timeout for a roster command to be acknowledged by the server. */
|
|
228
|
-
private static readonly ROSTER_COMMAND_TIMEOUT_MS;
|
|
229
|
-
/**
|
|
230
|
-
* Correlate interaction-target / character-roster-update acks back to the
|
|
231
|
-
* promise returned by the method that issued them, and keep roster state and
|
|
232
|
-
* the two roster events in sync — including for changes we did not initiate.
|
|
233
|
-
*/
|
|
234
|
-
private _handleRosterServerResponse;
|
|
235
|
-
/**
|
|
236
|
-
* Publish a roster command and resolve when its ack arrives.
|
|
237
|
-
*/
|
|
238
|
-
private _sendRosterCommand;
|
|
239
|
-
/**
|
|
240
|
-
* Route subsequent user turns to a different character instance.
|
|
241
|
-
*
|
|
242
|
-
* Retries once against the server's authoritative epoch if the routing epoch
|
|
243
|
-
* was stale, which happens when another participant switched first.
|
|
244
|
-
*/
|
|
245
|
-
setInteractionTarget(membershipId: string): Promise<ConvaiCharacterInstance>;
|
|
246
|
-
/**
|
|
247
|
-
* Add or remove character instances on a live room, without reconnecting.
|
|
248
|
-
*/
|
|
249
|
-
updateCharacterRoster(options: UpdateCharacterRosterOptions): Promise<CharacterRosterChange>;
|
|
250
220
|
/**
|
|
251
221
|
* Send descriptive scene updates. Use when environment description changes
|
|
252
222
|
* and the bot should know what is visible or nearby. Does not modify action_config.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConvaiClient.d.ts","sourceRoot":"","sources":["../../src/core/ConvaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAML,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,WAAW,EAEX,aAAa,EACb,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EAIjB,uBAAuB,EACvB,wBAAwB,EAExB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"ConvaiClient.d.ts","sourceRoot":"","sources":["../../src/core/ConvaiClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { AudioManager } from "./AudioManager";
|
|
|
5
5
|
import { VideoManager } from "./VideoManager";
|
|
6
6
|
import { ScreenShareManager } from "./ScreenShareManager";
|
|
7
7
|
import { MessageHandler } from "./MessageHandler";
|
|
8
|
-
import {
|
|
8
|
+
import { SDK_VERSION } from "../version";
|
|
9
9
|
import { EventEmitter } from "./EventEmitter";
|
|
10
10
|
import { MemoryManager } from "./MemoryManager";
|
|
11
11
|
import { ConnectionStateHandler } from "./ConnectionStateHandler";
|
|
@@ -79,7 +79,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
79
79
|
this._apiKey = null;
|
|
80
80
|
this._authToken = null;
|
|
81
81
|
this._characterId = null;
|
|
82
|
-
this._speakerId = null;
|
|
83
82
|
this._characterSessionId = "-1";
|
|
84
83
|
this._isBotReady = false;
|
|
85
84
|
this._participantSid = "";
|
|
@@ -89,11 +88,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
89
88
|
* so updateEmotion() called before any config is stored is not lost.
|
|
90
89
|
*/
|
|
91
90
|
this._stateOfMind = null;
|
|
92
|
-
/** Roster state for multi-character rooms. Empty for single-character sessions. */
|
|
93
|
-
this._roster = new CharacterRoster();
|
|
94
|
-
/** Pending setInteractionTarget/updateCharacterRoster commands, keyed by command_id. */
|
|
95
|
-
this._pendingRosterCommands = new Map();
|
|
96
|
-
this._rosterCommandSeq = 0;
|
|
97
91
|
this._endUserId = null;
|
|
98
92
|
this._endUserMetadata = null;
|
|
99
93
|
this._wsSession = null;
|
|
@@ -130,8 +124,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
130
124
|
endUserId: null,
|
|
131
125
|
endUserMetadata: null,
|
|
132
126
|
metrics: [],
|
|
133
|
-
characters: [],
|
|
134
|
-
activeMembershipId: null,
|
|
135
127
|
disconnectReason: null,
|
|
136
128
|
};
|
|
137
129
|
// Default audio settings for optimal interruption handling
|
|
@@ -174,9 +166,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
174
166
|
get characterId() {
|
|
175
167
|
return this._characterId;
|
|
176
168
|
}
|
|
177
|
-
get speakerId() {
|
|
178
|
-
return this._speakerId;
|
|
179
|
-
}
|
|
180
169
|
get room() {
|
|
181
170
|
return this._room;
|
|
182
171
|
}
|
|
@@ -220,15 +209,7 @@ export class ConvaiClient extends EventEmitter {
|
|
|
220
209
|
});
|
|
221
210
|
this._room.on(RoomEvent.ConnectionStateChanged, this._connectionStateHandler.handleConnectionStateChanged.bind(this._connectionStateHandler));
|
|
222
211
|
// Message handler events
|
|
223
|
-
this._messageHandler.on("botReady", (
|
|
224
|
-
// Each character instance sends its own bot-ready. Feed the roster
|
|
225
|
-
// before the de-dupe below, which only guards the consumer-facing event.
|
|
226
|
-
if (this._roster.applyBotReady(about)) {
|
|
227
|
-
this.updateState({
|
|
228
|
-
characters: this._roster.characters,
|
|
229
|
-
activeMembershipId: this._roster.activeMembershipId,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
212
|
+
this._messageHandler.on("botReady", () => {
|
|
232
213
|
// Server may send multiple bot-ready frames (one per client-ready
|
|
233
214
|
// we retried). Only surface the first to consumers per connect.
|
|
234
215
|
if (this._isBotReady) {
|
|
@@ -348,7 +329,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
348
329
|
this.emit("actionResponse", data);
|
|
349
330
|
});
|
|
350
331
|
this._messageHandler.on("serverResponse", (response) => {
|
|
351
|
-
this._handleRosterServerResponse(response);
|
|
352
332
|
this.emit("serverResponse", response);
|
|
353
333
|
});
|
|
354
334
|
this._messageHandler.on("interactionCreated", (data) => {
|
|
@@ -397,12 +377,8 @@ export class ConvaiClient extends EventEmitter {
|
|
|
397
377
|
* For LiveKit: publishes via the data channel.
|
|
398
378
|
* For WebSocket: sends via PipecatClient.sendClientMessage (wrapped in {t,d} envelope).
|
|
399
379
|
*/
|
|
400
|
-
publishMessage(type, data
|
|
401
|
-
|
|
402
|
-
// echoes back as extras.command_id. interaction-target REJECTS a message
|
|
403
|
-
// without it (code "invalid_command") even when the same value is present
|
|
404
|
-
// inside `data`, so the envelope field is not optional for those.
|
|
405
|
-
const message = id ? { id, type, data } : { type, data };
|
|
380
|
+
publishMessage(type, data) {
|
|
381
|
+
const message = { type, data };
|
|
406
382
|
if (this._activeTransport === "websocket" && this._wsSession?.isConnected) {
|
|
407
383
|
this._wsSession.sendMessage(type, data);
|
|
408
384
|
}
|
|
@@ -446,33 +422,15 @@ export class ConvaiClient extends EventEmitter {
|
|
|
446
422
|
this._messageHandler.setRtviMessageLogging(this._logRtviMessages);
|
|
447
423
|
const hasApiKey = Boolean(configWithDefaults.apiKey);
|
|
448
424
|
const hasAuthToken = Boolean(configWithDefaults.authToken);
|
|
449
|
-
|
|
450
|
-
const hasCharacterList = characterList.length > 0;
|
|
451
|
-
if (!hasApiKey && !hasAuthToken) {
|
|
425
|
+
if ((!hasApiKey && !hasAuthToken) || !configWithDefaults.characterId) {
|
|
452
426
|
throw new Error("Either apiKey or authToken is required, and characterId is required");
|
|
453
427
|
}
|
|
454
|
-
// Exactly one of characterId / characters — the server takes either shape,
|
|
455
|
-
// but silently ignores unknown fields, so catch the ambiguity here.
|
|
456
|
-
if (!hasCharacterList && !configWithDefaults.characterId) {
|
|
457
|
-
throw new Error("Either apiKey or authToken is required, and characterId is required");
|
|
458
|
-
}
|
|
459
|
-
if (hasCharacterList && configWithDefaults.characterId) {
|
|
460
|
-
throw new Error("Pass either characterId or characters, not both");
|
|
461
|
-
}
|
|
462
|
-
if (hasCharacterList && characterList.some((c) => !c?.characterId)) {
|
|
463
|
-
throw new Error("Every entry in characters requires a characterId");
|
|
464
|
-
}
|
|
465
428
|
this.updateState({ isConnecting: true });
|
|
466
429
|
try {
|
|
467
430
|
// Store connection config
|
|
468
431
|
this._apiKey = configWithDefaults.apiKey ?? null;
|
|
469
432
|
this._authToken = configWithDefaults.authToken ?? null;
|
|
470
|
-
this._characterId =
|
|
471
|
-
configWithDefaults.characterId ??
|
|
472
|
-
characterList[0]?.characterId ??
|
|
473
|
-
null;
|
|
474
|
-
this._roster.reset();
|
|
475
|
-
// Resolve speaker ID based on endUserId
|
|
433
|
+
this._characterId = configWithDefaults.characterId;
|
|
476
434
|
// Determine connection type based on enableVideo
|
|
477
435
|
const connType = configWithDefaults.enableVideo ? "video" : "audio";
|
|
478
436
|
this._connectionType = connType;
|
|
@@ -488,13 +446,7 @@ export class ConvaiClient extends EventEmitter {
|
|
|
488
446
|
this._stateOfMind = stateOfMind;
|
|
489
447
|
const characterSessionIdToSend = configWithDefaults.characterSessionId ?? this._characterSessionId;
|
|
490
448
|
const requestBody = {
|
|
491
|
-
|
|
492
|
-
? {
|
|
493
|
-
characters: characterList.map((c) => ({
|
|
494
|
-
character_id: c.characterId,
|
|
495
|
-
})),
|
|
496
|
-
}
|
|
497
|
-
: { character_id: configWithDefaults.characterId }),
|
|
449
|
+
character_id: configWithDefaults.characterId,
|
|
498
450
|
...(stateOfMind ? { state_of_mind: stateOfMind } : {}),
|
|
499
451
|
...(configWithDefaults.endUserId && {
|
|
500
452
|
end_user_id: configWithDefaults.endUserId,
|
|
@@ -563,7 +515,7 @@ export class ConvaiClient extends EventEmitter {
|
|
|
563
515
|
invocation_metadata: {
|
|
564
516
|
source: configWithDefaults.invocationMetadata?.source ?? "web_sdk",
|
|
565
517
|
client_version: configWithDefaults.invocationMetadata?.clientVersion ??
|
|
566
|
-
|
|
518
|
+
SDK_VERSION,
|
|
567
519
|
...(configWithDefaults.invocationMetadata?.extraMetadata && {
|
|
568
520
|
extra_metadata: configWithDefaults.invocationMetadata.extraMetadata,
|
|
569
521
|
}),
|
|
@@ -621,14 +573,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
621
573
|
characterSessionId: connectionData.character_session_id,
|
|
622
574
|
};
|
|
623
575
|
}
|
|
624
|
-
// Seed the roster before the transport comes up, so the first bot-ready
|
|
625
|
-
// and any early roster change already have instances to match against.
|
|
626
|
-
if (this._roster.applyConnectResponse(connectionData)) {
|
|
627
|
-
this.updateState({
|
|
628
|
-
characters: this._roster.characters,
|
|
629
|
-
activeMembershipId: this._roster.activeMembershipId,
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
576
|
if (connectionData.end_user_id) {
|
|
633
577
|
this._endUserId = connectionData.end_user_id;
|
|
634
578
|
}
|
|
@@ -911,7 +855,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
911
855
|
this._apiKey = null;
|
|
912
856
|
this._authToken = null;
|
|
913
857
|
this._characterId = null;
|
|
914
|
-
this._speakerId = null;
|
|
915
858
|
this._endUserId = null;
|
|
916
859
|
this._endUserMetadata = null;
|
|
917
860
|
this._memoryManager = null; // Clear memory manager on disconnect
|
|
@@ -1187,139 +1130,6 @@ export class ConvaiClient extends EventEmitter {
|
|
|
1187
1130
|
participant_sid: this._participantSid || this._room.localParticipant?.sid,
|
|
1188
1131
|
});
|
|
1189
1132
|
}
|
|
1190
|
-
/**
|
|
1191
|
-
* Correlate interaction-target / character-roster-update acks back to the
|
|
1192
|
-
* promise returned by the method that issued them, and keep roster state and
|
|
1193
|
-
* the two roster events in sync — including for changes we did not initiate.
|
|
1194
|
-
*/
|
|
1195
|
-
_handleRosterServerResponse(response) {
|
|
1196
|
-
const { event_type: eventType, extras } = response;
|
|
1197
|
-
if (eventType !== "interaction-target" &&
|
|
1198
|
-
eventType !== "character-roster-update") {
|
|
1199
|
-
return;
|
|
1200
|
-
}
|
|
1201
|
-
// Always adopt the server's epochs, including from errors — a
|
|
1202
|
-
// stale_route_epoch rejection carries the authoritative value.
|
|
1203
|
-
const commandId = extras?.command_id;
|
|
1204
|
-
const pending = commandId
|
|
1205
|
-
? this._pendingRosterCommands.get(commandId)
|
|
1206
|
-
: undefined;
|
|
1207
|
-
if (response.status === "error") {
|
|
1208
|
-
this._roster.adoptEpochs(extras ?? null);
|
|
1209
|
-
this.updateState({
|
|
1210
|
-
characters: this._roster.characters,
|
|
1211
|
-
activeMembershipId: this._roster.activeMembershipId,
|
|
1212
|
-
});
|
|
1213
|
-
if (pending && commandId) {
|
|
1214
|
-
this._pendingRosterCommands.delete(commandId);
|
|
1215
|
-
clearTimeout(pending.timer);
|
|
1216
|
-
pending.reject(Object.assign(new Error(response.message ?? `${eventType} was rejected by the server`), { code: extras?.code ?? null, extras: extras ?? null }));
|
|
1217
|
-
}
|
|
1218
|
-
return;
|
|
1219
|
-
}
|
|
1220
|
-
let result;
|
|
1221
|
-
if (eventType === "interaction-target") {
|
|
1222
|
-
result = this._roster.applyInteractionTarget(extras ?? null);
|
|
1223
|
-
this.updateState({
|
|
1224
|
-
characters: this._roster.characters,
|
|
1225
|
-
activeMembershipId: this._roster.activeMembershipId,
|
|
1226
|
-
});
|
|
1227
|
-
if (result)
|
|
1228
|
-
this.emit("activeCharacterChange", result);
|
|
1229
|
-
}
|
|
1230
|
-
else {
|
|
1231
|
-
result = this._roster.applyRosterUpdate(extras ?? null);
|
|
1232
|
-
this.updateState({
|
|
1233
|
-
characters: this._roster.characters,
|
|
1234
|
-
activeMembershipId: this._roster.activeMembershipId,
|
|
1235
|
-
});
|
|
1236
|
-
if (result)
|
|
1237
|
-
this.emit("rosterChange", result);
|
|
1238
|
-
}
|
|
1239
|
-
if (pending && commandId) {
|
|
1240
|
-
this._pendingRosterCommands.delete(commandId);
|
|
1241
|
-
clearTimeout(pending.timer);
|
|
1242
|
-
pending.resolve(result);
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* Publish a roster command and resolve when its ack arrives.
|
|
1247
|
-
*/
|
|
1248
|
-
_sendRosterCommand(type, build) {
|
|
1249
|
-
if (!this.isTransportReady()) {
|
|
1250
|
-
return Promise.reject(new Error(`Cannot send ${type}: not connected`));
|
|
1251
|
-
}
|
|
1252
|
-
if (!this._roster.isMultiCharacter) {
|
|
1253
|
-
return Promise.reject(new Error(`Cannot send ${type}: this session was not created with a characters array`));
|
|
1254
|
-
}
|
|
1255
|
-
const commandId = `${type}-${++this._rosterCommandSeq}`;
|
|
1256
|
-
return new Promise((resolve, reject) => {
|
|
1257
|
-
const timer = setTimeout(() => {
|
|
1258
|
-
this._pendingRosterCommands.delete(commandId);
|
|
1259
|
-
reject(new Error(`${type} timed out waiting for a server response`));
|
|
1260
|
-
}, ConvaiClient.ROSTER_COMMAND_TIMEOUT_MS);
|
|
1261
|
-
this._pendingRosterCommands.set(commandId, { resolve, reject, timer });
|
|
1262
|
-
this.publishMessage(type, build(commandId), commandId);
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
/**
|
|
1266
|
-
* Route subsequent user turns to a different character instance.
|
|
1267
|
-
*
|
|
1268
|
-
* Retries once against the server's authoritative epoch if the routing epoch
|
|
1269
|
-
* was stale, which happens when another participant switched first.
|
|
1270
|
-
*/
|
|
1271
|
-
async setInteractionTarget(membershipId) {
|
|
1272
|
-
if (!membershipId) {
|
|
1273
|
-
throw new Error("setInteractionTarget requires a membershipId");
|
|
1274
|
-
}
|
|
1275
|
-
if (this._roster.isMultiCharacter && !this._roster.find(membershipId)) {
|
|
1276
|
-
throw new Error(`Unknown membershipId "${membershipId}". Address instances by membershipId, not characterId.`);
|
|
1277
|
-
}
|
|
1278
|
-
const send = () => this._sendRosterCommand("interaction-target", (commandId) => this._roster.buildInteractionTarget(membershipId, commandId));
|
|
1279
|
-
try {
|
|
1280
|
-
await send();
|
|
1281
|
-
}
|
|
1282
|
-
catch (error) {
|
|
1283
|
-
const code = error?.code;
|
|
1284
|
-
if (code !== "stale_route_epoch")
|
|
1285
|
-
throw error;
|
|
1286
|
-
// The roster adopted the server's epoch when the error came in, so a
|
|
1287
|
-
// single retry is now fenced correctly.
|
|
1288
|
-
await send();
|
|
1289
|
-
}
|
|
1290
|
-
const instance = this._roster.find(membershipId);
|
|
1291
|
-
if (!instance) {
|
|
1292
|
-
throw new Error(`interaction-target succeeded but membership "${membershipId}" is not in the roster`);
|
|
1293
|
-
}
|
|
1294
|
-
return instance;
|
|
1295
|
-
}
|
|
1296
|
-
/**
|
|
1297
|
-
* Add or remove character instances on a live room, without reconnecting.
|
|
1298
|
-
*/
|
|
1299
|
-
async updateCharacterRoster(options) {
|
|
1300
|
-
const add = options?.add ?? [];
|
|
1301
|
-
const remove = options?.remove ?? [];
|
|
1302
|
-
if (add.length === 0 && remove.length === 0) {
|
|
1303
|
-
throw new Error("updateCharacterRoster requires at least one add or remove");
|
|
1304
|
-
}
|
|
1305
|
-
if (add.some((c) => !c?.characterId)) {
|
|
1306
|
-
throw new Error("Every entry in add requires a characterId");
|
|
1307
|
-
}
|
|
1308
|
-
// The server rejects removing the active instance without a replacement
|
|
1309
|
-
// (`replacement_target_required`), and rejects one that is not ready yet
|
|
1310
|
-
// (`replacement_target_unavailable`). Choose a ready survivor by default.
|
|
1311
|
-
const active = this._roster.activeMembershipId;
|
|
1312
|
-
const effective = !options.replacementTarget && active && remove.includes(active)
|
|
1313
|
-
? { ...options, replacementTarget: this._roster.pickReplacement(remove) }
|
|
1314
|
-
: options;
|
|
1315
|
-
const result = (await this._sendRosterCommand("character-roster-update", (commandId) => this._roster.buildRosterUpdate(effective, commandId)));
|
|
1316
|
-
// A success ack that moved nothing still resolves; report the roster as-is.
|
|
1317
|
-
return (result ?? {
|
|
1318
|
-
added: [],
|
|
1319
|
-
removed: [],
|
|
1320
|
-
characters: this._roster.characters,
|
|
1321
|
-
});
|
|
1322
|
-
}
|
|
1323
1133
|
/**
|
|
1324
1134
|
* Send descriptive scene updates. Use when environment description changes
|
|
1325
1135
|
* and the bot should know what is visible or nearby. Does not modify action_config.
|
|
@@ -1405,6 +1215,4 @@ export class ConvaiClient extends EventEmitter {
|
|
|
1405
1215
|
}
|
|
1406
1216
|
ConvaiClient.CLIENT_READY_RETRY_MS = 500;
|
|
1407
1217
|
ConvaiClient.CLIENT_READY_TIMEOUT_MS = 45000;
|
|
1408
|
-
/** Timeout for a roster command to be acknowledged by the server. */
|
|
1409
|
-
ConvaiClient.ROSTER_COMMAND_TIMEOUT_MS = 10000;
|
|
1410
1218
|
//# sourceMappingURL=ConvaiClient.js.map
|