realtime-avatar 0.25.0 → 0.26.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/README.md +78 -0
- package/dist/browser.d.ts +2 -87
- package/dist/browser.js +6 -1
- package/dist/{chunk-GMYGHDY2.js → chunk-HMESE54B.js} +22 -4
- package/dist/{chunk-DNHHQ5GZ.js → chunk-XJPGQMEW.js} +28 -10
- package/dist/express.js +2 -2
- package/dist/hono.js +2 -2
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1 -1
- package/dist/nextjs.js +2 -2
- package/dist/playout-delay-CtRZdtsj.d.ts +168 -0
- package/dist/{proxy-client-O-Mu9JKt.d.ts → proxy-client-C8M_G_Kk.d.ts} +163 -17
- package/dist/react-native.d.ts +3 -3
- package/dist/react-native.js +341 -26
- package/dist/react.d.ts +75 -14
- package/dist/react.js +532 -83
- package/dist/server.js +1 -1
- package/dist/tanstack-start.js +2 -2
- package/dist/tools.d.ts +17 -1
- package/dist/tools.js +28 -8
- package/package.json +1 -1
- package/dist/playout-delay-DWOc8iCl.d.ts +0 -65
package/dist/server.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, listRecordingsResponseSchema, recordingAccessResponseSchema, recordingArtifactSchema, recordingModeSchema, verifyTranscript } from './chunk-
|
|
1
|
+
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, listRecordingsResponseSchema, recordingAccessResponseSchema, recordingArtifactSchema, recordingModeSchema, verifyTranscript } from './chunk-HMESE54B.js';
|
|
2
2
|
import './chunk-MCIXU6XP.js';
|
package/dist/tanstack-start.js
CHANGED
package/dist/tools.d.ts
CHANGED
|
@@ -93,6 +93,22 @@ interface RoomLike {
|
|
|
93
93
|
identity: string;
|
|
94
94
|
}>;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Registration did not arm the tools. `retryable` says whether trying again can help:
|
|
98
|
+
* - true: the agent was not there or had not armed registration by the deadline (a slow start,
|
|
99
|
+
* or a session minted without `client_tools` — one attempt cannot tell them apart), or the RPC
|
|
100
|
+
* transport failed.
|
|
101
|
+
* - false: the manifest is too large, the agent refused or answered something unreadable, or
|
|
102
|
+
* LiveKit refused the request itself. The same request will fail the same way.
|
|
103
|
+
*/
|
|
104
|
+
declare class ToolRegistrationError extends Error {
|
|
105
|
+
readonly name = "ToolRegistrationError";
|
|
106
|
+
readonly retryable: boolean;
|
|
107
|
+
constructor(message: string, options: {
|
|
108
|
+
retryable: boolean;
|
|
109
|
+
cause?: unknown;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
96
112
|
/**
|
|
97
113
|
* Register your tools and start answering calls to them.
|
|
98
114
|
*
|
|
@@ -131,4 +147,4 @@ declare function attachAvatarTools(room: RoomLike, tools: Record<string, Registe
|
|
|
131
147
|
timeoutMs?: number;
|
|
132
148
|
}): Promise<ToolRegistration>;
|
|
133
149
|
|
|
134
|
-
export { type AvatarTool, MAX_MANIFEST_BYTES, MAX_RESULT_CHARS, MAX_TOOLS, type RegisteredTool, TOOL_DEADLINE_MS, type ToolContext, type ToolRegistration, attachAvatarTools, defineAvatarTool };
|
|
150
|
+
export { type AvatarTool, MAX_MANIFEST_BYTES, MAX_RESULT_CHARS, MAX_TOOLS, type RegisteredTool, TOOL_DEADLINE_MS, type ToolContext, type ToolRegistration, ToolRegistrationError, attachAvatarTools, defineAvatarTool };
|
package/dist/tools.js
CHANGED
|
@@ -35,14 +35,26 @@ function candidateIdentities(room) {
|
|
|
35
35
|
const agents = all.filter((id) => /^agent[-_]/i.test(id));
|
|
36
36
|
return [...agents, ...all.filter((id) => !agents.includes(id))];
|
|
37
37
|
}
|
|
38
|
+
function rpcCode(error) {
|
|
39
|
+
return typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
40
|
+
}
|
|
38
41
|
function methodMissing(error) {
|
|
39
|
-
const code = error
|
|
40
|
-
if (code === "UNSUPPORTED_METHOD" || code === "RECIPIENT_NOT_FOUND" || code ===
|
|
42
|
+
const code = rpcCode(error);
|
|
43
|
+
if (code === "UNSUPPORTED_METHOD" || code === "RECIPIENT_NOT_FOUND" || code === 1400 || code === 1401) {
|
|
41
44
|
return true;
|
|
42
45
|
}
|
|
43
46
|
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
44
47
|
return /not supported|unsupported_method|recipient_not_found|recipient not found/i.test(message);
|
|
45
48
|
}
|
|
49
|
+
var TRANSIENT_RPC_CODES = /* @__PURE__ */ new Set([1501, 1502, 1503, 1505]);
|
|
50
|
+
var ToolRegistrationError = class extends Error {
|
|
51
|
+
name = "ToolRegistrationError";
|
|
52
|
+
retryable;
|
|
53
|
+
constructor(message, options) {
|
|
54
|
+
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
55
|
+
this.retryable = options.retryable;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
46
58
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
47
59
|
function buildManifest(tools) {
|
|
48
60
|
const descriptors = [];
|
|
@@ -72,8 +84,9 @@ async function attachAvatarTools(room, tools, options = {}) {
|
|
|
72
84
|
const { descriptors, rejected } = buildManifest(tools);
|
|
73
85
|
const payload = JSON.stringify({ tools: descriptors });
|
|
74
86
|
if (payload.length > MAX_MANIFEST_BYTES) {
|
|
75
|
-
throw new
|
|
76
|
-
`tool manifest is ${payload.length} bytes, over the ${MAX_MANIFEST_BYTES} limit \u2014 shorten descriptions or register fewer tools
|
|
87
|
+
throw new ToolRegistrationError(
|
|
88
|
+
`tool manifest is ${payload.length} bytes, over the ${MAX_MANIFEST_BYTES} limit \u2014 shorten descriptions or register fewer tools`,
|
|
89
|
+
{ retryable: false }
|
|
77
90
|
);
|
|
78
91
|
}
|
|
79
92
|
options.signal?.throwIfAborted();
|
|
@@ -156,14 +169,21 @@ async function attachAvatarTools(room, tools, options = {}) {
|
|
|
156
169
|
} catch (error) {
|
|
157
170
|
activeCaller = void 0;
|
|
158
171
|
lastError = error;
|
|
159
|
-
if (!methodMissing(error))
|
|
172
|
+
if (!methodMissing(error)) {
|
|
173
|
+
if (options.signal?.aborted) throw error;
|
|
174
|
+
throw new ToolRegistrationError(
|
|
175
|
+
`tool registration failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
176
|
+
{ retryable: TRANSIENT_RPC_CODES.has(rpcCode(error)), cause: error }
|
|
177
|
+
);
|
|
178
|
+
}
|
|
160
179
|
}
|
|
161
180
|
}
|
|
162
181
|
if (Date.now() >= deadline) break;
|
|
163
182
|
await sleep(200);
|
|
164
183
|
}
|
|
165
|
-
throw new
|
|
166
|
-
sawCandidate ? `no participant accepted the tool manifest \u2014 either this session was not minted with the \`client_tools\` capability (a server-side grant), or the agent never armed registration within ${options.timeoutMs ?? 8e3}ms` + (lastError instanceof Error ? ` (last error: ${lastError.message})` : "") : "no remote participant joined the room before the timeout \u2014 nothing to register with"
|
|
184
|
+
throw new ToolRegistrationError(
|
|
185
|
+
sawCandidate ? `no participant accepted the tool manifest \u2014 either this session was not minted with the \`client_tools\` capability (a server-side grant), or the agent never armed registration within ${options.timeoutMs ?? 8e3}ms` + (lastError instanceof Error ? ` (last error: ${lastError.message})` : "") : "no remote participant joined the room before the timeout \u2014 nothing to register with",
|
|
186
|
+
{ retryable: true, cause: lastError ?? void 0 }
|
|
167
187
|
);
|
|
168
188
|
} catch (error) {
|
|
169
189
|
dispose();
|
|
@@ -171,4 +191,4 @@ async function attachAvatarTools(room, tools, options = {}) {
|
|
|
171
191
|
}
|
|
172
192
|
}
|
|
173
193
|
|
|
174
|
-
export { MAX_MANIFEST_BYTES, MAX_RESULT_CHARS, MAX_TOOLS, TOOL_DEADLINE_MS, attachAvatarTools, defineAvatarTool };
|
|
194
|
+
export { MAX_MANIFEST_BYTES, MAX_RESULT_CHARS, MAX_TOOLS, TOOL_DEADLINE_MS, ToolRegistrationError, attachAvatarTools, defineAvatarTool };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "realtime-avatar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Realtime Avatar SDK. `realtime-avatar` and the route adapters hold your API key and are server-only; `realtime-avatar/react`, `/browser` and `/tools` never can — importing a server entry into a browser build throws at bundle time.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "The Influence Company",
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Receiver-side playout delay (SECONDS) for the avatar media tracks.
|
|
3
|
-
*
|
|
4
|
-
* The avatar is published from a GPU datacenter and reaches viewers over the
|
|
5
|
-
* public internet, where a few percent of packet loss is normal. A shallow
|
|
6
|
-
* receiver buffer stalls (freezes) on every loss while it waits for a
|
|
7
|
-
* retransmit; a deeper buffer recovers the lost packets BEFORE playout, so the
|
|
8
|
-
* viewer sees smooth 25fps instead of freezing. Measured at ~5% loss this took
|
|
9
|
-
* the stream from ~11fps with multi-second freezes to a steady 25fps with zero
|
|
10
|
-
* freezes.
|
|
11
|
-
*
|
|
12
|
-
* 0.5s is applied via the native `RemoteTrack.setPlayoutDelay`, which sets the
|
|
13
|
-
* receiver's `playoutDelayHint` — the same Chromium jitter-buffer knob the old
|
|
14
|
-
* hand-rolled `jitterBufferTarget` reached into (the spec renamed
|
|
15
|
-
* playoutDelayHint→jitterBufferTarget; both influence the same buffer depth),
|
|
16
|
-
* but typed and SDK-owned so there is no cast or feature-probe. The hint is NOT
|
|
17
|
-
* free at the open: the receiver holds the FIRST video frame toward the target
|
|
18
|
-
* (~250-450ms of measured TTFF), a deliberate cost paid once for the freeze-free
|
|
19
|
-
* steady state above. The open-small-then-ramp variant that tried to dodge that
|
|
20
|
-
* cost was shipped, failed twice (the rVFC ramp trigger is throttled on the
|
|
21
|
-
* opacity:0-mounted element, stranding the shallow buffer), and was deliberately
|
|
22
|
-
* removed in 2262e4c7b — do not re-propose it. No-op on browsers that don't
|
|
23
|
-
* support the hint (the SDK warns and moves on).
|
|
24
|
-
*
|
|
25
|
-
* This lives in the vanilla browser package, not the React one, because the
|
|
26
|
-
* React surface applies it for you and a plain-DOM page has to be given it.
|
|
27
|
-
* Until this file existed the helper was only reachable through
|
|
28
|
-
* `realtime-avatar/react`, so every plain-DOM adopter — every one of this repo's
|
|
29
|
-
* own demos included — ran with the browser's default shallow buffer and froze on
|
|
30
|
-
* every lost packet. Nobody should have to know this knob exists: `prepareAvatarRoom`
|
|
31
|
-
* (and `attachRemoteAudio`, which calls it) applies it to every track the room
|
|
32
|
-
* subscribes, and `RealtimeAvatarLiveKitRoom` does the same for React. This file is
|
|
33
|
-
* the one place the number and its reasoning live.
|
|
34
|
-
* Structural like its siblings: no `livekit-client` import, no version pin.
|
|
35
|
-
*/
|
|
36
|
-
declare const DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS = 0.5;
|
|
37
|
-
/**
|
|
38
|
-
* A track that can take a native playout-delay hint — livekit-client's subscribed
|
|
39
|
-
* `RemoteTrack`. Duck-typed on the method rather than `instanceof`, so a
|
|
40
|
-
* placeholder or local track is skipped and the helper is testable with a fake.
|
|
41
|
-
*/
|
|
42
|
-
interface PlayoutDelayTarget {
|
|
43
|
-
setPlayoutDelay(delayInSeconds: number): void;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Apply the receiver playout delay to ONE subscribed track.
|
|
47
|
-
*
|
|
48
|
-
* Call it for every track `RoomEvent.TrackSubscribed` hands you, audio and video
|
|
49
|
-
* alike, before or after `attach()` — WebRTC syncs the pair to the LARGER hint,
|
|
50
|
-
* so applying it to one stream and not the other lets the lips lag the voice.
|
|
51
|
-
* Returns `true` when the hint was applied and `false` when the object cannot take
|
|
52
|
-
* one (a local track, a placeholder, a not-yet-subscribed publication), so a
|
|
53
|
-
* caller can log the miss without a try/catch. The delay is floored at 0 so a
|
|
54
|
-
* negative input can never throw.
|
|
55
|
-
*/
|
|
56
|
-
declare function applyPlayoutDelay(track: unknown, delaySeconds?: number): boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Apply the SAME native playout delay to the avatar's audio + video tracks
|
|
59
|
-
* (kept equal so the a/v sync stays lip-locked). Pure and exported so the clamp
|
|
60
|
-
* and the both-tracks-equal invariant are unit-testable without a DOM; the React
|
|
61
|
-
* hook `useAvatarPlayoutDelay` is a thin effect wrapper around this.
|
|
62
|
-
*/
|
|
63
|
-
declare function applyAvatarPlayoutDelay(videoTrack: unknown, audioTrack: unknown, delaySeconds?: number): void;
|
|
64
|
-
|
|
65
|
-
export { DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS as D, type PlayoutDelayTarget as P, applyAvatarPlayoutDelay as a, applyPlayoutDelay as b };
|