realtime-avatar 0.11.2 → 0.11.3

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.
@@ -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.2";
221
+ var SDK_VERSION = "0.11.3";
222
222
  var RealtimeAvatar = class {
223
223
  #apiKey;
224
224
  #baseUrl;
@@ -1,4 +1,4 @@
1
- import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-SKXUGNEK.js';
1
+ import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-K726WCDN.js';
2
2
 
3
3
  // ../proxy/src/config.ts
4
4
  var json = (body, status = 200) => new Response(JSON.stringify(body), {
package/dist/express.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-MJJ6GSAU.js';
2
- import './chunk-SKXUGNEK.js';
1
+ import { createProxyHandler } from './chunk-OVAQBIZ2.js';
2
+ import './chunk-K726WCDN.js';
3
3
 
4
4
  // ../proxy/src/express.ts
5
5
  function realtimeAvatarExpress(config) {
package/dist/hono.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-MJJ6GSAU.js';
2
- import './chunk-SKXUGNEK.js';
1
+ import { createProxyHandler } from './chunk-OVAQBIZ2.js';
2
+ import './chunk-K726WCDN.js';
3
3
 
4
4
  // ../proxy/src/hono.ts
5
5
  function realtimeAvatarHono(config) {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-SKXUGNEK.js';
1
+ export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-K726WCDN.js';
package/dist/nextjs.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-MJJ6GSAU.js';
2
- import './chunk-SKXUGNEK.js';
1
+ import { createProxyHandler } from './chunk-OVAQBIZ2.js';
2
+ import './chunk-K726WCDN.js';
3
3
 
4
4
  // ../proxy/src/nextjs.ts
5
5
  function createRealtimeAvatarRoute(config) {
@@ -378,8 +378,24 @@ declare const DEFAULT_GOVERNOR_CONFIG: GovernorConfig;
378
378
  interface Governor {
379
379
  state: GovernorState;
380
380
  cap: QualityCap;
381
- /** Consecutive failed up-probes — drives the exponential dwell backoff. */
381
+ /** Consecutive failed up-probes. Drives the exponential dwell backoff.
382
+ *
383
+ * NOT a signal about the low rung. It counts attempts to reach HIGH that did not
384
+ * survive, which says nothing about whether the rung below HIGH is holdable. Using it
385
+ * to pick WHICH rung "low" means was a real regression: see `lowUnhealthy`. */
382
386
  failures: number;
387
+ /** Unhealthy ticks observed while ALREADY on the low cap.
388
+ *
389
+ * This is the only honest evidence that the low rung itself is not affordable, and it
390
+ * is what steps the cap down to the bottom of the ladder. It exists because `failures`
391
+ * looked like it would do the job and does not: a starved OPENING reports the wait for
392
+ * the first frame as a freeze (`firstFrameWaitFreezeMs`), so any session whose first
393
+ * frame is slower than about a second fails its opening probation and lands on
394
+ * `failures = 1` before the link has been asked to carry anything. Measured on prod,
395
+ * first frames ran 2.4 s to 28 s, i.e. essentially every call. Keying the rung step on
396
+ * `failures` therefore sent the FIRST demote straight to the bottom rung, including on
397
+ * a call that recorded zero freezes. Reset whenever the cap returns to high. */
398
+ lowUnhealthy: number;
383
399
  /** Wall-clock ms the current state was entered (for dwell/clean/probe timing). */
384
400
  enteredAtMs: number;
385
401
  /** Wall-clock ms of the last healthy tick in the current low period (clean-window
@@ -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-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';
4
+ import { L as LiveKitSessionGrant, A as AvatarVideoFit } from './proxy-client-8cQOLLE_.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-8cQOLLE_.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';
@@ -747,6 +747,7 @@ var initGovernor = (nowMs, openingCap = "low") => ({
747
747
  state: openingCap === "high" ? "opening_high" : "opening",
748
748
  cap: openingCap,
749
749
  failures: 0,
750
+ lowUnhealthy: 0,
750
751
  enteredAtMs: nowMs,
751
752
  healthySinceMs: null
752
753
  });
@@ -794,12 +795,14 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
794
795
  const healthy = isHealthy(s);
795
796
  const healthySince = healthy ? g.healthySinceMs ?? nowMs : null;
796
797
  const resetFailures = healthy && healthySince !== null && nowMs - healthySince >= cfg.healthyResetMs;
798
+ const lowUnhealthy = healthy ? g.lowUnhealthy : g.lowUnhealthy + 1;
797
799
  const dwellDone = nowMs - g.enteredAtMs >= dwellMs(g.failures, cfg);
798
800
  if (dwellDone && healthy) {
799
801
  return {
800
802
  governor: {
801
803
  ...enter(g, "cap_low_eligible", "low", nowMs),
802
804
  failures: resetFailures ? 0 : g.failures,
805
+ lowUnhealthy: resetFailures ? 0 : lowUnhealthy,
803
806
  healthySinceMs: nowMs
804
807
  }
805
808
  };
@@ -808,13 +811,14 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
808
811
  governor: {
809
812
  ...g,
810
813
  healthySinceMs: healthySince,
811
- failures: resetFailures ? 0 : g.failures
814
+ failures: resetFailures ? 0 : g.failures,
815
+ lowUnhealthy: resetFailures ? 0 : lowUnhealthy
812
816
  }
813
817
  };
814
818
  }
815
819
  case "cap_low_eligible": {
816
820
  if (!isHealthy(s)) {
817
- return { governor: { ...g, healthySinceMs: null } };
821
+ return { governor: { ...g, healthySinceMs: null, lowUnhealthy: g.lowUnhealthy + 1 } };
818
822
  }
819
823
  const cleanSince = g.healthySinceMs ?? nowMs;
820
824
  if (nowMs - cleanSince >= cfg.cleanMs) {
@@ -827,7 +831,9 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
827
831
  }
828
832
  case "probing_up": {
829
833
  if (nowMs - g.enteredAtMs >= cfg.probeMs) {
830
- return { governor: { ...enter(g, "cap_high_stable", "high", nowMs), failures: 0 } };
834
+ return {
835
+ governor: { ...enter(g, "cap_high_stable", "high", nowMs), failures: 0, lowUnhealthy: 0 }
836
+ };
831
837
  }
832
838
  return { governor: g };
833
839
  }
@@ -837,10 +843,11 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
837
843
  return { governor: g };
838
844
  }
839
845
  };
840
- var resolveLowCapQuality = (declaredLayerQualities, failures = 0) => {
846
+ var LOW_CAP_STEP_AFTER_UNHEALTHY = 2;
847
+ var resolveLowCapQuality = (declaredLayerQualities, lowUnhealthy = 0) => {
841
848
  const sorted = [...declaredLayerQualities].sort((a, b) => a - b);
842
849
  if (sorted.length < 2) return 1;
843
- return failures >= 1 ? sorted[0] : sorted[sorted.length - 2];
850
+ return lowUnhealthy >= LOW_CAP_STEP_AFTER_UNHEALTHY ? sorted[0] : sorted[sorted.length - 2];
844
851
  };
845
852
 
846
853
  // ../client/src/react/use-quality-governor.ts
@@ -960,11 +967,11 @@ function useAvatarQualityGovernor(input) {
960
967
  return { freezeMs: 0, jitterRising: false };
961
968
  }
962
969
  };
963
- const applyCap = (cap, failures = 0) => {
970
+ const applyCap = (cap, lowUnhealthy = 0) => {
964
971
  try {
965
972
  const lowCap = resolveLowCapQuality(
966
973
  (targetPublication?.trackInfo?.layers ?? []).map((l) => l.quality),
967
- failures
974
+ lowUnhealthy
968
975
  );
969
976
  targetPublication?.setVideoQuality?.(cap === "low" ? lowCap : VideoQuality.HIGH);
970
977
  } catch {
@@ -989,13 +996,13 @@ function useAvatarQualityGovernor(input) {
989
996
  pausedSinceTick = false;
990
997
  const { governor, action } = step(gov, signal, Date.now(), config);
991
998
  gov = governor;
992
- if (action) applyCap(action.setCap, gov.failures);
999
+ if (action) applyCap(action.setCap, gov.lowUnhealthy);
993
1000
  } catch {
994
1001
  } finally {
995
1002
  tickRunning = false;
996
1003
  }
997
1004
  };
998
- applyCap(gov.cap, gov.failures);
1005
+ applyCap(gov.cap, gov.lowUnhealthy);
999
1006
  const handle = setInterval(() => void tick(), tickMs);
1000
1007
  return () => {
1001
1008
  disposed = true;
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-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';
3
+ import { g as AvatarSessionClient, A as AvatarVideoFit } from './proxy-client-8cQOLLE_.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-8cQOLLE_.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
@@ -948,6 +948,7 @@ var initGovernor = (nowMs, openingCap = "low") => ({
948
948
  state: openingCap === "high" ? "opening_high" : "opening",
949
949
  cap: openingCap,
950
950
  failures: 0,
951
+ lowUnhealthy: 0,
951
952
  enteredAtMs: nowMs,
952
953
  healthySinceMs: null
953
954
  });
@@ -995,12 +996,14 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
995
996
  const healthy = isHealthy(s);
996
997
  const healthySince = healthy ? g.healthySinceMs ?? nowMs : null;
997
998
  const resetFailures = healthy && healthySince !== null && nowMs - healthySince >= cfg.healthyResetMs;
999
+ const lowUnhealthy = healthy ? g.lowUnhealthy : g.lowUnhealthy + 1;
998
1000
  const dwellDone = nowMs - g.enteredAtMs >= dwellMs(g.failures, cfg);
999
1001
  if (dwellDone && healthy) {
1000
1002
  return {
1001
1003
  governor: {
1002
1004
  ...enter(g, "cap_low_eligible", "low", nowMs),
1003
1005
  failures: resetFailures ? 0 : g.failures,
1006
+ lowUnhealthy: resetFailures ? 0 : lowUnhealthy,
1004
1007
  healthySinceMs: nowMs
1005
1008
  }
1006
1009
  };
@@ -1009,13 +1012,14 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
1009
1012
  governor: {
1010
1013
  ...g,
1011
1014
  healthySinceMs: healthySince,
1012
- failures: resetFailures ? 0 : g.failures
1015
+ failures: resetFailures ? 0 : g.failures,
1016
+ lowUnhealthy: resetFailures ? 0 : lowUnhealthy
1013
1017
  }
1014
1018
  };
1015
1019
  }
1016
1020
  case "cap_low_eligible": {
1017
1021
  if (!isHealthy(s)) {
1018
- return { governor: { ...g, healthySinceMs: null } };
1022
+ return { governor: { ...g, healthySinceMs: null, lowUnhealthy: g.lowUnhealthy + 1 } };
1019
1023
  }
1020
1024
  const cleanSince = g.healthySinceMs ?? nowMs;
1021
1025
  if (nowMs - cleanSince >= cfg.cleanMs) {
@@ -1028,7 +1032,9 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
1028
1032
  }
1029
1033
  case "probing_up": {
1030
1034
  if (nowMs - g.enteredAtMs >= cfg.probeMs) {
1031
- return { governor: { ...enter(g, "cap_high_stable", "high", nowMs), failures: 0 } };
1035
+ return {
1036
+ governor: { ...enter(g, "cap_high_stable", "high", nowMs), failures: 0, lowUnhealthy: 0 }
1037
+ };
1032
1038
  }
1033
1039
  return { governor: g };
1034
1040
  }
@@ -1038,10 +1044,11 @@ var step = (g, s, nowMs, cfg = DEFAULT_GOVERNOR_CONFIG) => {
1038
1044
  return { governor: g };
1039
1045
  }
1040
1046
  };
1041
- var resolveLowCapQuality = (declaredLayerQualities, failures = 0) => {
1047
+ var LOW_CAP_STEP_AFTER_UNHEALTHY = 2;
1048
+ var resolveLowCapQuality = (declaredLayerQualities, lowUnhealthy = 0) => {
1042
1049
  const sorted = [...declaredLayerQualities].sort((a, b) => a - b);
1043
1050
  if (sorted.length < 2) return 1;
1044
- return failures >= 1 ? sorted[0] : sorted[sorted.length - 2];
1051
+ return lowUnhealthy >= LOW_CAP_STEP_AFTER_UNHEALTHY ? sorted[0] : sorted[sorted.length - 2];
1045
1052
  };
1046
1053
 
1047
1054
  // ../client/src/react/use-quality-governor.ts
@@ -1161,11 +1168,11 @@ function useAvatarQualityGovernor(input) {
1161
1168
  return { freezeMs: 0, jitterRising: false };
1162
1169
  }
1163
1170
  };
1164
- const applyCap = (cap, failures = 0) => {
1171
+ const applyCap = (cap, lowUnhealthy = 0) => {
1165
1172
  try {
1166
1173
  const lowCap = resolveLowCapQuality(
1167
1174
  (targetPublication?.trackInfo?.layers ?? []).map((l) => l.quality),
1168
- failures
1175
+ lowUnhealthy
1169
1176
  );
1170
1177
  targetPublication?.setVideoQuality?.(cap === "low" ? lowCap : VideoQuality.HIGH);
1171
1178
  } catch {
@@ -1190,13 +1197,13 @@ function useAvatarQualityGovernor(input) {
1190
1197
  pausedSinceTick = false;
1191
1198
  const { governor, action } = step(gov, signal, Date.now(), config);
1192
1199
  gov = governor;
1193
- if (action) applyCap(action.setCap, gov.failures);
1200
+ if (action) applyCap(action.setCap, gov.lowUnhealthy);
1194
1201
  } catch {
1195
1202
  } finally {
1196
1203
  tickRunning = false;
1197
1204
  }
1198
1205
  };
1199
- applyCap(gov.cap, gov.failures);
1206
+ applyCap(gov.cap, gov.lowUnhealthy);
1200
1207
  const handle = setInterval(() => void tick(), tickMs);
1201
1208
  return () => {
1202
1209
  disposed = true;
package/dist/server.js CHANGED
@@ -1 +1 @@
1
- export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-SKXUGNEK.js';
1
+ export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-K726WCDN.js';
@@ -1,5 +1,5 @@
1
- import { createProxyHandler } from './chunk-MJJ6GSAU.js';
2
- import './chunk-SKXUGNEK.js';
1
+ import { createProxyHandler } from './chunk-OVAQBIZ2.js';
2
+ import './chunk-K726WCDN.js';
3
3
 
4
4
  // src/tanstack-start.ts
5
5
  function realtimeAvatarServerRoute(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "realtime-avatar",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
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",