realtime-avatar 0.11.5 → 0.13.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/dist/{chunk-SML2NB3Q.js → chunk-NOHMMTFR.js} +16 -1
- package/dist/{chunk-FAEFGA2G.js → chunk-UVNDDNU2.js} +38 -18
- package/dist/express.d.ts +2 -2
- package/dist/express.js +2 -2
- package/dist/hono.d.ts +2 -2
- package/dist/hono.js +2 -2
- package/dist/index.d.ts +8 -25
- package/dist/index.js +1 -1
- package/dist/nextjs.d.ts +2 -2
- package/dist/nextjs.js +2 -2
- package/dist/{proxy-client-8cQOLLE_.d.ts → proxy-client-BoUJWSkf.d.ts} +28 -5
- package/dist/react-native.d.ts +2 -2
- package/dist/react-native.js +172 -5
- package/dist/react.d.ts +2 -2
- package/dist/react.js +175 -6
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/tanstack-start.d.ts +2 -2
- package/dist/tanstack-start.js +2 -2
- package/dist/{types-nxdohaiH.d.ts → types-B9GTrpx0.d.ts} +22 -8
- package/dist/{types-9a0bRdXl.d.ts → types-CJcTowDB.d.ts} +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-
|
|
1
|
+
import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-UVNDDNU2.js';
|
|
2
2
|
|
|
3
3
|
// ../proxy/src/config.ts
|
|
4
4
|
var json = (body, status = 200) => new Response(JSON.stringify(body), {
|
|
@@ -61,6 +61,21 @@ function createProxyHandler(config) {
|
|
|
61
61
|
minted.set(call.sessionId, now);
|
|
62
62
|
return json(call.raw);
|
|
63
63
|
} catch (error) {
|
|
64
|
+
if (error instanceof RealtimeAvatarHttpError && error.status === 429) {
|
|
65
|
+
const concurrency = error.code === "concurrency_limit_reached";
|
|
66
|
+
const counts = error.concurrency;
|
|
67
|
+
const message = concurrency ? counts?.maxConcurrentSessions !== void 0 && counts.activeSessions !== void 0 && counts.connectingSessions !== void 0 && counts.pendingSessions !== void 0 ? `Session limit reached (${counts.maxConcurrentSessions} allowed): ${counts.activeSessions} active, ${counts.connectingSessions} connecting, ${counts.pendingSessions} starting. End a session or wait for pending starts to clear, then retry.` : "The concurrent session limit is reached. Active and starting sessions count. End a session or wait for pending starts to clear, then retry." : "Too many requests. Wait before retrying.";
|
|
68
|
+
const response = json({
|
|
69
|
+
error: message,
|
|
70
|
+
code: concurrency ? "concurrency_limit_reached" : "rate_limited",
|
|
71
|
+
status: 429,
|
|
72
|
+
retryable: true,
|
|
73
|
+
...concurrency ? counts : {},
|
|
74
|
+
...error.requestId ? { requestId: error.requestId } : {}
|
|
75
|
+
}, 429);
|
|
76
|
+
if (error.requestId) response.headers.set("X-Request-ID", error.requestId);
|
|
77
|
+
return response;
|
|
78
|
+
}
|
|
64
79
|
if (error instanceof RealtimeAvatarHttpError && error.isBilling) {
|
|
65
80
|
return json({ code: error.code ?? "insufficient_credits" }, 402);
|
|
66
81
|
}
|
|
@@ -11,12 +11,32 @@ var RealtimeAvatarHttpError = class extends RealtimeAvatarError {
|
|
|
11
11
|
status;
|
|
12
12
|
code;
|
|
13
13
|
body;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
requestId;
|
|
15
|
+
concurrency;
|
|
16
|
+
constructor(status, code, body, requestId) {
|
|
17
|
+
const bounded = body.slice(0, 400);
|
|
18
|
+
super(`Realtime Avatar API ${status}${code ? ` (${code})` : ""}: ${bounded || "no body"}`);
|
|
16
19
|
this.name = "RealtimeAvatarHttpError";
|
|
17
20
|
this.status = status;
|
|
18
21
|
this.code = code;
|
|
19
|
-
this.body =
|
|
22
|
+
this.body = bounded;
|
|
23
|
+
let parsed = {};
|
|
24
|
+
try {
|
|
25
|
+
const value = JSON.parse(body);
|
|
26
|
+
if (value && typeof value === "object" && !Array.isArray(value)) parsed = value;
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
const validId = (value) => typeof value === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(value);
|
|
30
|
+
this.requestId = validId(parsed.requestId) ? parsed.requestId : validId(requestId) ? requestId : void 0;
|
|
31
|
+
if (status === 429 && code === "concurrency_limit_reached") {
|
|
32
|
+
this.concurrency = {};
|
|
33
|
+
for (const key of ["maxConcurrentSessions", "liveSessions", "activeSessions", "connectingSessions", "pendingSessions"]) {
|
|
34
|
+
const value = parsed[key];
|
|
35
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= (key === "maxConcurrentSessions" ? 1 : 0)) {
|
|
36
|
+
this.concurrency[key] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
20
40
|
}
|
|
21
41
|
/** Out of credits, or over this key's spend limit. Surface a paywall, not an error. */
|
|
22
42
|
get isBilling() {
|
|
@@ -26,12 +46,12 @@ var RealtimeAvatarHttpError = class extends RealtimeAvatarError {
|
|
|
26
46
|
var motionIdSchema = z.string().regex(/^[A-Za-z0-9_-]{1,64}$/).refine((value) => !["__proto__", "constructor", "prototype"].includes(value), "Reserved identifier");
|
|
27
47
|
function motionRecord(valueSchema) {
|
|
28
48
|
const record = z.record(motionIdSchema, valueSchema);
|
|
29
|
-
return z.
|
|
49
|
+
return z.preprocess((value, ctx) => {
|
|
30
50
|
if (value !== null && typeof value === "object" && Object.hasOwn(value, "__proto__")) {
|
|
31
51
|
ctx.addIssue({ code: "custom", path: ["__proto__"], message: "Reserved identifier" });
|
|
32
52
|
}
|
|
33
53
|
return value;
|
|
34
|
-
}
|
|
54
|
+
}, record);
|
|
35
55
|
}
|
|
36
56
|
var clipSourceSchema = z.union([
|
|
37
57
|
z.strictObject({ assetId: z.string().trim().min(1).max(160) }),
|
|
@@ -134,9 +154,7 @@ var schema13 = z.strictObject({
|
|
|
134
154
|
"verdict": schema11,
|
|
135
155
|
"issues": schema12,
|
|
136
156
|
"firstFrameUrl": schema4,
|
|
137
|
-
"lastFrameUrl": schema4
|
|
138
|
-
"trimStartMs": schema8,
|
|
139
|
-
"trimEndMs": schema8
|
|
157
|
+
"lastFrameUrl": schema4
|
|
140
158
|
});
|
|
141
159
|
var schema14 = z.union([schema13, schema3]);
|
|
142
160
|
var schema15 = z.strictObject({
|
|
@@ -218,7 +236,7 @@ function isTransient(cause) {
|
|
|
218
236
|
|
|
219
237
|
// ../http-client/src/client.ts
|
|
220
238
|
var DEFAULT_BASE_URL = "https://realtimeavatar.ai/api/v1";
|
|
221
|
-
var SDK_VERSION = "0.
|
|
239
|
+
var SDK_VERSION = "0.13.0";
|
|
222
240
|
var RealtimeAvatar = class {
|
|
223
241
|
#apiKey;
|
|
224
242
|
#baseUrl;
|
|
@@ -270,14 +288,16 @@ var RealtimeAvatar = class {
|
|
|
270
288
|
if (options.video !== void 0) Object.assign(body, videoToWire(options.video));
|
|
271
289
|
const response = await this.#request("POST", "/realtime/livekit/session", { json: body });
|
|
272
290
|
if (response.status === 429) {
|
|
273
|
-
const busy = await response.json();
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
291
|
+
const busy = await response.clone().json().catch(() => null);
|
|
292
|
+
if (isRecord(busy) && !("code" in busy) && typeof busy.queue_size === "number" && Number.isFinite(busy.queue_size) && busy.queue_size >= 0 && typeof busy.recommended_retry_ms === "number" && Number.isFinite(busy.recommended_retry_ms) && busy.recommended_retry_ms >= 0) {
|
|
293
|
+
return {
|
|
294
|
+
queued: true,
|
|
295
|
+
position: typeof busy.queue_position === "number" ? busy.queue_position : null,
|
|
296
|
+
size: busy.queue_size,
|
|
297
|
+
retryAfterMs: busy.recommended_retry_ms,
|
|
298
|
+
queueTicketId: typeof busy.queue_ticket_id === "string" ? busy.queue_ticket_id : null
|
|
299
|
+
};
|
|
300
|
+
}
|
|
281
301
|
}
|
|
282
302
|
const grant = await this.#json(response);
|
|
283
303
|
return {
|
|
@@ -657,7 +677,7 @@ var RealtimeAvatar = class {
|
|
|
657
677
|
code = JSON.parse(text).code;
|
|
658
678
|
} catch {
|
|
659
679
|
}
|
|
660
|
-
throw new RealtimeAvatarHttpError(response.status, code, text.
|
|
680
|
+
throw new RealtimeAvatarHttpError(response.status, code, text, response.headers.get("x-request-id") ?? void 0);
|
|
661
681
|
}
|
|
662
682
|
};
|
|
663
683
|
function toUsageSessionPage(raw) {
|
package/dist/express.d.ts
CHANGED
package/dist/express.js
CHANGED
package/dist/hono.d.ts
CHANGED
package/dist/hono.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as CallPolicy, C as CallMode, S as StartCallResult, E as EndCallOptions, A as Avatar, b as AvatarUpdate, c as AvatarSourceSwap, d as ClipLibraryDeclaration, e as ClipLibraryUpdate, L as LoopRedirect, f as ClipLibrary, g as AssetKind, h as Asset, i as ListSessionsOptions, U as UsageSessionPage, j as UsageSession, k as CreditBalance, T as TranscriptPayload } from './types-
|
|
2
|
-
export { l as AvatarClip, m as CallConnection, n as CallQueued, o as ClipDeclaration, p as ClipLibraryPlan, q as ClipSource, r as ContextMessage, s as EndCallReason, V as VideoPolicy, t as isQueued } from './types-
|
|
1
|
+
import { a as CallPolicy, C as CallMode, S as StartCallResult, E as EndCallOptions, A as Avatar, b as AvatarUpdate, c as AvatarSourceSwap, d as ClipLibraryDeclaration, e as ClipLibraryUpdate, L as LoopRedirect, f as ClipLibrary, g as AssetKind, h as Asset, i as ListSessionsOptions, U as UsageSessionPage, j as UsageSession, k as CreditBalance, T as TranscriptPayload } from './types-B9GTrpx0.js';
|
|
2
|
+
export { l as AvatarClip, m as CallConnection, n as CallQueued, o as ClipDeclaration, p as ClipLibraryPlan, q as ClipSource, r as ContextMessage, s as EndCallReason, V as VideoPolicy, t as isQueued } from './types-B9GTrpx0.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
interface RealtimeAvatarOptions {
|
|
@@ -294,6 +294,7 @@ declare class RealtimeAvatarError extends Error {
|
|
|
294
294
|
* | `loop_pending` · `anchor_pending` | 409 | one is already in flight — wait, then retry |
|
|
295
295
|
* | `revision_conflict` | 409 | someone declared first. Re-read `listClips`, re-decide, re-declare |
|
|
296
296
|
* | `clip_render_limit` | 429 | a true rate limit; nothing was applied. Retry later |
|
|
297
|
+
* | `concurrency_limit_reached` | 429 | active and starting sessions occupy the limit; release one or wait for pending starts before retrying |
|
|
297
298
|
* | `clip_screen_unavailable` | 503 | the prose screen could not run. Retry |
|
|
298
299
|
*
|
|
299
300
|
* Pose validation does NOT appear here: a rejected upload is not an error response at all.
|
|
@@ -308,7 +309,9 @@ declare class RealtimeAvatarHttpError extends RealtimeAvatarError {
|
|
|
308
309
|
readonly status: number;
|
|
309
310
|
readonly code: string | undefined;
|
|
310
311
|
readonly body: string;
|
|
311
|
-
|
|
312
|
+
readonly requestId?: string;
|
|
313
|
+
readonly concurrency?: Partial<Record<"maxConcurrentSessions" | "liveSessions" | "activeSessions" | "connectingSessions" | "pendingSessions", number>>;
|
|
314
|
+
constructor(status: number, code: string | undefined, body: string, requestId?: string);
|
|
312
315
|
/** Out of credits, or over this key's spend limit. Surface a paywall, not an error. */
|
|
313
316
|
get isBilling(): boolean;
|
|
314
317
|
}
|
|
@@ -338,32 +341,12 @@ declare const clipLibraryDeclarationSchema: z.ZodObject<{
|
|
|
338
341
|
clips: z.ZodArray<z.ZodString>;
|
|
339
342
|
}, z.core.$strict>>;
|
|
340
343
|
}, z.core.$strict>>;
|
|
341
|
-
actions: z.ZodOptional<z.
|
|
342
|
-
description: string;
|
|
343
|
-
clips: string[];
|
|
344
|
-
}>, Record<string, {
|
|
345
|
-
description: string;
|
|
346
|
-
clips: string[];
|
|
347
|
-
}>>, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
344
|
+
actions: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
348
345
|
description: z.ZodString;
|
|
349
346
|
clips: z.ZodArray<z.ZodString>;
|
|
350
347
|
}, z.core.$strict>>>>;
|
|
351
348
|
expectedRevision: z.ZodInt;
|
|
352
|
-
clips: z.ZodNonOptional<z.
|
|
353
|
-
source: {
|
|
354
|
-
assetId: string;
|
|
355
|
-
} | {
|
|
356
|
-
motionPrompt: string;
|
|
357
|
-
durationSeconds?: number | undefined;
|
|
358
|
-
};
|
|
359
|
-
}>, Record<string, {
|
|
360
|
-
source: {
|
|
361
|
-
assetId: string;
|
|
362
|
-
} | {
|
|
363
|
-
motionPrompt: string;
|
|
364
|
-
durationSeconds?: number | undefined;
|
|
365
|
-
};
|
|
366
|
-
}>>, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
349
|
+
clips: z.ZodNonOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
367
350
|
source: z.ZodUnion<readonly [z.ZodObject<{
|
|
368
351
|
assetId: z.ZodString;
|
|
369
352
|
}, z.core.$strict>, z.ZodObject<{
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-
|
|
1
|
+
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-UVNDDNU2.js';
|
package/dist/nextjs.d.ts
CHANGED
package/dist/nextjs.js
CHANGED
|
@@ -403,6 +403,22 @@ interface Governor {
|
|
|
403
403
|
healthySinceMs: number | null;
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
declare const NETWORK_QUALITY_POLICY: {
|
|
407
|
+
readonly startupGraceMs: 3000;
|
|
408
|
+
readonly maxSampleGapMs: 1500;
|
|
409
|
+
readonly minimumPackets: 20;
|
|
410
|
+
readonly lossWindowSamples: 3;
|
|
411
|
+
readonly lossRatio: 0.05;
|
|
412
|
+
readonly jitterSeconds: 0.1;
|
|
413
|
+
readonly impairedFps: 12;
|
|
414
|
+
readonly downgradeMs: 2000;
|
|
415
|
+
readonly floorMs: 2000;
|
|
416
|
+
readonly notifyAfterDowngradeMs: 5000;
|
|
417
|
+
readonly recoverMs: 5000;
|
|
418
|
+
readonly clearNoticeMs: 10000;
|
|
419
|
+
};
|
|
420
|
+
type NetworkQualityStatus = "unknown" | "healthy" | "poor";
|
|
421
|
+
|
|
406
422
|
/** How the media is fit into the surface box. Mirrors CSS `object-fit`. */
|
|
407
423
|
type AvatarVideoFit = "contain" | "cover";
|
|
408
424
|
type AvatarVideoSurfaceProps = {
|
|
@@ -439,8 +455,13 @@ type AvatarVideoSurfaceProps = {
|
|
|
439
455
|
* Enable the subscriber-side fast-down/sticky-up quality governor. It starts on
|
|
440
456
|
* the lower simulcast rung, reacts immediately to an SFU pause or decoded-frame
|
|
441
457
|
* freeze, and only probes the full layer after a clean dwell. Default true.
|
|
458
|
+
* False releases the manual cap to HIGH on each subscription without running
|
|
459
|
+
* the governor. SFU bandwidth adaptation and live/idle fallback remain active.
|
|
442
460
|
*/
|
|
443
|
-
adaptiveQuality?: boolean;
|
|
461
|
+
adaptiveQuality?: boolean | "network-only";
|
|
462
|
+
/** Opt-in "network-only" keeps HIGH unless sustained receiver/network impairment is
|
|
463
|
+
* observed. Status is unknown until enough fresh data exists; poor after 5s. */
|
|
464
|
+
onNetworkStatusChange?: (status: NetworkQualityStatus) => void;
|
|
444
465
|
/**
|
|
445
466
|
* Opening bet for the governor when `adaptiveQuality` is on. `"high"` opens on the
|
|
446
467
|
* FULL simulcast layer under probation — sharp from frame 1, no LOW→HIGH layer-walk —
|
|
@@ -1539,9 +1560,11 @@ type FreezeReadingFn = () => {
|
|
|
1539
1560
|
inhibited: boolean;
|
|
1540
1561
|
};
|
|
1541
1562
|
interface UseAvatarQualityGovernorInput {
|
|
1542
|
-
/** Master switch (product policy
|
|
1543
|
-
*
|
|
1544
|
-
enabled: boolean;
|
|
1563
|
+
/** Master switch (product policy). Off releases the manual cap to HIGH on each
|
|
1564
|
+
* subscription, with no governor tick or congestion listeners. SFU adaptation stays on. */
|
|
1565
|
+
enabled: boolean | "network-only";
|
|
1566
|
+
/** Sustained, receiver-evidenced impairment. Never inferred from rendering jitter alone. */
|
|
1567
|
+
onNetworkStatusChange?: (status: NetworkQualityStatus) => void;
|
|
1545
1568
|
/** The player's rVFC freeze reading getter (see FreezeReadingFn). Optional: without
|
|
1546
1569
|
* it the governor still reacts to Paused + getStats freezes, just without the
|
|
1547
1570
|
* cross-browser rVFC signal. */
|
|
@@ -1624,4 +1647,4 @@ interface ProxyClientOptions {
|
|
|
1624
1647
|
}
|
|
1625
1648
|
declare function createProxyClient(options: ProxyClientOptions): AvatarSessionClient;
|
|
1626
1649
|
|
|
1627
|
-
export { RECONNECT_BACKOFF_MS as $, type AvatarVideoFit as A, type BehaviorSnapshot as B, type CallTranscript as C, DEFAULT_APPROACHING_END_LEAD_SECONDS as D, type EndReason as E, type FishTtsModel as F, type Governor as G, type GraceWindowClosedEvent as H, type GraceWindowOpenEvent as I, type GraceWindowState as J, type IdleWarningEvent as K, type LiveKitSessionGrant as L, type InboundRtpCursor as M, type InboundRtpReading as N, type KnownBehaviorState as O, type LLMProvider as P, type LLMSelection as Q, type LiveKitAvatarGrantState as R, type LiveKitAvatarGrantStatus as S, type LiveKitCapacityState as T, type LiveKitConnectionStatus as U, type LiveKitSessionRequest as V, type LiveKitSessionStartResult as W, MAX_RECONNECT_ATTEMPTS as X, MAX_SESSION_INSTRUCTIONS_CHARS as Y, type ProxyClientOptions as Z, type QualityCap as _, AdaptivePlayoutController as a, type RealtimeAvatarRequestOptions as a0, type RealtimeSessionApi as a1, type RealtimeSessionMedia as a2, type RealtimeSessionRoomSinks as a3, type ReconnectPolicy as a4, type ReconnectingEvent as a5, type RecoveryState as a6, type RetryStep as a7, type SessionBehavior as a8, type SessionClip as a9, useAvatarAdaptivePlayoutDelay as aA, useAvatarPlayoutDelay as aB, useAvatarQualityGovernor as aC, useCallTranscript as aD, useLiveKitAvatarGrant as aE, useLiveTrackProducing as aF, useMicLease as aG, useRealtimeSession as aH, useReleaseMicLeaseOnTrackEnded as aI, useSessionLifecycle as aJ, AvatarVideoSurface as aK, type AvatarVideoSurfaceProps as aL, type LivePlaybackKeeper as aM, MIC_LEASE_ENDED_TIMEOUT_MS as aN, type MicLease as aO, type PlayableVideoElement as
|
|
1650
|
+
export { RECONNECT_BACKOFF_MS as $, type AvatarVideoFit as A, type BehaviorSnapshot as B, type CallTranscript as C, DEFAULT_APPROACHING_END_LEAD_SECONDS as D, type EndReason as E, type FishTtsModel as F, type Governor as G, type GraceWindowClosedEvent as H, type GraceWindowOpenEvent as I, type GraceWindowState as J, type IdleWarningEvent as K, type LiveKitSessionGrant as L, type InboundRtpCursor as M, type InboundRtpReading as N, type KnownBehaviorState as O, type LLMProvider as P, type LLMSelection as Q, type LiveKitAvatarGrantState as R, type LiveKitAvatarGrantStatus as S, type LiveKitCapacityState as T, type LiveKitConnectionStatus as U, type LiveKitSessionRequest as V, type LiveKitSessionStartResult as W, MAX_RECONNECT_ATTEMPTS as X, MAX_SESSION_INSTRUCTIONS_CHARS as Y, type ProxyClientOptions as Z, type QualityCap as _, AdaptivePlayoutController as a, type RealtimeAvatarRequestOptions as a0, type RealtimeSessionApi as a1, type RealtimeSessionMedia as a2, type RealtimeSessionRoomSinks as a3, type ReconnectPolicy as a4, type ReconnectingEvent as a5, type RecoveryState as a6, type RetryStep as a7, type SessionBehavior as a8, type SessionClip as a9, useAvatarAdaptivePlayoutDelay as aA, useAvatarPlayoutDelay as aB, useAvatarQualityGovernor as aC, useCallTranscript as aD, useLiveKitAvatarGrant as aE, useLiveTrackProducing as aF, useMicLease as aG, useRealtimeSession as aH, useReleaseMicLeaseOnTrackEnded as aI, useSessionLifecycle as aJ, AvatarVideoSurface as aK, type AvatarVideoSurfaceProps as aL, type LivePlaybackKeeper as aM, MIC_LEASE_ENDED_TIMEOUT_MS as aN, type MicLease as aO, NETWORK_QUALITY_POLICY as aP, type NetworkQualityStatus as aQ, type PlayableVideoElement as aR, RealtimeAvatarCapacityError as aS, RealtimeAvatarLiveKitRoom as aT, type RealtimeAvatarLiveKitRoomProps as aU, shouldReplayPendingTurn as aV, type SessionClocks as aa, type SessionEndReason as ab, type SessionLifecycleApi as ac, type SessionLifecyclePhase as ad, type SessionLifecyclePhaseKind as ae, SessionLifecycleRoomBridge as af, type SessionLifecycleRoomBridgeProps as ag, type SurfaceLayers as ah, type TurnState as ai, type TurnTimeoutEvent as aj, type UseAvatarQualityGovernorInput as ak, type UseLiveKitAvatarGrantInput as al, type UseRealtimeSessionInput as am, type UseSessionLifecycleInput as an, type VoiceSpec as ao, type VoiceSpecInput as ap, capacityErrorFromBusy as aq, capacityStateFromGrant as ar, createProxyClient as as, isNativeLiveTrackSubscribed as at, knownBehaviorStates as au, mapTurnState as av, readInboundRtp as aw, sessionBehaviorSchema as ax, sessionClipSchema as ay, splitCallTranscript as az, type AdaptivePlayoutDecision as b, type AdaptivePlayoutOptions as c, type AdaptivePlayoutSample as d, type ApproachingEndEvent as e, type ApproachingEndReason as f, type AvatarSessionClient as g, type CallTranscriptSegment as h, type CartesiaTtsModel as i, type ClipResult as j, type ClosingTurnResult as k, type CreditsLowEvent as l, DEFAULT_CREDITS_LOW_LEAD_SECONDS as m, DEFAULT_GOVERNOR_CONFIG as n, DEFAULT_GRACE_CEILING_SECONDS as o, DEFAULT_GRACE_WINDOW_LEAD_SECONDS as p, DEFAULT_IDLE_SECONDS as q, DEFAULT_IDLE_WARN_LEAD_SECONDS as r, DEFAULT_TURN_TIMEOUT_SECONDS as s, type EndedEvent as t, type ExtendResult as u, type FreezeReadingFn as v, type GovernorAction as w, type GovernorConfig as x, type GovernorSignal as y, type GovernorState as z };
|
package/dist/react-native.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LiveKitRoomProps } from '@livekit/react-native';
|
|
2
2
|
export { AudioSession, VideoTrack, VideoTrackProps, registerGlobals } from '@livekit/react-native';
|
|
3
3
|
import { ReactNode, ReactElement } from 'react';
|
|
4
|
-
import { L as LiveKitSessionGrant, A as AvatarVideoFit } from './proxy-client-
|
|
5
|
-
export { a as AdaptivePlayoutController, b as AdaptivePlayoutDecision, c as AdaptivePlayoutOptions, d as AdaptivePlayoutSample, e as ApproachingEndEvent, f as ApproachingEndReason, g as AvatarSessionClient, B as BehaviorSnapshot, C as CallTranscript, h as CallTranscriptSegment, i as CartesiaTtsModel, j as ClipResult, k as ClosingTurnResult, l as CreditsLowEvent, D as DEFAULT_APPROACHING_END_LEAD_SECONDS, m as DEFAULT_CREDITS_LOW_LEAD_SECONDS, n as DEFAULT_GOVERNOR_CONFIG, o as DEFAULT_GRACE_CEILING_SECONDS, p as DEFAULT_GRACE_WINDOW_LEAD_SECONDS, q as DEFAULT_IDLE_SECONDS, r as DEFAULT_IDLE_WARN_LEAD_SECONDS, s as DEFAULT_TURN_TIMEOUT_SECONDS, E as EndReason, t as EndedEvent, u as ExtendResult, F as FishTtsModel, v as FreezeReadingFn, G as Governor, w as GovernorAction, x as GovernorConfig, y as GovernorSignal, z as GovernorState, H as GraceWindowClosedEvent, I as GraceWindowOpenEvent, J as GraceWindowState, K as IdleWarningEvent, M as InboundRtpCursor, N as InboundRtpReading, O as KnownBehaviorState, P as LLMProvider, Q as LLMSelection, R as LiveKitAvatarGrantState, S as LiveKitAvatarGrantStatus, T as LiveKitCapacityState, U as LiveKitConnectionStatus, V as LiveKitSessionRequest, W as LiveKitSessionStartResult, X as MAX_RECONNECT_ATTEMPTS, Y as MAX_SESSION_INSTRUCTIONS_CHARS, Z as ProxyClientOptions, _ as QualityCap, $ as RECONNECT_BACKOFF_MS, a0 as RealtimeAvatarRequestOptions, a1 as RealtimeSessionApi, a2 as RealtimeSessionMedia, a3 as RealtimeSessionRoomSinks, a4 as ReconnectPolicy, a5 as ReconnectingEvent, a6 as RecoveryState, a7 as RetryStep, a8 as SessionBehavior, a9 as SessionClip, aa as SessionClocks, ab as SessionEndReason, ac as SessionLifecycleApi, ad as SessionLifecyclePhase, ae as SessionLifecyclePhaseKind, af as SessionLifecycleRoomBridge, ag as SessionLifecycleRoomBridgeProps, ah as SurfaceLayers, ai as TurnState, aj as TurnTimeoutEvent, ak as UseAvatarQualityGovernorInput, al as UseLiveKitAvatarGrantInput, am as UseRealtimeSessionInput, an as UseSessionLifecycleInput, ao as VoiceSpec, ap as VoiceSpecInput, aq as capacityErrorFromBusy, ar as capacityStateFromGrant, as as createProxyClient, at as isNativeLiveTrackSubscribed, au as knownBehaviorStates, av as mapTurnState, aw as readInboundRtp, ax as sessionBehaviorSchema, ay as sessionClipSchema, az as splitCallTranscript, aA as useAvatarAdaptivePlayoutDelay, aB as useAvatarPlayoutDelay, aC as useAvatarQualityGovernor, aD as useCallTranscript, aE as useLiveKitAvatarGrant, aF as useLiveTrackProducing, aG as useMicLease, aH as useRealtimeSession, aI as useReleaseMicLeaseOnTrackEnded, aJ as useSessionLifecycle } from './proxy-client-
|
|
4
|
+
import { L as LiveKitSessionGrant, A as AvatarVideoFit } from './proxy-client-BoUJWSkf.js';
|
|
5
|
+
export { a as AdaptivePlayoutController, b as AdaptivePlayoutDecision, c as AdaptivePlayoutOptions, d as AdaptivePlayoutSample, e as ApproachingEndEvent, f as ApproachingEndReason, g as AvatarSessionClient, B as BehaviorSnapshot, C as CallTranscript, h as CallTranscriptSegment, i as CartesiaTtsModel, j as ClipResult, k as ClosingTurnResult, l as CreditsLowEvent, D as DEFAULT_APPROACHING_END_LEAD_SECONDS, m as DEFAULT_CREDITS_LOW_LEAD_SECONDS, n as DEFAULT_GOVERNOR_CONFIG, o as DEFAULT_GRACE_CEILING_SECONDS, p as DEFAULT_GRACE_WINDOW_LEAD_SECONDS, q as DEFAULT_IDLE_SECONDS, r as DEFAULT_IDLE_WARN_LEAD_SECONDS, s as DEFAULT_TURN_TIMEOUT_SECONDS, E as EndReason, t as EndedEvent, u as ExtendResult, F as FishTtsModel, v as FreezeReadingFn, G as Governor, w as GovernorAction, x as GovernorConfig, y as GovernorSignal, z as GovernorState, H as GraceWindowClosedEvent, I as GraceWindowOpenEvent, J as GraceWindowState, K as IdleWarningEvent, M as InboundRtpCursor, N as InboundRtpReading, O as KnownBehaviorState, P as LLMProvider, Q as LLMSelection, R as LiveKitAvatarGrantState, S as LiveKitAvatarGrantStatus, T as LiveKitCapacityState, U as LiveKitConnectionStatus, V as LiveKitSessionRequest, W as LiveKitSessionStartResult, X as MAX_RECONNECT_ATTEMPTS, Y as MAX_SESSION_INSTRUCTIONS_CHARS, Z as ProxyClientOptions, _ as QualityCap, $ as RECONNECT_BACKOFF_MS, a0 as RealtimeAvatarRequestOptions, a1 as RealtimeSessionApi, a2 as RealtimeSessionMedia, a3 as RealtimeSessionRoomSinks, a4 as ReconnectPolicy, a5 as ReconnectingEvent, a6 as RecoveryState, a7 as RetryStep, a8 as SessionBehavior, a9 as SessionClip, aa as SessionClocks, ab as SessionEndReason, ac as SessionLifecycleApi, ad as SessionLifecyclePhase, ae as SessionLifecyclePhaseKind, af as SessionLifecycleRoomBridge, ag as SessionLifecycleRoomBridgeProps, ah as SurfaceLayers, ai as TurnState, aj as TurnTimeoutEvent, ak as UseAvatarQualityGovernorInput, al as UseLiveKitAvatarGrantInput, am as UseRealtimeSessionInput, an as UseSessionLifecycleInput, ao as VoiceSpec, ap as VoiceSpecInput, aq as capacityErrorFromBusy, ar as capacityStateFromGrant, as as createProxyClient, at as isNativeLiveTrackSubscribed, au as knownBehaviorStates, av as mapTurnState, aw as readInboundRtp, ax as sessionBehaviorSchema, ay as sessionClipSchema, az as splitCallTranscript, aA as useAvatarAdaptivePlayoutDelay, aB as useAvatarPlayoutDelay, aC as useAvatarQualityGovernor, aD as useCallTranscript, aE as useLiveKitAvatarGrant, aF as useLiveTrackProducing, aG as useMicLease, aH as useRealtimeSession, aI as useReleaseMicLeaseOnTrackEnded, aJ as useSessionLifecycle } from './proxy-client-BoUJWSkf.js';
|
|
6
6
|
import { StyleProp, ViewStyle } from 'react-native';
|
|
7
7
|
export { useChat, useConnectionState, useLocalParticipant, useRoomContext, useTrackToggle, useTranscriptions, useVoiceAssistant } from '@livekit/components-react';
|
|
8
8
|
export { D as DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS } from './playout-delay-DWOc8iCl.js';
|
package/dist/react-native.js
CHANGED
|
@@ -3,7 +3,7 @@ export { AudioSession, VideoTrack, registerGlobals } from '@livekit/react-native
|
|
|
3
3
|
import { useEffect, createElement, useRef, useState, useCallback, useMemo } from 'react';
|
|
4
4
|
import { useTranscriptions, useLocalParticipant, useMaybeRoomContext, useVoiceAssistant, useConnectionState, isTrackReference, useRoomContext, useChat } from '@livekit/components-react';
|
|
5
5
|
export { useChat, useConnectionState, useLocalParticipant, useRoomContext, useTrackToggle, useTranscriptions, useVoiceAssistant } from '@livekit/components-react';
|
|
6
|
-
import { ConnectionQuality, RoomEvent, TrackEvent, ConnectionState, Track,
|
|
6
|
+
import { VideoQuality, ConnectionQuality, RoomEvent, TrackEvent, ConnectionState, Track, ConnectionError, ConnectionErrorReason, DisconnectReason, Room } from 'livekit-client';
|
|
7
7
|
export { DisconnectReason, Room, RoomEvent, Track } from 'livekit-client';
|
|
8
8
|
import { Platform, StyleSheet, Animated, Image, View, Text } from 'react-native';
|
|
9
9
|
import { z } from 'zod';
|
|
@@ -241,6 +241,13 @@ function normalizeRealtimeAvatarError(input) {
|
|
|
241
241
|
if (status === 409) {
|
|
242
242
|
return { code: "conflict", message: "That request is already in progress. Try again in a moment.", retryable: true };
|
|
243
243
|
}
|
|
244
|
+
if (status === 429 && rawCode === "concurrency_limit_reached") {
|
|
245
|
+
return {
|
|
246
|
+
code: rawCode,
|
|
247
|
+
message: userSafeMessage(rawMessage) ?? "The concurrent session limit is reached. Active and starting sessions count. End a session or wait for pending starts to clear, then retry.",
|
|
248
|
+
retryable: true
|
|
249
|
+
};
|
|
250
|
+
}
|
|
244
251
|
if (status === 429) {
|
|
245
252
|
return { code: "rate_limited", message: "Too many realtime requests. Please slow down and retry.", retryable: true };
|
|
246
253
|
}
|
|
@@ -870,6 +877,144 @@ var resolveLowCapQuality = (declaredLayerQualities, lowUnhealthy = 0) => {
|
|
|
870
877
|
return lowUnhealthy >= LOW_CAP_STEP_AFTER_UNHEALTHY ? sorted[0] : sorted[sorted.length - 2];
|
|
871
878
|
};
|
|
872
879
|
|
|
880
|
+
// ../client/src/react/network-quality.ts
|
|
881
|
+
var NETWORK_QUALITY_POLICY = {
|
|
882
|
+
startupGraceMs: 3e3,
|
|
883
|
+
maxSampleGapMs: 1500,
|
|
884
|
+
minimumPackets: 20,
|
|
885
|
+
lossRatio: 0.05,
|
|
886
|
+
jitterSeconds: 0.1,
|
|
887
|
+
impairedFps: 12,
|
|
888
|
+
downgradeMs: 2e3,
|
|
889
|
+
floorMs: 2e3,
|
|
890
|
+
notifyAfterDowngradeMs: 5e3,
|
|
891
|
+
recoverMs: 5e3,
|
|
892
|
+
clearNoticeMs: 1e4
|
|
893
|
+
};
|
|
894
|
+
function readNetworkVideoSample(report) {
|
|
895
|
+
const samples = [];
|
|
896
|
+
report?.forEach((row) => {
|
|
897
|
+
if (row.type !== "inbound-rtp" || (row.kind ?? row.mediaType) !== "video") return;
|
|
898
|
+
const { timestamp, framesDecoded, packetsReceived, packetsLost, jitter } = row;
|
|
899
|
+
if (typeof row.id !== "string" || ![timestamp, framesDecoded, packetsReceived, packetsLost, jitter].every(
|
|
900
|
+
(n) => typeof n === "number" && Number.isFinite(n)
|
|
901
|
+
) || timestamp < 0 || framesDecoded < 0 || packetsReceived < 0 || jitter < 0) return;
|
|
902
|
+
samples.push({
|
|
903
|
+
id: `${row.id}:${row.ssrc ?? ""}`,
|
|
904
|
+
timestamp,
|
|
905
|
+
framesDecoded,
|
|
906
|
+
packetsReceived,
|
|
907
|
+
packetsLost,
|
|
908
|
+
jitter
|
|
909
|
+
});
|
|
910
|
+
});
|
|
911
|
+
return samples.length === 1 ? samples[0] : null;
|
|
912
|
+
}
|
|
913
|
+
function initNetworkQuality(nowMs) {
|
|
914
|
+
return {
|
|
915
|
+
cap: "high",
|
|
916
|
+
status: "unknown",
|
|
917
|
+
sample: null,
|
|
918
|
+
lastPollMs: null,
|
|
919
|
+
openedMs: nowMs,
|
|
920
|
+
badMs: 0,
|
|
921
|
+
postDowngradeBadMs: 0,
|
|
922
|
+
reducedBadMs: 0,
|
|
923
|
+
cleanMs: 0,
|
|
924
|
+
packetWindow: []
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
function stepNetworkQuality(previous, sample, nowMs, options) {
|
|
928
|
+
const p = NETWORK_QUALITY_POLICY;
|
|
929
|
+
const s = { ...previous, sample, lastPollMs: nowMs };
|
|
930
|
+
const before = previous.sample;
|
|
931
|
+
const pollMs = previous.lastPollMs === null ? 0 : nowMs - previous.lastPollMs;
|
|
932
|
+
const elapsedMs = sample && before ? sample.timestamp - before.timestamp : 0;
|
|
933
|
+
const interrupted = options.inhibited || pollMs <= 0 || pollMs > p.maxSampleGapMs;
|
|
934
|
+
const valid = !interrupted && sample !== null && before !== null && sample.id === before.id && elapsedMs > 0 && elapsedMs <= p.maxSampleGapMs && sample.framesDecoded >= before.framesDecoded && sample.packetsReceived >= before.packetsReceived;
|
|
935
|
+
if (!valid || nowMs - s.openedMs < p.startupGraceMs) {
|
|
936
|
+
s.badMs = s.postDowngradeBadMs = s.reducedBadMs = s.cleanMs = 0;
|
|
937
|
+
s.packetWindow = [];
|
|
938
|
+
if (options.inhibited) s.sample = null;
|
|
939
|
+
return s;
|
|
940
|
+
}
|
|
941
|
+
const received = sample.packetsReceived - before.packetsReceived;
|
|
942
|
+
const lost = Math.max(0, sample.packetsLost - before.packetsLost);
|
|
943
|
+
s.packetWindow = [...previous.packetWindow, { received, lost }].slice(-3);
|
|
944
|
+
const totals = s.packetWindow.reduce((sum, interval) => ({
|
|
945
|
+
received: sum.received + interval.received,
|
|
946
|
+
lost: sum.lost + interval.lost
|
|
947
|
+
}), { received: 0, lost: 0 });
|
|
948
|
+
const packets = totals.received + totals.lost;
|
|
949
|
+
const fps = (sample.framesDecoded - before.framesDecoded) * 1e3 / elapsedMs;
|
|
950
|
+
const loss = packets >= p.minimumPackets ? totals.lost / packets : null;
|
|
951
|
+
const impaired = options.paused || fps < p.impairedFps;
|
|
952
|
+
const bad = options.paused || impaired && (loss !== null && loss >= p.lossRatio || received >= p.minimumPackets && sample.jitter >= p.jitterSeconds);
|
|
953
|
+
const clean = received > 0 && !options.paused && loss !== null && loss < p.lossRatio && sample.jitter < p.jitterSeconds && fps >= p.impairedFps;
|
|
954
|
+
const duration = Math.min(pollMs, elapsedMs);
|
|
955
|
+
s.badMs = bad ? previous.badMs + duration : 0;
|
|
956
|
+
s.postDowngradeBadMs = bad && previous.cap !== "high" ? previous.postDowngradeBadMs + duration : 0;
|
|
957
|
+
s.cleanMs = clean ? previous.cleanMs + duration : 0;
|
|
958
|
+
s.reducedBadMs = bad && fps === 0 && previous.cap !== "high" ? previous.reducedBadMs + duration : 0;
|
|
959
|
+
if (s.badMs >= p.downgradeMs && s.cap === "high") s.cap = "reduced";
|
|
960
|
+
else if (s.reducedBadMs >= p.floorMs && fps === 0 && s.cap === "reduced") s.cap = "floor";
|
|
961
|
+
if (s.postDowngradeBadMs >= p.notifyAfterDowngradeMs) s.status = "poor";
|
|
962
|
+
if (s.cleanMs >= p.recoverMs) s.cap = "high";
|
|
963
|
+
if (s.cleanMs >= p.clearNoticeMs) s.status = "healthy";
|
|
964
|
+
return s;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// ../client/src/react/network-quality-binding.ts
|
|
968
|
+
function bindNetworkQuality(publication, inhibited, notify, tickMs) {
|
|
969
|
+
let disposed = false;
|
|
970
|
+
let running = false;
|
|
971
|
+
let state = initNetworkQuality(performance.now());
|
|
972
|
+
const apply = () => {
|
|
973
|
+
const qualities = (publication.trackInfo?.layers ?? []).map((l) => l.quality);
|
|
974
|
+
const cap = state.cap === "high" ? VideoQuality.HIGH : resolveLowCapQuality(qualities, state.cap === "floor" ? 2 : 0);
|
|
975
|
+
try {
|
|
976
|
+
publication.setVideoQuality(cap);
|
|
977
|
+
} catch {
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
const emit = (status) => {
|
|
981
|
+
try {
|
|
982
|
+
notify(status);
|
|
983
|
+
} catch {
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
apply();
|
|
987
|
+
emit("unknown");
|
|
988
|
+
const tick = async () => {
|
|
989
|
+
if (disposed || running) return;
|
|
990
|
+
running = true;
|
|
991
|
+
try {
|
|
992
|
+
const track = publication.track;
|
|
993
|
+
const stats = await track?.getRTCStatsReport?.();
|
|
994
|
+
if (disposed || publication.track !== track) return;
|
|
995
|
+
const prior = state;
|
|
996
|
+
state = stepNetworkQuality(state, readNetworkVideoSample(stats), performance.now(), {
|
|
997
|
+
paused: track?.streamState === Track.StreamState.Paused,
|
|
998
|
+
inhibited: document.hidden || publication.isMuted || inhibited()
|
|
999
|
+
});
|
|
1000
|
+
if (state.cap !== prior.cap) apply();
|
|
1001
|
+
if (state.status !== prior.status) emit(state.status);
|
|
1002
|
+
} catch {
|
|
1003
|
+
if (!disposed) state = { ...state, sample: null, packetWindow: [], badMs: 0, postDowngradeBadMs: 0, cleanMs: 0, reducedBadMs: 0 };
|
|
1004
|
+
} finally {
|
|
1005
|
+
running = false;
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
const timer = setInterval(() => {
|
|
1009
|
+
void tick();
|
|
1010
|
+
}, tickMs);
|
|
1011
|
+
return () => {
|
|
1012
|
+
disposed = true;
|
|
1013
|
+
clearInterval(timer);
|
|
1014
|
+
emit("unknown");
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
|
|
873
1018
|
// ../client/src/react/use-quality-governor.ts
|
|
874
1019
|
var qualityToSignal = (q) => {
|
|
875
1020
|
switch (q) {
|
|
@@ -886,7 +1031,7 @@ var qualityToSignal = (q) => {
|
|
|
886
1031
|
}
|
|
887
1032
|
};
|
|
888
1033
|
function useAvatarQualityGovernor(input) {
|
|
889
|
-
const { enabled, freezeReading, config: policy = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
|
|
1034
|
+
const { enabled, freezeReading, onNetworkStatusChange, config: policy = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
|
|
890
1035
|
const room = useMaybeRoomContext();
|
|
891
1036
|
const { videoTrack } = useVoiceAssistant();
|
|
892
1037
|
const {
|
|
@@ -923,11 +1068,28 @@ function useAvatarQualityGovernor(input) {
|
|
|
923
1068
|
]);
|
|
924
1069
|
const freezeReadingRef = useRef(freezeReading);
|
|
925
1070
|
freezeReadingRef.current = freezeReading;
|
|
1071
|
+
const networkCallback = useRef(onNetworkStatusChange);
|
|
1072
|
+
networkCallback.current = onNetworkStatusChange;
|
|
926
1073
|
const targetPublication = videoTrack?.publication;
|
|
927
1074
|
const targetParticipant = videoTrack?.participant;
|
|
928
1075
|
const targetTrack = targetPublication?.track;
|
|
929
1076
|
useEffect(() => {
|
|
930
|
-
if (!
|
|
1077
|
+
if (!room || !targetPublication || !targetParticipant) return;
|
|
1078
|
+
if (enabled === "network-only") {
|
|
1079
|
+
return bindNetworkQuality(
|
|
1080
|
+
targetPublication,
|
|
1081
|
+
() => freezeReadingRef.current?.().inhibited ?? false,
|
|
1082
|
+
(status) => networkCallback.current?.(status),
|
|
1083
|
+
tickMs
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
if (!enabled) {
|
|
1087
|
+
try {
|
|
1088
|
+
targetPublication.setVideoQuality(VideoQuality.HIGH);
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
931
1093
|
let pausedSinceTick = false;
|
|
932
1094
|
let lastFreezeStat = null;
|
|
933
1095
|
let jitterTrend = null;
|
|
@@ -2595,8 +2757,13 @@ function createProxyClient(options) {
|
|
|
2595
2757
|
requestOptions
|
|
2596
2758
|
);
|
|
2597
2759
|
if (response.status === 429) {
|
|
2598
|
-
const
|
|
2599
|
-
|
|
2760
|
+
const value = await response.clone().json().catch(() => null);
|
|
2761
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2762
|
+
const busy = value;
|
|
2763
|
+
const valid = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
|
|
2764
|
+
const queue2 = busy.queued === true && valid(busy.size) && valid(busy.retryAfterMs) || valid(busy.queue_size) && valid(busy.recommended_retry_ms);
|
|
2765
|
+
if (!("code" in busy) && queue2) return { status: "busy", busy };
|
|
2766
|
+
}
|
|
2600
2767
|
}
|
|
2601
2768
|
if (!response.ok) {
|
|
2602
2769
|
throw await RealtimeAvatarApiError.fromResponse(response);
|
package/dist/react.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RegisteredTool, ToolRegistration } from './tools.js';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { g as AvatarSessionClient, A as AvatarVideoFit } from './proxy-client-
|
|
4
|
-
export { a as AdaptivePlayoutController, b as AdaptivePlayoutDecision, c as AdaptivePlayoutOptions, d as AdaptivePlayoutSample, e as ApproachingEndEvent, f as ApproachingEndReason, aK as AvatarVideoSurface, aL as AvatarVideoSurfaceProps, B as BehaviorSnapshot, C as CallTranscript, h as CallTranscriptSegment, i as CartesiaTtsModel, j as ClipResult, k as ClosingTurnResult, l as CreditsLowEvent, D as DEFAULT_APPROACHING_END_LEAD_SECONDS, m as DEFAULT_CREDITS_LOW_LEAD_SECONDS, n as DEFAULT_GOVERNOR_CONFIG, o as DEFAULT_GRACE_CEILING_SECONDS, p as DEFAULT_GRACE_WINDOW_LEAD_SECONDS, q as DEFAULT_IDLE_SECONDS, r as DEFAULT_IDLE_WARN_LEAD_SECONDS, s as DEFAULT_TURN_TIMEOUT_SECONDS, E as EndReason, t as EndedEvent, u as ExtendResult, F as FishTtsModel, v as FreezeReadingFn, G as Governor, w as GovernorAction, x as GovernorConfig, y as GovernorSignal, z as GovernorState, H as GraceWindowClosedEvent, I as GraceWindowOpenEvent, J as GraceWindowState, K as IdleWarningEvent, M as InboundRtpCursor, N as InboundRtpReading, O as KnownBehaviorState, P as LLMProvider, Q as LLMSelection, R as LiveKitAvatarGrantState, S as LiveKitAvatarGrantStatus, T as LiveKitCapacityState, U as LiveKitConnectionStatus, V as LiveKitSessionRequest, W as LiveKitSessionStartResult, aM as LivePlaybackKeeper, X as MAX_RECONNECT_ATTEMPTS, Y as MAX_SESSION_INSTRUCTIONS_CHARS, aN as MIC_LEASE_ENDED_TIMEOUT_MS, aO as MicLease, aP as PlayableVideoElement, Z as ProxyClientOptions, _ as QualityCap, $ as RECONNECT_BACKOFF_MS,
|
|
3
|
+
import { g as AvatarSessionClient, A as AvatarVideoFit } from './proxy-client-BoUJWSkf.js';
|
|
4
|
+
export { a as AdaptivePlayoutController, b as AdaptivePlayoutDecision, c as AdaptivePlayoutOptions, d as AdaptivePlayoutSample, e as ApproachingEndEvent, f as ApproachingEndReason, aK as AvatarVideoSurface, aL as AvatarVideoSurfaceProps, B as BehaviorSnapshot, C as CallTranscript, h as CallTranscriptSegment, i as CartesiaTtsModel, j as ClipResult, k as ClosingTurnResult, l as CreditsLowEvent, D as DEFAULT_APPROACHING_END_LEAD_SECONDS, m as DEFAULT_CREDITS_LOW_LEAD_SECONDS, n as DEFAULT_GOVERNOR_CONFIG, o as DEFAULT_GRACE_CEILING_SECONDS, p as DEFAULT_GRACE_WINDOW_LEAD_SECONDS, q as DEFAULT_IDLE_SECONDS, r as DEFAULT_IDLE_WARN_LEAD_SECONDS, s as DEFAULT_TURN_TIMEOUT_SECONDS, E as EndReason, t as EndedEvent, u as ExtendResult, F as FishTtsModel, v as FreezeReadingFn, G as Governor, w as GovernorAction, x as GovernorConfig, y as GovernorSignal, z as GovernorState, H as GraceWindowClosedEvent, I as GraceWindowOpenEvent, J as GraceWindowState, K as IdleWarningEvent, M as InboundRtpCursor, N as InboundRtpReading, O as KnownBehaviorState, P as LLMProvider, Q as LLMSelection, R as LiveKitAvatarGrantState, S as LiveKitAvatarGrantStatus, T as LiveKitCapacityState, U as LiveKitConnectionStatus, V as LiveKitSessionRequest, W as LiveKitSessionStartResult, aM as LivePlaybackKeeper, X as MAX_RECONNECT_ATTEMPTS, Y as MAX_SESSION_INSTRUCTIONS_CHARS, aN as MIC_LEASE_ENDED_TIMEOUT_MS, aO as MicLease, aP as NETWORK_QUALITY_POLICY, aQ as NetworkQualityStatus, aR as PlayableVideoElement, Z as ProxyClientOptions, _ as QualityCap, $ as RECONNECT_BACKOFF_MS, aS as RealtimeAvatarCapacityError, aT as RealtimeAvatarLiveKitRoom, aU as RealtimeAvatarLiveKitRoomProps, a0 as RealtimeAvatarRequestOptions, a1 as RealtimeSessionApi, a2 as RealtimeSessionMedia, a3 as RealtimeSessionRoomSinks, a4 as ReconnectPolicy, a5 as ReconnectingEvent, a6 as RecoveryState, a7 as RetryStep, a8 as SessionBehavior, a9 as SessionClip, aa as SessionClocks, ab as SessionEndReason, ac as SessionLifecycleApi, ad as SessionLifecyclePhase, ae as SessionLifecyclePhaseKind, af as SessionLifecycleRoomBridge, ag as SessionLifecycleRoomBridgeProps, ah as SurfaceLayers, ai as TurnState, aj as TurnTimeoutEvent, ak as UseAvatarQualityGovernorInput, al as UseLiveKitAvatarGrantInput, am as UseRealtimeSessionInput, an as UseSessionLifecycleInput, ao as VoiceSpec, ap as VoiceSpecInput, aq as capacityErrorFromBusy, ar as capacityStateFromGrant, as as createProxyClient, au as knownBehaviorStates, av as mapTurnState, aw as readInboundRtp, ax as sessionBehaviorSchema, ay as sessionClipSchema, aV as shouldReplayPendingTurn, az as splitCallTranscript, aA as useAvatarAdaptivePlayoutDelay, aB as useAvatarPlayoutDelay, aC as useAvatarQualityGovernor, aD as useCallTranscript, aE as useLiveKitAvatarGrant, aG as useMicLease, aH as useRealtimeSession, aI as useReleaseMicLeaseOnTrackEnded, aJ as useSessionLifecycle } from './proxy-client-BoUJWSkf.js';
|
|
5
5
|
export { D as DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS } from './playout-delay-DWOc8iCl.js';
|
|
6
6
|
import 'zod';
|
|
7
7
|
import '@livekit/components-react';
|
package/dist/react.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useRef, useState, useEffect, useCallback, useMemo, createElement, Fragment } from 'react';
|
|
3
3
|
import { useRoomContext, useConnectionState, useTranscriptions, useLocalParticipant, RoomAudioRenderer, LiveKitRoom, useMaybeRoomContext, useVoiceAssistant, VideoTrack, useChat } from '@livekit/components-react';
|
|
4
|
-
import { ConnectionState, ConnectionQuality, RoomEvent, TrackEvent, Track,
|
|
4
|
+
import { ConnectionState, VideoQuality, ConnectionQuality, RoomEvent, TrackEvent, Track, ConnectionError, ConnectionErrorReason, DisconnectReason, Room } from 'livekit-client';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
7
|
// ../client/src/react/use-character-tools.ts
|
|
@@ -394,6 +394,13 @@ function normalizeRealtimeAvatarError(input) {
|
|
|
394
394
|
if (status === 409) {
|
|
395
395
|
return { code: "conflict", message: "That request is already in progress. Try again in a moment.", retryable: true };
|
|
396
396
|
}
|
|
397
|
+
if (status === 429 && rawCode === "concurrency_limit_reached") {
|
|
398
|
+
return {
|
|
399
|
+
code: rawCode,
|
|
400
|
+
message: userSafeMessage(rawMessage) ?? "The concurrent session limit is reached. Active and starting sessions count. End a session or wait for pending starts to clear, then retry.",
|
|
401
|
+
retryable: true
|
|
402
|
+
};
|
|
403
|
+
}
|
|
397
404
|
if (status === 429) {
|
|
398
405
|
return { code: "rate_limited", message: "Too many realtime requests. Please slow down and retry.", retryable: true };
|
|
399
406
|
}
|
|
@@ -1071,6 +1078,145 @@ var resolveLowCapQuality = (declaredLayerQualities, lowUnhealthy = 0) => {
|
|
|
1071
1078
|
return lowUnhealthy >= LOW_CAP_STEP_AFTER_UNHEALTHY ? sorted[0] : sorted[sorted.length - 2];
|
|
1072
1079
|
};
|
|
1073
1080
|
|
|
1081
|
+
// ../client/src/react/network-quality.ts
|
|
1082
|
+
var NETWORK_QUALITY_POLICY = {
|
|
1083
|
+
startupGraceMs: 3e3,
|
|
1084
|
+
maxSampleGapMs: 1500,
|
|
1085
|
+
minimumPackets: 20,
|
|
1086
|
+
lossWindowSamples: 3,
|
|
1087
|
+
lossRatio: 0.05,
|
|
1088
|
+
jitterSeconds: 0.1,
|
|
1089
|
+
impairedFps: 12,
|
|
1090
|
+
downgradeMs: 2e3,
|
|
1091
|
+
floorMs: 2e3,
|
|
1092
|
+
notifyAfterDowngradeMs: 5e3,
|
|
1093
|
+
recoverMs: 5e3,
|
|
1094
|
+
clearNoticeMs: 1e4
|
|
1095
|
+
};
|
|
1096
|
+
function readNetworkVideoSample(report) {
|
|
1097
|
+
const samples = [];
|
|
1098
|
+
report?.forEach((row) => {
|
|
1099
|
+
if (row.type !== "inbound-rtp" || (row.kind ?? row.mediaType) !== "video") return;
|
|
1100
|
+
const { timestamp, framesDecoded, packetsReceived, packetsLost, jitter } = row;
|
|
1101
|
+
if (typeof row.id !== "string" || ![timestamp, framesDecoded, packetsReceived, packetsLost, jitter].every(
|
|
1102
|
+
(n) => typeof n === "number" && Number.isFinite(n)
|
|
1103
|
+
) || timestamp < 0 || framesDecoded < 0 || packetsReceived < 0 || jitter < 0) return;
|
|
1104
|
+
samples.push({
|
|
1105
|
+
id: `${row.id}:${row.ssrc ?? ""}`,
|
|
1106
|
+
timestamp,
|
|
1107
|
+
framesDecoded,
|
|
1108
|
+
packetsReceived,
|
|
1109
|
+
packetsLost,
|
|
1110
|
+
jitter
|
|
1111
|
+
});
|
|
1112
|
+
});
|
|
1113
|
+
return samples.length === 1 ? samples[0] : null;
|
|
1114
|
+
}
|
|
1115
|
+
function initNetworkQuality(nowMs) {
|
|
1116
|
+
return {
|
|
1117
|
+
cap: "high",
|
|
1118
|
+
status: "unknown",
|
|
1119
|
+
sample: null,
|
|
1120
|
+
lastPollMs: null,
|
|
1121
|
+
openedMs: nowMs,
|
|
1122
|
+
badMs: 0,
|
|
1123
|
+
postDowngradeBadMs: 0,
|
|
1124
|
+
reducedBadMs: 0,
|
|
1125
|
+
cleanMs: 0,
|
|
1126
|
+
packetWindow: []
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
function stepNetworkQuality(previous, sample, nowMs, options) {
|
|
1130
|
+
const p = NETWORK_QUALITY_POLICY;
|
|
1131
|
+
const s = { ...previous, sample, lastPollMs: nowMs };
|
|
1132
|
+
const before = previous.sample;
|
|
1133
|
+
const pollMs = previous.lastPollMs === null ? 0 : nowMs - previous.lastPollMs;
|
|
1134
|
+
const elapsedMs = sample && before ? sample.timestamp - before.timestamp : 0;
|
|
1135
|
+
const interrupted = options.inhibited || pollMs <= 0 || pollMs > p.maxSampleGapMs;
|
|
1136
|
+
const valid = !interrupted && sample !== null && before !== null && sample.id === before.id && elapsedMs > 0 && elapsedMs <= p.maxSampleGapMs && sample.framesDecoded >= before.framesDecoded && sample.packetsReceived >= before.packetsReceived;
|
|
1137
|
+
if (!valid || nowMs - s.openedMs < p.startupGraceMs) {
|
|
1138
|
+
s.badMs = s.postDowngradeBadMs = s.reducedBadMs = s.cleanMs = 0;
|
|
1139
|
+
s.packetWindow = [];
|
|
1140
|
+
if (options.inhibited) s.sample = null;
|
|
1141
|
+
return s;
|
|
1142
|
+
}
|
|
1143
|
+
const received = sample.packetsReceived - before.packetsReceived;
|
|
1144
|
+
const lost = Math.max(0, sample.packetsLost - before.packetsLost);
|
|
1145
|
+
s.packetWindow = [...previous.packetWindow, { received, lost }].slice(-p.lossWindowSamples);
|
|
1146
|
+
const totals = s.packetWindow.reduce((sum, interval) => ({
|
|
1147
|
+
received: sum.received + interval.received,
|
|
1148
|
+
lost: sum.lost + interval.lost
|
|
1149
|
+
}), { received: 0, lost: 0 });
|
|
1150
|
+
const packets = totals.received + totals.lost;
|
|
1151
|
+
const fps = (sample.framesDecoded - before.framesDecoded) * 1e3 / elapsedMs;
|
|
1152
|
+
const loss = packets >= p.minimumPackets ? totals.lost / packets : null;
|
|
1153
|
+
const impaired = options.paused || fps < p.impairedFps;
|
|
1154
|
+
const bad = options.paused || impaired && (loss !== null && loss >= p.lossRatio || received >= p.minimumPackets && sample.jitter >= p.jitterSeconds);
|
|
1155
|
+
const clean = received > 0 && !options.paused && loss !== null && loss < p.lossRatio && sample.jitter < p.jitterSeconds && fps >= p.impairedFps;
|
|
1156
|
+
const duration = Math.min(pollMs, elapsedMs);
|
|
1157
|
+
s.badMs = bad ? previous.badMs + duration : 0;
|
|
1158
|
+
s.postDowngradeBadMs = bad && previous.cap !== "high" ? previous.postDowngradeBadMs + duration : 0;
|
|
1159
|
+
s.cleanMs = clean ? previous.cleanMs + duration : 0;
|
|
1160
|
+
s.reducedBadMs = bad && fps === 0 && previous.cap !== "high" ? previous.reducedBadMs + duration : 0;
|
|
1161
|
+
if (s.badMs >= p.downgradeMs && s.cap === "high") s.cap = "reduced";
|
|
1162
|
+
else if (s.reducedBadMs >= p.floorMs && fps === 0 && s.cap === "reduced") s.cap = "floor";
|
|
1163
|
+
if (s.postDowngradeBadMs >= p.notifyAfterDowngradeMs) s.status = "poor";
|
|
1164
|
+
if (s.cleanMs >= p.recoverMs) s.cap = "high";
|
|
1165
|
+
if (s.cleanMs >= p.clearNoticeMs) s.status = "healthy";
|
|
1166
|
+
return s;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// ../client/src/react/network-quality-binding.ts
|
|
1170
|
+
function bindNetworkQuality(publication, inhibited, notify, tickMs) {
|
|
1171
|
+
let disposed = false;
|
|
1172
|
+
let running = false;
|
|
1173
|
+
let state = initNetworkQuality(performance.now());
|
|
1174
|
+
const apply = () => {
|
|
1175
|
+
const qualities = (publication.trackInfo?.layers ?? []).map((l) => l.quality);
|
|
1176
|
+
const cap = state.cap === "high" ? VideoQuality.HIGH : resolveLowCapQuality(qualities, state.cap === "floor" ? 2 : 0);
|
|
1177
|
+
try {
|
|
1178
|
+
publication.setVideoQuality(cap);
|
|
1179
|
+
} catch {
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
const emit = (status) => {
|
|
1183
|
+
try {
|
|
1184
|
+
notify(status);
|
|
1185
|
+
} catch {
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
apply();
|
|
1189
|
+
emit("unknown");
|
|
1190
|
+
const tick = async () => {
|
|
1191
|
+
if (disposed || running) return;
|
|
1192
|
+
running = true;
|
|
1193
|
+
try {
|
|
1194
|
+
const track = publication.track;
|
|
1195
|
+
const stats = await track?.getRTCStatsReport?.();
|
|
1196
|
+
if (disposed || publication.track !== track) return;
|
|
1197
|
+
const prior = state;
|
|
1198
|
+
state = stepNetworkQuality(state, readNetworkVideoSample(stats), performance.now(), {
|
|
1199
|
+
paused: track?.streamState === Track.StreamState.Paused,
|
|
1200
|
+
inhibited: document.hidden || publication.isMuted || inhibited()
|
|
1201
|
+
});
|
|
1202
|
+
if (state.cap !== prior.cap) apply();
|
|
1203
|
+
if (state.status !== prior.status) emit(state.status);
|
|
1204
|
+
} catch {
|
|
1205
|
+
if (!disposed) state = { ...state, sample: null, packetWindow: [], badMs: 0, postDowngradeBadMs: 0, cleanMs: 0, reducedBadMs: 0 };
|
|
1206
|
+
} finally {
|
|
1207
|
+
running = false;
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
const timer = setInterval(() => {
|
|
1211
|
+
void tick();
|
|
1212
|
+
}, tickMs);
|
|
1213
|
+
return () => {
|
|
1214
|
+
disposed = true;
|
|
1215
|
+
clearInterval(timer);
|
|
1216
|
+
emit("unknown");
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1074
1220
|
// ../client/src/react/use-quality-governor.ts
|
|
1075
1221
|
var qualityToSignal = (q) => {
|
|
1076
1222
|
switch (q) {
|
|
@@ -1087,7 +1233,7 @@ var qualityToSignal = (q) => {
|
|
|
1087
1233
|
}
|
|
1088
1234
|
};
|
|
1089
1235
|
function useAvatarQualityGovernor(input) {
|
|
1090
|
-
const { enabled, freezeReading, config: policy = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
|
|
1236
|
+
const { enabled, freezeReading, onNetworkStatusChange, config: policy = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
|
|
1091
1237
|
const room = useMaybeRoomContext();
|
|
1092
1238
|
const { videoTrack } = useVoiceAssistant();
|
|
1093
1239
|
const {
|
|
@@ -1124,11 +1270,28 @@ function useAvatarQualityGovernor(input) {
|
|
|
1124
1270
|
]);
|
|
1125
1271
|
const freezeReadingRef = useRef(freezeReading);
|
|
1126
1272
|
freezeReadingRef.current = freezeReading;
|
|
1273
|
+
const networkCallback = useRef(onNetworkStatusChange);
|
|
1274
|
+
networkCallback.current = onNetworkStatusChange;
|
|
1127
1275
|
const targetPublication = videoTrack?.publication;
|
|
1128
1276
|
const targetParticipant = videoTrack?.participant;
|
|
1129
1277
|
const targetTrack = targetPublication?.track;
|
|
1130
1278
|
useEffect(() => {
|
|
1131
|
-
if (!
|
|
1279
|
+
if (!room || !targetPublication || !targetParticipant) return;
|
|
1280
|
+
if (enabled === "network-only") {
|
|
1281
|
+
return bindNetworkQuality(
|
|
1282
|
+
targetPublication,
|
|
1283
|
+
() => freezeReadingRef.current?.().inhibited ?? false,
|
|
1284
|
+
(status) => networkCallback.current?.(status),
|
|
1285
|
+
tickMs
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
if (!enabled) {
|
|
1289
|
+
try {
|
|
1290
|
+
targetPublication.setVideoQuality(VideoQuality.HIGH);
|
|
1291
|
+
} catch {
|
|
1292
|
+
}
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1132
1295
|
let pausedSinceTick = false;
|
|
1133
1296
|
let lastFreezeStat = null;
|
|
1134
1297
|
let jitterTrend = null;
|
|
@@ -1360,6 +1523,7 @@ function AvatarVideoSurface(props) {
|
|
|
1360
1523
|
// Keep the governor alive across presentation-intent changes; resetting it on
|
|
1361
1524
|
// every turn would re-apply LOW and a normal short turn could never earn HIGH.
|
|
1362
1525
|
enabled: adaptiveQuality,
|
|
1526
|
+
onNetworkStatusChange: props.onNetworkStatusChange,
|
|
1363
1527
|
freezeReading: frameFlow.freezeReading,
|
|
1364
1528
|
config: governorConfig
|
|
1365
1529
|
});
|
|
@@ -3214,8 +3378,13 @@ function createProxyClient(options) {
|
|
|
3214
3378
|
requestOptions
|
|
3215
3379
|
);
|
|
3216
3380
|
if (response.status === 429) {
|
|
3217
|
-
const
|
|
3218
|
-
|
|
3381
|
+
const value = await response.clone().json().catch(() => null);
|
|
3382
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
3383
|
+
const busy = value;
|
|
3384
|
+
const valid = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
|
|
3385
|
+
const queue2 = busy.queued === true && valid(busy.size) && valid(busy.retryAfterMs) || valid(busy.queue_size) && valid(busy.recommended_retry_ms);
|
|
3386
|
+
if (!("code" in busy) && queue2) return { status: "busy", busy };
|
|
3387
|
+
}
|
|
3219
3388
|
}
|
|
3220
3389
|
if (!response.ok) {
|
|
3221
3390
|
throw await RealtimeAvatarApiError.fromResponse(response);
|
|
@@ -3251,4 +3420,4 @@ function createProxyClient(options) {
|
|
|
3251
3420
|
};
|
|
3252
3421
|
}
|
|
3253
3422
|
|
|
3254
|
-
export { AdaptivePlayoutController, AvatarCall, AvatarVideoSurface, DEFAULT_APPROACHING_END_LEAD_SECONDS, DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS, DEFAULT_AVATAR_UNSTABLE_STALL_MS, DEFAULT_CREDITS_LOW_LEAD_SECONDS, DEFAULT_GOVERNOR_CONFIG, DEFAULT_GRACE_CEILING_SECONDS, DEFAULT_GRACE_WINDOW_LEAD_SECONDS, DEFAULT_IDLE_SECONDS, DEFAULT_IDLE_WARN_LEAD_SECONDS, DEFAULT_TURN_TIMEOUT_SECONDS, MAX_RECONNECT_ATTEMPTS, MAX_SESSION_INSTRUCTIONS_CHARS, MIC_LEASE_ENDED_TIMEOUT_MS, RECONNECT_BACKOFF_MS, RealtimeAvatarCapacityError, RealtimeAvatarLiveKitRoom, SessionLifecycleRoomBridge, capacityErrorFromBusy, capacityStateFromGrant, createProxyClient, knownBehaviorStates, mapTurnState, readInboundRtp, sessionBehaviorSchema, sessionClipSchema, shouldReplayPendingTurn, splitCallTranscript, useAvatarAdaptivePlayoutDelay, useAvatarCall, useAvatarPlayoutDelay, useAvatarQualityGovernor, useCallTranscript, useCharacterTools, useLiveKitAvatarGrant, useMicLease, useRealtimeSession, useReleaseMicLeaseOnTrackEnded, useSessionLifecycle };
|
|
3423
|
+
export { AdaptivePlayoutController, AvatarCall, AvatarVideoSurface, DEFAULT_APPROACHING_END_LEAD_SECONDS, DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS, DEFAULT_AVATAR_UNSTABLE_STALL_MS, DEFAULT_CREDITS_LOW_LEAD_SECONDS, DEFAULT_GOVERNOR_CONFIG, DEFAULT_GRACE_CEILING_SECONDS, DEFAULT_GRACE_WINDOW_LEAD_SECONDS, DEFAULT_IDLE_SECONDS, DEFAULT_IDLE_WARN_LEAD_SECONDS, DEFAULT_TURN_TIMEOUT_SECONDS, MAX_RECONNECT_ATTEMPTS, MAX_SESSION_INSTRUCTIONS_CHARS, MIC_LEASE_ENDED_TIMEOUT_MS, NETWORK_QUALITY_POLICY, RECONNECT_BACKOFF_MS, RealtimeAvatarCapacityError, RealtimeAvatarLiveKitRoom, SessionLifecycleRoomBridge, capacityErrorFromBusy, capacityStateFromGrant, createProxyClient, knownBehaviorStates, mapTurnState, readInboundRtp, sessionBehaviorSchema, sessionClipSchema, shouldReplayPendingTurn, splitCallTranscript, useAvatarAdaptivePlayoutDelay, useAvatarCall, useAvatarPlayoutDelay, useAvatarQualityGovernor, useCallTranscript, useCharacterTools, useLiveKitAvatarGrant, useMicLease, useRealtimeSession, useReleaseMicLeaseOnTrackEnded, useSessionLifecycle };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, RealtimeAvatarOptions, StartCallOptions, clipLibraryDeclarationSchema, verifyTranscript } from './index.js';
|
|
2
|
-
export { h as Asset, g as AssetKind, A as Avatar, l as AvatarClip, c as AvatarSourceSwap, b as AvatarUpdate, m as CallConnection, C as CallMode, a as CallPolicy, n as CallQueued, o as ClipDeclaration, f as ClipLibrary, d as ClipLibraryDeclaration, p as ClipLibraryPlan, e as ClipLibraryUpdate, q as ClipSource, r as ContextMessage, k as CreditBalance, E as EndCallOptions, s as EndCallReason, i as ListSessionsOptions, L as LoopRedirect, S as StartCallResult, T as TranscriptPayload, j as UsageSession, U as UsageSessionPage, V as VideoPolicy, t as isQueued } from './types-
|
|
2
|
+
export { h as Asset, g as AssetKind, A as Avatar, l as AvatarClip, c as AvatarSourceSwap, b as AvatarUpdate, m as CallConnection, C as CallMode, a as CallPolicy, n as CallQueued, o as ClipDeclaration, f as ClipLibrary, d as ClipLibraryDeclaration, p as ClipLibraryPlan, e as ClipLibraryUpdate, q as ClipSource, r as ContextMessage, k as CreditBalance, E as EndCallOptions, s as EndCallReason, i as ListSessionsOptions, L as LoopRedirect, S as StartCallResult, T as TranscriptPayload, j as UsageSession, U as UsageSessionPage, V as VideoPolicy, t as isQueued } from './types-B9GTrpx0.js';
|
|
3
3
|
import 'zod';
|
package/dist/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-
|
|
1
|
+
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-UVNDDNU2.js';
|
package/dist/tanstack-start.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as ProxyConfig } from './types-
|
|
2
|
-
import './types-
|
|
1
|
+
import { P as ProxyConfig } from './types-CJcTowDB.js';
|
|
2
|
+
import './types-B9GTrpx0.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* TanStack Start. Mount at `routes/api/realtime-avatar/$.ts` — the trailing `$` is Start's
|
package/dist/tanstack-start.js
CHANGED
|
@@ -343,10 +343,10 @@ interface components {
|
|
|
343
343
|
CreateApiKeyRequest: {
|
|
344
344
|
name: string;
|
|
345
345
|
/**
|
|
346
|
-
* @
|
|
346
|
+
* @description Deprecated. Accepted for older clients but ignored; all new keys use the same tic_ format.
|
|
347
347
|
* @enum {string}
|
|
348
348
|
*/
|
|
349
|
-
environment
|
|
349
|
+
environment?: "live" | "test";
|
|
350
350
|
/**
|
|
351
351
|
* @default [
|
|
352
352
|
* "realtime:write",
|
|
@@ -363,15 +363,16 @@ interface components {
|
|
|
363
363
|
keyId: string;
|
|
364
364
|
tenantId: string;
|
|
365
365
|
name: string;
|
|
366
|
-
/** @enum {string} */
|
|
367
|
-
environment: "live" | "test";
|
|
368
366
|
redactedKey: string;
|
|
367
|
+
/** @default false */
|
|
368
|
+
canReveal: boolean;
|
|
369
369
|
scopes: ("*" | "api_keys:write" | "credits:read" | "avatars:read" | "avatars:write" | "realtime:write" | "usage:read" | "usage:write")[];
|
|
370
370
|
/** @enum {string} */
|
|
371
371
|
status: "active" | "revoked" | "expired";
|
|
372
372
|
spendLimitCreditMicros: number | null;
|
|
373
373
|
createdAt: string;
|
|
374
374
|
expiresAt: string | null;
|
|
375
|
+
/** Format: starts_with */
|
|
375
376
|
apiKey: string;
|
|
376
377
|
};
|
|
377
378
|
Asset: {
|
|
@@ -482,8 +483,6 @@ interface components {
|
|
|
482
483
|
issues: string[];
|
|
483
484
|
firstFrameUrl: string | null;
|
|
484
485
|
lastFrameUrl: string | null;
|
|
485
|
-
trimStartMs: number | null;
|
|
486
|
-
trimEndMs: number | null;
|
|
487
486
|
} | null;
|
|
488
487
|
error: {
|
|
489
488
|
code: string;
|
|
@@ -522,6 +521,13 @@ interface components {
|
|
|
522
521
|
};
|
|
523
522
|
};
|
|
524
523
|
};
|
|
524
|
+
ReviewAvatarClipRequest: {
|
|
525
|
+
clipId: string;
|
|
526
|
+
uploadAssetId: string;
|
|
527
|
+
expectedRevision: number;
|
|
528
|
+
expectedAnchorVersion: number;
|
|
529
|
+
reason: string;
|
|
530
|
+
};
|
|
525
531
|
PutAvatarClipsRequest: {
|
|
526
532
|
expectedRevision: number;
|
|
527
533
|
clips: {
|
|
@@ -573,8 +579,6 @@ interface components {
|
|
|
573
579
|
issues: string[];
|
|
574
580
|
firstFrameUrl: string | null;
|
|
575
581
|
lastFrameUrl: string | null;
|
|
576
|
-
trimStartMs: number | null;
|
|
577
|
-
trimEndMs: number | null;
|
|
578
582
|
} | null;
|
|
579
583
|
error: {
|
|
580
584
|
code: string;
|
|
@@ -659,6 +663,16 @@ interface components {
|
|
|
659
663
|
grantedScopes?: ("*" | "api_keys:write" | "credits:read" | "avatars:read" | "avatars:write" | "realtime:write" | "usage:read" | "usage:write")[];
|
|
660
664
|
/** @description Present on 402 — where to send the user to top up. */
|
|
661
665
|
billingUrl?: string;
|
|
666
|
+
/** @description On concurrency_limit_reached: the workspace's concurrent session limit. */
|
|
667
|
+
maxConcurrentSessions?: number;
|
|
668
|
+
/** @description Legacy concurrency count: occupied reservations, including active, connecting and starting sessions. Not the number of active conversations. */
|
|
669
|
+
liveSessions?: number;
|
|
670
|
+
/** @description On concurrency_limit_reached: counted reservations with started media, observed at refusal. */
|
|
671
|
+
activeSessions?: number;
|
|
672
|
+
/** @description On concurrency_limit_reached: counted reservations with an attached session that has not started media. */
|
|
673
|
+
connectingSessions?: number;
|
|
674
|
+
/** @description On concurrency_limit_reached: counted in-flight starts with no attached session yet. */
|
|
675
|
+
pendingSessions?: number;
|
|
662
676
|
} & {
|
|
663
677
|
[key: string]: unknown;
|
|
664
678
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CallMode, a as CallPolicy } from './types-
|
|
1
|
+
import { C as CallMode, a as CallPolicy } from './types-B9GTrpx0.js';
|
|
2
2
|
|
|
3
3
|
/** The three things a caller can ask the proxy to do. Gate on these, not on URLs. */
|
|
4
4
|
type ProxyOperation = "connect" | "end" | "avatars" | "credits";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "realtime-avatar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.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",
|