@nuancelabs/js-sdk 0.13.1 → 0.14.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 +1 -0
- package/index.d.ts +36 -1
- package/index.js +47 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ const conversation = createNuanceConversation({
|
|
|
18
18
|
// Your endpoint, which mints a session token with your API key.
|
|
19
19
|
token: async () => {
|
|
20
20
|
const response = await fetch("/api/nuance-token", { method: "POST" });
|
|
21
|
+
if (!response.ok) throw new Error(await response.text());
|
|
21
22
|
return (await response.json()).token;
|
|
22
23
|
},
|
|
23
24
|
});
|
package/index.d.ts
CHANGED
|
@@ -86,6 +86,38 @@ export declare interface AgentTurnStartedEvent extends SessionEventBase {
|
|
|
86
86
|
source: "reply" | "say" | (string & {});
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* An error answer from the Nuance API that the SDK has no more specific error
|
|
91
|
+
* for, such as a `401` for an expired or used session token, a `429` when this
|
|
92
|
+
* month's conversation time is used, or a `503` once the SDK has stopped
|
|
93
|
+
* retrying a busy service. See the Errors guide for each status and `code`.
|
|
94
|
+
*
|
|
95
|
+
* Act on `status` and `code`, never on `message`: the message is the server's
|
|
96
|
+
* `detail`, written for you, and it can change.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* try {
|
|
101
|
+
* await conversation.connect();
|
|
102
|
+
* } catch (error) {
|
|
103
|
+
* if (error instanceof ApiError && error.status === 401) {
|
|
104
|
+
* // The session token expired or was used: the next connect() fetches a new one.
|
|
105
|
+
* }
|
|
106
|
+
* }
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export declare class ApiError extends Error {
|
|
110
|
+
/** The HTTP status, such as `401` or `503`. */
|
|
111
|
+
readonly status: number;
|
|
112
|
+
/** The error's `code` when the server sent one, such as `"busy"` or `"unavailable"`. */
|
|
113
|
+
readonly code: string | null;
|
|
114
|
+
/** How long to wait before trying again, when the server said. */
|
|
115
|
+
readonly retryAfterSeconds: number | null;
|
|
116
|
+
/** The parsed JSON body of the answer, or `null` when it had none. */
|
|
117
|
+
readonly body: unknown;
|
|
118
|
+
constructor(status: number, detail: string, body?: unknown);
|
|
119
|
+
}
|
|
120
|
+
|
|
89
121
|
/**
|
|
90
122
|
* An audio track that can be attached to or detached from an audio element.
|
|
91
123
|
*/
|
|
@@ -362,7 +394,8 @@ export declare type ConversationEvent =
|
|
|
362
394
|
* `"time-limit"` when the session was capped and ran out its clock,
|
|
363
395
|
* `"policy-violation"` when the runtime ended it for content, `"refused"`
|
|
364
396
|
* when the runtime would not start it, with its reason in `message` when it
|
|
365
|
-
* gave one.
|
|
397
|
+
* gave one. Call {@link Conversation.disconnect} then: after the runtime's
|
|
398
|
+
* own end the call stays connected, with the camera and microphone on.
|
|
366
399
|
*/
|
|
367
400
|
| {
|
|
368
401
|
type: "session-ended";
|
|
@@ -416,6 +449,7 @@ export declare type ConversationStateValue = `${ConversationState}`;
|
|
|
416
449
|
* // Your server mints a session token with its API key.
|
|
417
450
|
* token: async () => {
|
|
418
451
|
* const response = await fetch("/api/nuance-token", { method: "POST" });
|
|
452
|
+
* if (!response.ok) throw new Error(await response.text());
|
|
419
453
|
* return (await response.json()).token;
|
|
420
454
|
* },
|
|
421
455
|
* });
|
|
@@ -448,6 +482,7 @@ export declare interface CreateNuanceConversationOptions {
|
|
|
448
482
|
* ```ts
|
|
449
483
|
* token: async () => {
|
|
450
484
|
* const response = await fetch("/api/nuance-token", { method: "POST" });
|
|
485
|
+
* if (!response.ok) throw new Error(await response.text());
|
|
451
486
|
* return (await response.json()).token;
|
|
452
487
|
* }
|
|
453
488
|
* ```
|
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.14.1"}`;
|
|
8
8
|
|
|
9
9
|
// src/utils.ts
|
|
10
10
|
function normalizeHost(host) {
|
|
@@ -14,12 +14,16 @@ function normalizeHost(host) {
|
|
|
14
14
|
// src/api/client.ts
|
|
15
15
|
class ApiError extends Error {
|
|
16
16
|
status;
|
|
17
|
+
code;
|
|
18
|
+
retryAfterSeconds;
|
|
17
19
|
body;
|
|
18
20
|
constructor(status, detail, body = null) {
|
|
19
21
|
super(detail);
|
|
20
22
|
this.name = "ApiError";
|
|
21
23
|
this.status = status;
|
|
22
24
|
this.body = body;
|
|
25
|
+
this.code = isRecord(body) && typeof body.code === "string" ? body.code : null;
|
|
26
|
+
this.retryAfterSeconds = isRecord(body) && typeof body.retry_after_seconds === "number" ? body.retry_after_seconds : null;
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -99,7 +103,6 @@ class NuanceApiClient {
|
|
|
99
103
|
return this.headersProvider ? await this.headersProvider() : {};
|
|
100
104
|
}
|
|
101
105
|
}
|
|
102
|
-
|
|
103
106
|
// src/core/active-session-error.ts
|
|
104
107
|
class ActiveSessionError extends Error {
|
|
105
108
|
constructor() {
|
|
@@ -1676,6 +1679,8 @@ var COMMAND_TIMEOUT_MS = 5000;
|
|
|
1676
1679
|
var STREAM_TIMEOUT_MS = 30000;
|
|
1677
1680
|
var BACKGROUND_ID = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
1678
1681
|
var AVATAR_RETURN_TIMEOUT_MS = 8000;
|
|
1682
|
+
var RUNTIME_RETURN_TIMEOUT_MS = 20000;
|
|
1683
|
+
var RUNTIME_RECHECK_MS = 1000;
|
|
1679
1684
|
function contextItem(item) {
|
|
1680
1685
|
const name = item.name === undefined ? {} : { name: item.name };
|
|
1681
1686
|
return item.type === "text" ? { type: "text", text: item.text, ...name } : { type: "image", media_type: item.mediaType, data: item.data, ...name };
|
|
@@ -1738,6 +1743,7 @@ class LiveKitConversation {
|
|
|
1738
1743
|
everConnected = false;
|
|
1739
1744
|
away = false;
|
|
1740
1745
|
awayTimer = null;
|
|
1746
|
+
runtimeTimer = null;
|
|
1741
1747
|
presentationPaused = false;
|
|
1742
1748
|
readySending = false;
|
|
1743
1749
|
contextSent = null;
|
|
@@ -2049,10 +2055,14 @@ class LiveKitConversation {
|
|
|
2049
2055
|
queueMicrotask(() => {
|
|
2050
2056
|
if (this.room.state === ConnectionState2.Disconnected)
|
|
2051
2057
|
return;
|
|
2052
|
-
if (isReconnecting(this.room.state))
|
|
2058
|
+
if (isReconnecting(this.room.state)) {
|
|
2053
2059
|
this.avatarAway();
|
|
2054
|
-
else
|
|
2060
|
+
} else if (this.sessionEnded) {
|
|
2055
2061
|
this.avatarLeft();
|
|
2062
|
+
} else if (this.avatarInRoom()) {} else {
|
|
2063
|
+
this.avatarAway();
|
|
2064
|
+
this.awaitRuntimeReturn();
|
|
2065
|
+
}
|
|
2056
2066
|
});
|
|
2057
2067
|
});
|
|
2058
2068
|
this.room.on(RoomEvent3.Disconnected, () => {
|
|
@@ -2339,6 +2349,33 @@ class LiveKitConversation {
|
|
|
2339
2349
|
this.avatarLeft();
|
|
2340
2350
|
}, AVATAR_RETURN_TIMEOUT_MS);
|
|
2341
2351
|
}
|
|
2352
|
+
awaitRuntimeReturn(delay = RUNTIME_RETURN_TIMEOUT_MS) {
|
|
2353
|
+
if (this.runtimeTimer !== null)
|
|
2354
|
+
return;
|
|
2355
|
+
this.runtimeTimer = setTimeout(() => {
|
|
2356
|
+
this.runtimeTimer = null;
|
|
2357
|
+
if (!this.away)
|
|
2358
|
+
return;
|
|
2359
|
+
if (isReconnecting(this.room.state)) {
|
|
2360
|
+
this.awaitRuntimeReturn(RUNTIME_RECHECK_MS);
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
if (this.room.state === ConnectionState2.Disconnected)
|
|
2364
|
+
return;
|
|
2365
|
+
if (this.avatarInRoom())
|
|
2366
|
+
return;
|
|
2367
|
+
this.clearAway();
|
|
2368
|
+
this.avatarLeft();
|
|
2369
|
+
this.reportEnd("connection-lost");
|
|
2370
|
+
}, delay);
|
|
2371
|
+
}
|
|
2372
|
+
avatarInRoom() {
|
|
2373
|
+
for (const [, participant] of this.room.remoteParticipants) {
|
|
2374
|
+
if (this.isAvatarParticipant(participant))
|
|
2375
|
+
return true;
|
|
2376
|
+
}
|
|
2377
|
+
return false;
|
|
2378
|
+
}
|
|
2342
2379
|
avatarBack() {
|
|
2343
2380
|
const resume = this.presentationPaused && this._avatar.isReady;
|
|
2344
2381
|
this.clearAway();
|
|
@@ -2354,6 +2391,10 @@ class LiveKitConversation {
|
|
|
2354
2391
|
clearTimeout(this.awayTimer);
|
|
2355
2392
|
this.awayTimer = null;
|
|
2356
2393
|
}
|
|
2394
|
+
if (this.runtimeTimer !== null) {
|
|
2395
|
+
clearTimeout(this.runtimeTimer);
|
|
2396
|
+
this.runtimeTimer = null;
|
|
2397
|
+
}
|
|
2357
2398
|
}
|
|
2358
2399
|
startLayerFallback() {
|
|
2359
2400
|
if (this.layerFallback !== null)
|
|
@@ -2812,7 +2853,7 @@ class NuanceConversation {
|
|
|
2812
2853
|
return "time-limit";
|
|
2813
2854
|
if (reason === "policy_violation")
|
|
2814
2855
|
return "policy-violation";
|
|
2815
|
-
if (this.cutOff())
|
|
2856
|
+
if (reason === "runtime_silent" || this.cutOff())
|
|
2816
2857
|
return "connection-lost";
|
|
2817
2858
|
return "ended";
|
|
2818
2859
|
}
|
|
@@ -3048,5 +3089,6 @@ export {
|
|
|
3048
3089
|
LegalRequiredError,
|
|
3049
3090
|
GuestLimitError,
|
|
3050
3091
|
ConversationState,
|
|
3092
|
+
ApiError,
|
|
3051
3093
|
ActiveSessionError
|
|
3052
3094
|
};
|