@nuancelabs/js-sdk 0.5.0 → 0.9.0
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/index.d.ts +22 -3
- package/index.js +66 -14
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -212,6 +212,8 @@ export declare type ConversationEvent =
|
|
|
212
212
|
* Emitted only while waiting. `estimatedWaitSeconds` never increases for a
|
|
213
213
|
* given session: a wait that grows reads as the service failing, and arriving
|
|
214
214
|
* early is forgiven. Null when there is no serving capacity to estimate from.
|
|
215
|
+
* `preparing` is true once the session is next and an avatar is held for it
|
|
216
|
+
* while it gets ready; the session connects when it is.
|
|
215
217
|
*/
|
|
216
218
|
/**
|
|
217
219
|
* How long the live session has left, when it is capped.
|
|
@@ -229,16 +231,20 @@ export declare type ConversationEvent =
|
|
|
229
231
|
* A runtime that stops at its limit does not necessarily leave the transport,
|
|
230
232
|
* so a caller cannot infer this from the connection alone. `reason` is
|
|
231
233
|
* `"time-limit"` when the session was capped and ran out its clock,
|
|
232
|
-
* `"policy-violation"` when the runtime ended it for content
|
|
234
|
+
* `"policy-violation"` when the runtime ended it for content, `"refused"`
|
|
235
|
+
* when the runtime would not start it, with its reason in `message` when it
|
|
236
|
+
* gave one.
|
|
233
237
|
*/
|
|
234
238
|
| {
|
|
235
239
|
type: "session-ended";
|
|
236
240
|
reason: SessionEndReason;
|
|
241
|
+
message?: string;
|
|
237
242
|
} | {
|
|
238
243
|
type: "queue-changed";
|
|
239
244
|
position: number;
|
|
240
245
|
estimatedWaitSeconds: number | null;
|
|
241
246
|
poolSlots: number | null;
|
|
247
|
+
preparing: boolean;
|
|
242
248
|
};
|
|
243
249
|
|
|
244
250
|
/**
|
|
@@ -338,6 +344,12 @@ export declare interface CreateNuanceConversationOptions {
|
|
|
338
344
|
* ```
|
|
339
345
|
*/
|
|
340
346
|
personality?: PersonalityChoice;
|
|
347
|
+
/**
|
|
348
|
+
* The longest the conversation may run, in seconds. The server holds it to
|
|
349
|
+
* the account's maximum, so a longer value runs for that maximum; left out,
|
|
350
|
+
* the conversation runs for the maximum.
|
|
351
|
+
*/
|
|
352
|
+
maxSessionSeconds?: number;
|
|
341
353
|
/**
|
|
342
354
|
* Capture constraints for the user's camera.
|
|
343
355
|
*
|
|
@@ -444,9 +456,10 @@ export declare class PolicyCurfewError extends Error {
|
|
|
444
456
|
/**
|
|
445
457
|
* Why a session is over. `"time-limit"`: the capped session ran out its clock.
|
|
446
458
|
* `"policy-violation"`: the runtime ended it for content that breaks the usage
|
|
447
|
-
* policy. `"
|
|
459
|
+
* policy. `"refused"`: the runtime would not start it, for the reason in the
|
|
460
|
+
* event's `message`. `"ended"`: any other server-side end.
|
|
448
461
|
*/
|
|
449
|
-
export declare type SessionEndReason = "time-limit" | "ended" | "policy-violation" | "connection-lost";
|
|
462
|
+
export declare type SessionEndReason = "time-limit" | "ended" | "policy-violation" | "refused" | "connection-lost";
|
|
450
463
|
|
|
451
464
|
|
|
452
465
|
|
|
@@ -458,6 +471,12 @@ export declare interface SessionPersonality {
|
|
|
458
471
|
* before a call, in plain text.
|
|
459
472
|
*/
|
|
460
473
|
system_prompt?: string;
|
|
474
|
+
/**
|
|
475
|
+
* The face the avatar is drawn as, by the id Nuance gave your organization.
|
|
476
|
+
* Leave it out for the default face. A face your organization has not been
|
|
477
|
+
* given is refused when the token is minted.
|
|
478
|
+
*/
|
|
479
|
+
face_id?: string;
|
|
461
480
|
}
|
|
462
481
|
|
|
463
482
|
/**
|
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ function isRecord(value) {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
// src/core/sdk-version.ts
|
|
7
|
-
var SDK_HEADER = `js/${"0.
|
|
7
|
+
var SDK_HEADER = `js/${"0.9.0"}`;
|
|
8
8
|
|
|
9
9
|
// src/utils.ts
|
|
10
10
|
function normalizeHost(host) {
|
|
@@ -1063,6 +1063,9 @@ function endReason(reason) {
|
|
|
1063
1063
|
return "policy-violation";
|
|
1064
1064
|
if (reason === "time_limit")
|
|
1065
1065
|
return "time-limit";
|
|
1066
|
+
if (reason === "invalid_spec" || reason === "runtime_failed") {
|
|
1067
|
+
return "refused";
|
|
1068
|
+
}
|
|
1066
1069
|
return "ended";
|
|
1067
1070
|
}
|
|
1068
1071
|
function parseSessionEvent(payload) {
|
|
@@ -1093,7 +1096,15 @@ function parseSessionEvent(payload) {
|
|
|
1093
1096
|
};
|
|
1094
1097
|
}
|
|
1095
1098
|
if (decoded.type === "error" && decoded.fatal === true) {
|
|
1096
|
-
|
|
1099
|
+
const ended = {
|
|
1100
|
+
type: "ended",
|
|
1101
|
+
reason: endReason(decoded.code),
|
|
1102
|
+
byClient: false
|
|
1103
|
+
};
|
|
1104
|
+
if (typeof decoded.message === "string" && decoded.message !== "") {
|
|
1105
|
+
ended.message = decoded.message;
|
|
1106
|
+
}
|
|
1107
|
+
return ended;
|
|
1097
1108
|
}
|
|
1098
1109
|
if (decoded.type === "error" && decoded.code === "bad_command") {
|
|
1099
1110
|
return { type: "command-unreadable" };
|
|
@@ -1528,6 +1539,7 @@ var CLOCK_SYNC_TOPIC = "clock-sync";
|
|
|
1528
1539
|
var STATS_FLUSH_TIMEOUT_MS = 300;
|
|
1529
1540
|
var SESSION_END_TIMEOUT_MS = 300;
|
|
1530
1541
|
var SESSION_END_ID = "client-session-end";
|
|
1542
|
+
var REFUSAL_REASON_WAIT_MS = 500;
|
|
1531
1543
|
var COMMAND_TIMEOUT_MS = 5000;
|
|
1532
1544
|
var BACKGROUND_ID = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
1533
1545
|
var AVATAR_RETURN_TIMEOUT_MS = 8000;
|
|
@@ -1578,6 +1590,7 @@ class LiveKitConversation {
|
|
|
1578
1590
|
network = "good";
|
|
1579
1591
|
eventsRegistered = false;
|
|
1580
1592
|
sessionEnded = false;
|
|
1593
|
+
refusal = null;
|
|
1581
1594
|
speaksProtocol = false;
|
|
1582
1595
|
avatarSpeaking = false;
|
|
1583
1596
|
answered = null;
|
|
@@ -1698,6 +1711,7 @@ class LiveKitConversation {
|
|
|
1698
1711
|
this.stopReadyFallback();
|
|
1699
1712
|
this.stopLayerFallback();
|
|
1700
1713
|
this.clearAway();
|
|
1714
|
+
this.stopRefusal();
|
|
1701
1715
|
this._user?.cleanup();
|
|
1702
1716
|
this._user?.releaseDevices();
|
|
1703
1717
|
await this.flushStats();
|
|
@@ -1731,6 +1745,15 @@ class LiveKitConversation {
|
|
|
1731
1745
|
throw new Error("Nothing to send: the text is blank");
|
|
1732
1746
|
return this.command({ type: "input.text", text: line, respond: true });
|
|
1733
1747
|
}
|
|
1748
|
+
async holdAgent() {
|
|
1749
|
+
await this.command({ type: "agent.stop" }).catch(() => {
|
|
1750
|
+
return;
|
|
1751
|
+
});
|
|
1752
|
+
return this.command({ type: "floor.hold" });
|
|
1753
|
+
}
|
|
1754
|
+
async releaseAgent() {
|
|
1755
|
+
return this.command({ type: "floor.release" });
|
|
1756
|
+
}
|
|
1734
1757
|
onChange(handler) {
|
|
1735
1758
|
return this.onEvent((event) => {
|
|
1736
1759
|
if (event.type !== "data-event" && event.type !== "screen-share-changed")
|
|
@@ -1976,12 +1999,16 @@ class LiveKitConversation {
|
|
|
1976
1999
|
} else if (event.type === "ended") {
|
|
1977
2000
|
this.answered?.();
|
|
1978
2001
|
if (!event.byClient)
|
|
1979
|
-
this.reportEnd(event.reason);
|
|
2002
|
+
this.reportEnd(event.reason, event.message);
|
|
1980
2003
|
}
|
|
1981
2004
|
}
|
|
1982
2005
|
handleRuntimeSignal(payload) {
|
|
1983
2006
|
const signal = parseRuntimeSignal(payload);
|
|
1984
2007
|
if (signal?.type === "session-ended") {
|
|
2008
|
+
if (signal.reason === "refused") {
|
|
2009
|
+
this.refusal ??= setTimeout(() => this.reportEnd("refused"), REFUSAL_REASON_WAIT_MS);
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
1985
2012
|
this.reportEnd(signal.reason);
|
|
1986
2013
|
} else if (signal?.type === "output-ready") {
|
|
1987
2014
|
this.markAvatarReady();
|
|
@@ -2120,11 +2147,18 @@ class LiveKitConversation {
|
|
|
2120
2147
|
this.presentation?.stop();
|
|
2121
2148
|
this.presentation = null;
|
|
2122
2149
|
}
|
|
2123
|
-
reportEnd(reason) {
|
|
2150
|
+
reportEnd(reason, message) {
|
|
2151
|
+
this.stopRefusal();
|
|
2124
2152
|
if (this.sessionEnded)
|
|
2125
2153
|
return;
|
|
2126
2154
|
this.sessionEnded = true;
|
|
2127
|
-
this.emit({ type: "session-ended", reason });
|
|
2155
|
+
this.emit(message === undefined ? { type: "session-ended", reason } : { type: "session-ended", reason, message });
|
|
2156
|
+
}
|
|
2157
|
+
stopRefusal() {
|
|
2158
|
+
if (this.refusal === null)
|
|
2159
|
+
return;
|
|
2160
|
+
clearTimeout(this.refusal);
|
|
2161
|
+
this.refusal = null;
|
|
2128
2162
|
}
|
|
2129
2163
|
handleClockSyncPing(payload) {
|
|
2130
2164
|
const reply = clockSyncPong(payload, Date.now() / 1000, () => Date.now() / 1000);
|
|
@@ -2202,6 +2236,7 @@ class NuanceConversation {
|
|
|
2202
2236
|
sessionOverrides;
|
|
2203
2237
|
personality;
|
|
2204
2238
|
variant;
|
|
2239
|
+
maxSessionSeconds;
|
|
2205
2240
|
videoCapture;
|
|
2206
2241
|
startOn;
|
|
2207
2242
|
mediaDevices;
|
|
@@ -2239,6 +2274,7 @@ class NuanceConversation {
|
|
|
2239
2274
|
this.sessionOverrides = options.sessionOverrides ?? {};
|
|
2240
2275
|
this.personality = options.personality;
|
|
2241
2276
|
this.variant = options.variant;
|
|
2277
|
+
this.maxSessionSeconds = options.maxSessionSeconds;
|
|
2242
2278
|
this.videoCapture = options.videoCapture;
|
|
2243
2279
|
this.startOn = options.startOn ?? "first-frame";
|
|
2244
2280
|
this.mediaDevices = options.mediaDevices;
|
|
@@ -2275,6 +2311,9 @@ class NuanceConversation {
|
|
|
2275
2311
|
request.personality = this.personality;
|
|
2276
2312
|
if (this.variant)
|
|
2277
2313
|
request.variant = this.variant;
|
|
2314
|
+
if (this.maxSessionSeconds !== undefined) {
|
|
2315
|
+
request.max_session_seconds = this.maxSessionSeconds;
|
|
2316
|
+
}
|
|
2278
2317
|
conversation = await this.createWhenNotBusy(request, attempt);
|
|
2279
2318
|
} catch (error) {
|
|
2280
2319
|
if (error instanceof ApiError && error.status === 409) {
|
|
@@ -2305,10 +2344,10 @@ class NuanceConversation {
|
|
|
2305
2344
|
this.setState(event.state);
|
|
2306
2345
|
return;
|
|
2307
2346
|
}
|
|
2308
|
-
if (event.type === "session-ended" && event.reason === "connection-lost") {
|
|
2347
|
+
if (event.type === "session-ended" && (event.reason === "connection-lost" || event.reason === "refused")) {
|
|
2309
2348
|
const held = this.held;
|
|
2310
2349
|
this.held = null;
|
|
2311
|
-
this.endSession(event.reason);
|
|
2350
|
+
this.endSession(event.reason, event.message);
|
|
2312
2351
|
this.disconnect().catch(() => {});
|
|
2313
2352
|
if (held !== null) {
|
|
2314
2353
|
this.api.abandonConversation(held).catch(() => {});
|
|
@@ -2316,7 +2355,7 @@ class NuanceConversation {
|
|
|
2316
2355
|
return;
|
|
2317
2356
|
}
|
|
2318
2357
|
if (event.type === "session-ended") {
|
|
2319
|
-
this.endSession(event.reason);
|
|
2358
|
+
this.endSession(event.reason, event.message);
|
|
2320
2359
|
return;
|
|
2321
2360
|
}
|
|
2322
2361
|
this.emit(event);
|
|
@@ -2379,6 +2418,18 @@ class NuanceConversation {
|
|
|
2379
2418
|
}
|
|
2380
2419
|
return this.delegate.sendText(text);
|
|
2381
2420
|
}
|
|
2421
|
+
async holdAgent() {
|
|
2422
|
+
if (!this.delegate) {
|
|
2423
|
+
throw new Error("Not connected — call connect() first");
|
|
2424
|
+
}
|
|
2425
|
+
return this.delegate.holdAgent();
|
|
2426
|
+
}
|
|
2427
|
+
async releaseAgent() {
|
|
2428
|
+
if (!this.delegate) {
|
|
2429
|
+
throw new Error("Not connected — call connect() first");
|
|
2430
|
+
}
|
|
2431
|
+
return this.delegate.releaseAgent();
|
|
2432
|
+
}
|
|
2382
2433
|
onChange(handler) {
|
|
2383
2434
|
return this.onEvent((event) => {
|
|
2384
2435
|
if (event.type !== "data-event" && event.type !== "screen-share-changed")
|
|
@@ -2455,7 +2506,7 @@ class NuanceConversation {
|
|
|
2455
2506
|
throw new TerminalStatusError(event.reason);
|
|
2456
2507
|
}
|
|
2457
2508
|
if (event.type === "queued" && event.position != null) {
|
|
2458
|
-
this.reportPlace(event.position, event.estimated_wait_seconds ?? null, null);
|
|
2509
|
+
this.reportPlace(event.position, event.estimated_wait_seconds ?? null, null, event.preparing ?? false);
|
|
2459
2510
|
}
|
|
2460
2511
|
}
|
|
2461
2512
|
}
|
|
@@ -2639,9 +2690,9 @@ class NuanceConversation {
|
|
|
2639
2690
|
if (state.status !== "queued" || state.position == null) {
|
|
2640
2691
|
return;
|
|
2641
2692
|
}
|
|
2642
|
-
this.reportPlace(state.position, state.estimated_wait_seconds ?? null, state.pool_slots ?? null);
|
|
2693
|
+
this.reportPlace(state.position, state.estimated_wait_seconds ?? null, state.pool_slots ?? null, state.preparing ?? false);
|
|
2643
2694
|
}
|
|
2644
|
-
reportPlace(position, estimate, poolSlots) {
|
|
2695
|
+
reportPlace(position, estimate, poolSlots, preparing) {
|
|
2645
2696
|
if (this._state !== "queued") {
|
|
2646
2697
|
this.setState("queued");
|
|
2647
2698
|
}
|
|
@@ -2649,7 +2700,8 @@ class NuanceConversation {
|
|
|
2649
2700
|
type: "queue-changed",
|
|
2650
2701
|
position,
|
|
2651
2702
|
estimatedWaitSeconds: this.smoothEstimate(position, estimate),
|
|
2652
|
-
poolSlots
|
|
2703
|
+
poolSlots,
|
|
2704
|
+
preparing
|
|
2653
2705
|
});
|
|
2654
2706
|
}
|
|
2655
2707
|
smoothEstimate(position, estimate) {
|
|
@@ -2685,14 +2737,14 @@ class NuanceConversation {
|
|
|
2685
2737
|
}
|
|
2686
2738
|
await this.api.abandonConversation(held).catch(() => {});
|
|
2687
2739
|
}
|
|
2688
|
-
endSession(reason) {
|
|
2740
|
+
endSession(reason, message) {
|
|
2689
2741
|
if (this.ended) {
|
|
2690
2742
|
return;
|
|
2691
2743
|
}
|
|
2692
2744
|
this.ended = true;
|
|
2693
2745
|
this.clearLimit();
|
|
2694
2746
|
this.stopHeartbeat();
|
|
2695
|
-
this.emit({ type: "session-ended", reason });
|
|
2747
|
+
this.emit(message === undefined ? { type: "session-ended", reason } : { type: "session-ended", reason, message });
|
|
2696
2748
|
}
|
|
2697
2749
|
stopHeartbeat() {
|
|
2698
2750
|
this.stopBeats?.();
|