realtime-avatar 0.11.0 → 0.11.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.
@@ -1,4 +1,4 @@
1
- import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-MBQ2VKLC.js';
1
+ import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-X3XXLAJJ.js';
2
2
 
3
3
  // ../proxy/src/config.ts
4
4
  var json = (body, status = 200) => new Response(JSON.stringify(body), {
@@ -218,7 +218,7 @@ function isTransient(cause) {
218
218
 
219
219
  // ../http-client/src/client.ts
220
220
  var DEFAULT_BASE_URL = "https://realtimeavatar.ai/api/v1";
221
- var SDK_VERSION = "0.11.0";
221
+ var SDK_VERSION = "0.11.1";
222
222
  var RealtimeAvatar = class {
223
223
  #apiKey;
224
224
  #baseUrl;
package/dist/express.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
- import './types-FoJMJimV.js';
1
+ import { P as ProxyConfig } from './types-9a0bRdXl.js';
2
+ import './types-nxdohaiH.js';
3
3
 
4
4
  type Expressish = {
5
5
  method: string;
package/dist/express.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
- import './chunk-MBQ2VKLC.js';
1
+ import { createProxyHandler } from './chunk-2TQVKQJJ.js';
2
+ import './chunk-X3XXLAJJ.js';
3
3
 
4
4
  // ../proxy/src/express.ts
5
5
  function realtimeAvatarExpress(config) {
package/dist/hono.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
- import './types-FoJMJimV.js';
1
+ import { P as ProxyConfig } from './types-9a0bRdXl.js';
2
+ import './types-nxdohaiH.js';
3
3
 
4
4
  /**
5
5
  * Hono (and anything else built on Fetch handlers — Workers, Bun, Deno).
package/dist/hono.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
- import './chunk-MBQ2VKLC.js';
1
+ import { createProxyHandler } from './chunk-2TQVKQJJ.js';
2
+ import './chunk-X3XXLAJJ.js';
3
3
 
4
4
  // ../proxy/src/hono.ts
5
5
  function realtimeAvatarHono(config) {
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-FoJMJimV.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-FoJMJimV.js';
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-nxdohaiH.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-nxdohaiH.js';
3
3
  import { z } from 'zod';
4
4
 
5
5
  interface RealtimeAvatarOptions {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-MBQ2VKLC.js';
1
+ export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-X3XXLAJJ.js';
package/dist/nextjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
- import './types-FoJMJimV.js';
1
+ import { P as ProxyConfig } from './types-9a0bRdXl.js';
2
+ import './types-nxdohaiH.js';
3
3
 
4
4
  /**
5
5
  * App Router. Mount at `app/api/realtime-avatar/[...path]/route.ts`:
package/dist/nextjs.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
- import './chunk-MBQ2VKLC.js';
1
+ import { createProxyHandler } from './chunk-2TQVKQJJ.js';
2
+ import './chunk-X3XXLAJJ.js';
3
3
 
4
4
  // ../proxy/src/nextjs.ts
5
5
  function createRealtimeAvatarRoute(config) {
@@ -468,7 +468,14 @@ type AvatarVideoSurfaceProps = {
468
468
  idleReturnDelayMs?: number;
469
469
  /**
470
470
  * Maximum time without a newly presented decoded frame before the live layer is
471
- * treated as stalled and immediately replaced by the idle/poster floor. Default 800ms.
471
+ * treated as stalled and replaced by the idle/poster floor — i.e. how long the LAST
472
+ * live frame is held through a network gap. Default
473
+ * {@link DEFAULT_AVATAR_FRAME_STALL_MS} (2 s). Once two stalls land inside 15 s the
474
+ * link is treated as unstable and the hold steps up to
475
+ * {@link DEFAULT_AVATAR_UNSTABLE_STALL_MS} (4 s) until the window clears, so a
476
+ * flapping link settles on a briefly frozen face rather than a body swap per gap.
477
+ * A disconnect, a turn end (track muted) and a track that never presented a frame
478
+ * are not stalls and do not wait on this.
472
479
  */
473
480
  frameStallMs?: number;
474
481
  /** Extra className for the box (the layers fill it). */
@@ -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-CWvT16wz.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-CWvT16wz.js';
4
+ import { L as LiveKitSessionGrant, A as AvatarVideoFit } from './proxy-client-D1Zm7reb.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-D1Zm7reb.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.d.ts CHANGED
@@ -1,12 +1,21 @@
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-CWvT16wz.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 PlayableVideoElement, Z as ProxyClientOptions, _ as QualityCap, $ as RECONNECT_BACKOFF_MS, aQ as RealtimeAvatarCapacityError, aR as RealtimeAvatarLiveKitRoom, aS 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, aT 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-CWvT16wz.js';
3
+ import { g as AvatarSessionClient, A as AvatarVideoFit } from './proxy-client-D1Zm7reb.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 PlayableVideoElement, Z as ProxyClientOptions, _ as QualityCap, $ as RECONNECT_BACKOFF_MS, aQ as RealtimeAvatarCapacityError, aR as RealtimeAvatarLiveKitRoom, aS 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, aT 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-D1Zm7reb.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';
8
8
  import 'livekit-client';
9
9
 
10
+ /**
11
+ * Once a link has proven unstable, hold the frozen live frame this long before
12
+ * falling back to the idle floor. Measured on a prod rtx6000 call through a
13
+ * 900 kbit / 150 ms / 10 % loss link (2026-09-09): after the opening, presented-frame
14
+ * gaps cluster at 650–1150 ms with two multi-second outages around simulcast layer
15
+ * switches. Nothing shorter than a few seconds is worth a body swap on such a link.
16
+ */
17
+ declare const DEFAULT_AVATAR_UNSTABLE_STALL_MS = 4000;
18
+
10
19
  declare function useCharacterTools(tools: Record<string, RegisteredTool>, options?: {
11
20
  onResult?: (event: {
12
21
  name: string;
@@ -120,4 +129,4 @@ declare function useAvatarCall(props: AvatarCallProps): {
120
129
  /** One component: a live character on screen. */
121
130
  declare function AvatarCall(props: AvatarCallProps): ReactNode;
122
131
 
123
- export { AvatarCall, type AvatarCallEndReason, type AvatarCallHandle, type AvatarCallProps, type AvatarCallStatus, AvatarSessionClient, AvatarVideoFit, useAvatarCall, useCharacterTools };
132
+ export { AvatarCall, type AvatarCallEndReason, type AvatarCallHandle, type AvatarCallProps, type AvatarCallStatus, AvatarSessionClient, AvatarVideoFit, DEFAULT_AVATAR_UNSTABLE_STALL_MS, useAvatarCall, useCharacterTools };
package/dist/react.js CHANGED
@@ -1234,9 +1234,48 @@ var FrameRecovery = class {
1234
1234
  return this.ready;
1235
1235
  }
1236
1236
  };
1237
+ var AVATAR_FIRST_FRAME_GRACE_MS = 1e3;
1238
+ function firstFrameWaitFreezeMs(waitedMs) {
1239
+ if (!Number.isFinite(waitedMs) || waitedMs <= AVATAR_FIRST_FRAME_GRACE_MS) return 0;
1240
+ return waitedMs - AVATAR_FIRST_FRAME_GRACE_MS;
1241
+ }
1242
+ var DEFAULT_AVATAR_UNSTABLE_STALL_MS = 4e3;
1243
+ var AVATAR_UNSTABLE_LINK_STALLS = 2;
1244
+ var AVATAR_UNSTABLE_LINK_WINDOW_MS = 15e3;
1245
+ var StallEscalation = class {
1246
+ constructor(baseMs, unstableMs = DEFAULT_AVATAR_UNSTABLE_STALL_MS, windowMs = AVATAR_UNSTABLE_LINK_WINDOW_MS, stallsToEscalate = AVATAR_UNSTABLE_LINK_STALLS) {
1247
+ this.baseMs = baseMs;
1248
+ this.windowMs = windowMs;
1249
+ this.stallsToEscalate = stallsToEscalate;
1250
+ this.unstableMs = Math.max(baseMs, unstableMs);
1251
+ }
1252
+ baseMs;
1253
+ windowMs;
1254
+ stallsToEscalate;
1255
+ stallsAtMs = [];
1256
+ unstableMs;
1257
+ /** Record one stall EPISODE (the moment the live layer is hidden), not one poll tick. */
1258
+ recordStall(nowMs) {
1259
+ this.prune(nowMs);
1260
+ this.stallsAtMs.push(nowMs);
1261
+ }
1262
+ /** The threshold in force right now. */
1263
+ thresholdMs(nowMs) {
1264
+ this.prune(nowMs);
1265
+ return this.stallsAtMs.length >= this.stallsToEscalate ? this.unstableMs : this.baseMs;
1266
+ }
1267
+ /** Is the link currently considered unstable (escalated)? */
1268
+ unstable(nowMs) {
1269
+ return this.thresholdMs(nowMs) !== this.baseMs;
1270
+ }
1271
+ prune(nowMs) {
1272
+ const cutoff = nowMs - this.windowMs;
1273
+ while (this.stallsAtMs.length > 0 && this.stallsAtMs[0] < cutoff) this.stallsAtMs.shift();
1274
+ }
1275
+ };
1237
1276
 
1238
1277
  // ../client/src/react/avatar-video-surface.ts
1239
- var DEFAULT_AVATAR_FRAME_STALL_MS = 800;
1278
+ var DEFAULT_AVATAR_FRAME_STALL_MS = 2e3;
1240
1279
  var AVATAR_FRAME_GAP_FREEZE_FLOOR_MS = 100;
1241
1280
  function AvatarVideoSurface(props) {
1242
1281
  const {
@@ -1445,6 +1484,7 @@ function isFrameFreezeInhibited(snapshot) {
1445
1484
  function useLiveFrameFlow(wrapRef, trackProducing, trackIdentity, stallAfterMs) {
1446
1485
  const boundedStallMs = normalizeFrameStallMs(stallAfterMs);
1447
1486
  const recovery = useMemo(() => new FrameRecovery(boundedStallMs), [trackIdentity, boundedStallMs]);
1487
+ const escalation = useMemo(() => new StallEscalation(boundedStallMs), [trackIdentity, boundedStallMs]);
1448
1488
  const [flowing, setFlowing] = useState(false);
1449
1489
  const [seenFrame, setSeenFrame] = useState(false);
1450
1490
  const flowingRef = useRef(false);
@@ -1452,14 +1492,16 @@ function useLiveFrameFlow(wrapRef, trackProducing, trackIdentity, stallAfterMs)
1452
1492
  seenFrame: false,
1453
1493
  lastFrameAtMs: null,
1454
1494
  maxGapMs: 0,
1455
- resumePending: false
1495
+ resumePending: false,
1496
+ producingSinceMs: null
1456
1497
  });
1457
1498
  useEffect(() => {
1458
1499
  sampleRef.current = {
1459
1500
  seenFrame: false,
1460
1501
  lastFrameAtMs: null,
1461
1502
  maxGapMs: 0,
1462
- resumePending: document.visibilityState !== "visible"
1503
+ resumePending: document.visibilityState !== "visible",
1504
+ producingSinceMs: trackProducing ? Date.now() : null
1463
1505
  };
1464
1506
  flowingRef.current = false;
1465
1507
  setSeenFrame(false);
@@ -1477,6 +1519,7 @@ function useLiveFrameFlow(wrapRef, trackProducing, trackIdentity, stallAfterMs)
1477
1519
  lastCurrentTime = video?.currentTime ?? lastCurrentTime;
1478
1520
  const firstFrame = !previous.seenFrame;
1479
1521
  sampleRef.current = {
1522
+ producingSinceMs: previous.producingSinceMs,
1480
1523
  seenFrame: true,
1481
1524
  lastFrameAtMs: now,
1482
1525
  // A hidden tab/bfcache resume is a local scheduling gap, not network
@@ -1488,6 +1531,7 @@ function useLiveFrameFlow(wrapRef, trackProducing, trackIdentity, stallAfterMs)
1488
1531
  resumePending: false
1489
1532
  };
1490
1533
  if (firstFrame) setSeenFrame(true);
1534
+ recovery.stallAfterMs = escalation.thresholdMs(now);
1491
1535
  const nextFlowing = recovery.frame(now);
1492
1536
  if (flowingRef.current !== nextFlowing) {
1493
1537
  flowingRef.current = nextFlowing;
@@ -1533,13 +1577,19 @@ function useLiveFrameFlow(wrapRef, trackProducing, trackIdentity, stallAfterMs)
1533
1577
  lastCurrentTime = video.currentTime;
1534
1578
  markFrame();
1535
1579
  }
1580
+ const nowMs = Date.now();
1581
+ const stallAfterMs2 = escalation.thresholdMs(nowMs);
1582
+ recovery.stallAfterMs = stallAfterMs2;
1536
1583
  const frameFresh = isFrameFlowingAt({
1537
1584
  seenFrame: sampleRef.current.seenFrame,
1538
1585
  lastFrameAtMs: sampleRef.current.lastFrameAtMs,
1539
- nowMs: Date.now(),
1540
- stallAfterMs: boundedStallMs
1586
+ nowMs,
1587
+ stallAfterMs: stallAfterMs2
1541
1588
  });
1542
- if (!frameFresh && sampleRef.current.seenFrame) recovery.stall();
1589
+ if (!frameFresh && sampleRef.current.seenFrame) {
1590
+ if (flowingRef.current) escalation.recordStall(nowMs);
1591
+ recovery.stall();
1592
+ }
1543
1593
  const nextFlowing = frameFresh && recovery.ready;
1544
1594
  if (flowingRef.current !== nextFlowing) {
1545
1595
  flowingRef.current = nextFlowing;
@@ -1553,11 +1603,14 @@ function useLiveFrameFlow(wrapRef, trackProducing, trackIdentity, stallAfterMs)
1553
1603
  stopObserving();
1554
1604
  cancelFrameCallback();
1555
1605
  };
1556
- }, [wrapRef, trackProducing, trackIdentity, boundedStallMs, recovery]);
1606
+ }, [wrapRef, trackProducing, trackIdentity, boundedStallMs, recovery, escalation]);
1557
1607
  const freezeReading = useCallback(() => {
1558
1608
  const sample = sampleRef.current;
1559
1609
  const lastFrameAtMs = sample.lastFrameAtMs;
1560
1610
  const hidden = typeof document !== "undefined" && document.visibilityState !== "visible";
1611
+ if (!hidden && !sample.resumePending && trackProducing && !sample.seenFrame && sample.producingSinceMs !== null) {
1612
+ return { freezeMsInWindow: firstFrameWaitFreezeMs(Date.now() - sample.producingSinceMs), inhibited: false };
1613
+ }
1561
1614
  const inhibited = isFrameFreezeInhibited({
1562
1615
  hidden,
1563
1616
  resumePending: sample.resumePending,
@@ -3164,4 +3217,4 @@ function createProxyClient(options) {
3164
3217
  };
3165
3218
  }
3166
3219
 
3167
- export { AdaptivePlayoutController, AvatarCall, AvatarVideoSurface, DEFAULT_APPROACHING_END_LEAD_SECONDS, DEFAULT_AVATAR_PLAYOUT_DELAY_SECONDS, 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 };
3220
+ 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 };
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-FoJMJimV.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-nxdohaiH.js';
3
3
  import 'zod';
package/dist/server.js CHANGED
@@ -1 +1 @@
1
- export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-MBQ2VKLC.js';
1
+ export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-X3XXLAJJ.js';
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
- import './types-FoJMJimV.js';
1
+ import { P as ProxyConfig } from './types-9a0bRdXl.js';
2
+ import './types-nxdohaiH.js';
3
3
 
4
4
  /**
5
5
  * TanStack Start. Mount at `routes/api/realtime-avatar/$.ts` — the trailing `$` is Start's
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
- import './chunk-MBQ2VKLC.js';
1
+ import { createProxyHandler } from './chunk-2TQVKQJJ.js';
2
+ import './chunk-X3XXLAJJ.js';
3
3
 
4
4
  // src/tanstack-start.ts
5
5
  function realtimeAvatarServerRoute(config) {
@@ -1,4 +1,4 @@
1
- import { C as CallMode, a as CallPolicy } from './types-FoJMJimV.js';
1
+ import { C as CallMode, a as CallPolicy } from './types-nxdohaiH.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";
@@ -645,6 +645,11 @@ interface components {
645
645
  documentation: string;
646
646
  /** @description Set when the failure is worth retrying as-is. */
647
647
  retryable?: boolean;
648
+ /**
649
+ * Format: uuid
650
+ * @description Server-generated correlation ID, also returned in X-Request-ID on correlated failures. Quote this when contacting support. Detailed diagnostics require separate operational access.
651
+ */
652
+ requestId?: string;
648
653
  /**
649
654
  * @description Present on `403 insufficient_scope` — the one scope this operation needed and the key did not carry. Repeated in the `WWW-Authenticate` challenge as `scope=`.
650
655
  * @enum {string}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "realtime-avatar",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
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",