realtime-avatar 0.10.0 → 0.11.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.
@@ -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.10.0";
221
+ var SDK_VERSION = "0.11.0";
222
222
  var RealtimeAvatar = class {
223
223
  #apiKey;
224
224
  #baseUrl;
@@ -1,4 +1,4 @@
1
- import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-5UEMZN6J.js';
1
+ import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-MBQ2VKLC.js';
2
2
 
3
3
  // ../proxy/src/config.ts
4
4
  var json = (body, status = 200) => new Response(JSON.stringify(body), {
package/dist/express.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-zQtYeR_l.js';
2
- import './types-BgYFwlSn.js';
1
+ import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
+ import './types-FoJMJimV.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-UJQBYKPI.js';
2
- import './chunk-5UEMZN6J.js';
1
+ import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
+ import './chunk-MBQ2VKLC.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-zQtYeR_l.js';
2
- import './types-BgYFwlSn.js';
1
+ import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
+ import './types-FoJMJimV.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-UJQBYKPI.js';
2
- import './chunk-5UEMZN6J.js';
1
+ import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
+ import './chunk-MBQ2VKLC.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-BgYFwlSn.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-BgYFwlSn.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-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';
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-5UEMZN6J.js';
1
+ export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-MBQ2VKLC.js';
package/dist/nextjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-zQtYeR_l.js';
2
- import './types-BgYFwlSn.js';
1
+ import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
+ import './types-FoJMJimV.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-UJQBYKPI.js';
2
- import './chunk-5UEMZN6J.js';
1
+ import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
+ import './chunk-MBQ2VKLC.js';
3
3
 
4
4
  // ../proxy/src/nextjs.ts
5
5
  function createRealtimeAvatarRoute(config) {
@@ -101,11 +101,6 @@ declare const sessionClipSchema: z.ZodObject<{
101
101
  type SessionClip = z.infer<typeof sessionClipSchema>;
102
102
  declare const sessionBehaviorSchema: z.ZodObject<{
103
103
  gestures_enabled: z.ZodOptional<z.ZodBoolean>;
104
- gesture_freq: z.ZodOptional<z.ZodEnum<{
105
- sparse: "sparse";
106
- balanced: "balanced";
107
- lively: "lively";
108
- }>>;
109
104
  }, z.core.$strict>;
110
105
  type SessionBehavior = z.infer<typeof sessionBehaviorSchema>;
111
106
  /**
@@ -206,11 +201,6 @@ declare const liveKitSessionRequestSchema: z.ZodObject<{
206
201
  }, z.core.$strict>>>;
207
202
  behavior: z.ZodOptional<z.ZodObject<{
208
203
  gestures_enabled: z.ZodOptional<z.ZodBoolean>;
209
- gesture_freq: z.ZodOptional<z.ZodEnum<{
210
- sparse: "sparse";
211
- balanced: "balanced";
212
- lively: "lively";
213
- }>>;
214
204
  }, z.core.$strict>>;
215
205
  renderBackend: z.ZodOptional<z.ZodString>;
216
206
  supportEdits: z.ZodOptional<z.ZodObject<{
@@ -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-B6OnXpaC.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-B6OnXpaC.js';
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';
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';
@@ -858,38 +858,74 @@ var qualityToSignal = (q) => {
858
858
  }
859
859
  };
860
860
  function useAvatarQualityGovernor(input) {
861
- const { enabled, freezeReading, config = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
861
+ const { enabled, freezeReading, config: policy = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
862
862
  const room = useMaybeRoomContext();
863
863
  const { videoTrack } = useVoiceAssistant();
864
- const pausedSinceTick = useRef(false);
865
- const connQuality = useRef("unknown");
866
- const lastFreezeStat = useRef(null);
867
- const jitterTrend = useRef(null);
864
+ const {
865
+ openingCap,
866
+ downgradeFreezeMs,
867
+ probationFreezeMs,
868
+ openingDwellMs,
869
+ dwellBaseMs,
870
+ dwellMaxMs,
871
+ cleanMs,
872
+ probeMs,
873
+ healthyResetMs
874
+ } = policy;
875
+ const config = useMemo(() => ({
876
+ openingCap,
877
+ downgradeFreezeMs,
878
+ probationFreezeMs,
879
+ openingDwellMs,
880
+ dwellBaseMs,
881
+ dwellMaxMs,
882
+ cleanMs,
883
+ probeMs,
884
+ healthyResetMs
885
+ }), [
886
+ openingCap,
887
+ downgradeFreezeMs,
888
+ probationFreezeMs,
889
+ openingDwellMs,
890
+ dwellBaseMs,
891
+ dwellMaxMs,
892
+ cleanMs,
893
+ probeMs,
894
+ healthyResetMs
895
+ ]);
896
+ const freezeReadingRef = useRef(freezeReading);
897
+ freezeReadingRef.current = freezeReading;
898
+ const targetPublication = videoTrack?.publication;
899
+ const targetParticipant = videoTrack?.participant;
900
+ const targetTrack = targetPublication?.track;
868
901
  useEffect(() => {
869
- if (!enabled || !room) return;
870
- const targetPublication = videoTrack?.publication;
871
- const targetParticipant = videoTrack?.participant;
872
- pausedSinceTick.current = false;
873
- lastFreezeStat.current = null;
874
- jitterTrend.current = null;
875
- connQuality.current = qualityToSignal(
902
+ if (!enabled || !room || !targetPublication || !targetParticipant) return;
903
+ let pausedSinceTick = false;
904
+ let lastFreezeStat = null;
905
+ let jitterTrend = null;
906
+ let connQuality = qualityToSignal(
876
907
  targetParticipant?.connectionQuality ?? ConnectionQuality.Unknown
877
908
  );
878
909
  const onStreamState = (pub, streamState) => {
879
- if (targetPublication && pub !== targetPublication) return;
880
- if (streamState === Track.StreamState.Paused) pausedSinceTick.current = true;
910
+ if (pub !== targetPublication) return;
911
+ if (streamState === Track.StreamState.Paused) pausedSinceTick = true;
881
912
  };
882
913
  const onQuality = (q, participant) => {
883
- if (targetParticipant && participant.sid !== targetParticipant.sid) return;
884
- connQuality.current = qualityToSignal(q);
914
+ if (participant.sid !== targetParticipant.sid) return;
915
+ connQuality = qualityToSignal(q);
885
916
  };
886
917
  try {
887
918
  room.on(RoomEvent.TrackStreamStateChanged, onStreamState);
888
919
  room.on(RoomEvent.ConnectionQualityChanged, onQuality);
889
920
  } catch {
921
+ try {
922
+ room.off(RoomEvent.TrackStreamStateChanged, onStreamState);
923
+ room.off(RoomEvent.ConnectionQualityChanged, onQuality);
924
+ } catch {
925
+ }
890
926
  return;
891
927
  }
892
- let gov = initGovernor(Date.now());
928
+ let gov = initGovernor(Date.now(), config.openingCap);
893
929
  const readGetStatsSignals = async () => {
894
930
  try {
895
931
  const track = targetPublication?.track;
@@ -908,13 +944,13 @@ function useAvatarQualityGovernor(input) {
908
944
  }
909
945
  });
910
946
  const now = Date.now();
911
- const prev = lastFreezeStat.current;
912
- lastFreezeStat.current = { frozen: frozenTotalMs, ts: now };
913
- const trend = stepJitterBufferTrend(jitterTrend.current, {
947
+ const prev = lastFreezeStat;
948
+ lastFreezeStat = { frozen: frozenTotalMs, ts: now };
949
+ const trend = stepJitterBufferTrend(jitterTrend, {
914
950
  delaySeconds: jitterDelaySeconds,
915
951
  emittedCount: jitterEmittedCount
916
952
  });
917
- jitterTrend.current = trend.state;
953
+ jitterTrend = trend.state;
918
954
  return {
919
955
  freezeMs: prev ? Math.max(0, frozenTotalMs - prev.frozen) : 0,
920
956
  jitterRising: trend.rising
@@ -938,17 +974,17 @@ function useAvatarQualityGovernor(input) {
938
974
  if (disposed || tickRunning) return;
939
975
  tickRunning = true;
940
976
  try {
941
- const rvfc = freezeReading?.() ?? { freezeMsInWindow: 0, inhibited: false };
977
+ const rvfc = freezeReadingRef.current?.() ?? { freezeMsInWindow: 0, inhibited: false };
942
978
  const statsSignals = await readGetStatsSignals();
943
979
  if (disposed) return;
944
980
  const signal = {
945
- paused: pausedSinceTick.current,
981
+ paused: pausedSinceTick,
946
982
  freezeMsInWindow: Math.max(rvfc.freezeMsInWindow, statsSignals.freezeMs),
947
983
  jitterRising: statsSignals.jitterRising,
948
- connectionQuality: connQuality.current,
984
+ connectionQuality: connQuality,
949
985
  inhibited: rvfc.inhibited
950
986
  };
951
- pausedSinceTick.current = false;
987
+ pausedSinceTick = false;
952
988
  const { governor, action } = step(gov, signal, Date.now(), config);
953
989
  gov = governor;
954
990
  if (action) applyCap(action.setCap);
@@ -968,7 +1004,7 @@ function useAvatarQualityGovernor(input) {
968
1004
  } catch {
969
1005
  }
970
1006
  };
971
- }, [enabled, room, videoTrack, freezeReading, config, tickMs]);
1007
+ }, [enabled, room, targetPublication, targetParticipant, targetTrack, config, tickMs]);
972
1008
  }
973
1009
 
974
1010
  // ../client/src/react/avatar-video-surface.ts
@@ -1297,8 +1333,7 @@ var sessionChoreographySchema = z.object({
1297
1333
  { message: "idle_dwell_min_seconds must be <= idle_dwell_max_seconds" }
1298
1334
  );
1299
1335
  var sessionBehaviorSchema = z.object({
1300
- gestures_enabled: z.boolean().optional(),
1301
- gesture_freq: z.enum(["sparse", "balanced", "lively"]).optional()
1336
+ gestures_enabled: z.boolean().optional()
1302
1337
  }).strict();
1303
1338
  var transcriptWebhookSchema = z.object({
1304
1339
  url: z.string().url().max(500),
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-B6OnXpaC.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-B6OnXpaC.js';
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';
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
@@ -1059,38 +1059,74 @@ var qualityToSignal = (q) => {
1059
1059
  }
1060
1060
  };
1061
1061
  function useAvatarQualityGovernor(input) {
1062
- const { enabled, freezeReading, config = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
1062
+ const { enabled, freezeReading, config: policy = DEFAULT_GOVERNOR_CONFIG, tickMs = 1e3 } = input;
1063
1063
  const room = useMaybeRoomContext();
1064
1064
  const { videoTrack } = useVoiceAssistant();
1065
- const pausedSinceTick = useRef(false);
1066
- const connQuality = useRef("unknown");
1067
- const lastFreezeStat = useRef(null);
1068
- const jitterTrend = useRef(null);
1065
+ const {
1066
+ openingCap,
1067
+ downgradeFreezeMs,
1068
+ probationFreezeMs,
1069
+ openingDwellMs,
1070
+ dwellBaseMs,
1071
+ dwellMaxMs,
1072
+ cleanMs,
1073
+ probeMs,
1074
+ healthyResetMs
1075
+ } = policy;
1076
+ const config = useMemo(() => ({
1077
+ openingCap,
1078
+ downgradeFreezeMs,
1079
+ probationFreezeMs,
1080
+ openingDwellMs,
1081
+ dwellBaseMs,
1082
+ dwellMaxMs,
1083
+ cleanMs,
1084
+ probeMs,
1085
+ healthyResetMs
1086
+ }), [
1087
+ openingCap,
1088
+ downgradeFreezeMs,
1089
+ probationFreezeMs,
1090
+ openingDwellMs,
1091
+ dwellBaseMs,
1092
+ dwellMaxMs,
1093
+ cleanMs,
1094
+ probeMs,
1095
+ healthyResetMs
1096
+ ]);
1097
+ const freezeReadingRef = useRef(freezeReading);
1098
+ freezeReadingRef.current = freezeReading;
1099
+ const targetPublication = videoTrack?.publication;
1100
+ const targetParticipant = videoTrack?.participant;
1101
+ const targetTrack = targetPublication?.track;
1069
1102
  useEffect(() => {
1070
- if (!enabled || !room) return;
1071
- const targetPublication = videoTrack?.publication;
1072
- const targetParticipant = videoTrack?.participant;
1073
- pausedSinceTick.current = false;
1074
- lastFreezeStat.current = null;
1075
- jitterTrend.current = null;
1076
- connQuality.current = qualityToSignal(
1103
+ if (!enabled || !room || !targetPublication || !targetParticipant) return;
1104
+ let pausedSinceTick = false;
1105
+ let lastFreezeStat = null;
1106
+ let jitterTrend = null;
1107
+ let connQuality = qualityToSignal(
1077
1108
  targetParticipant?.connectionQuality ?? ConnectionQuality.Unknown
1078
1109
  );
1079
1110
  const onStreamState = (pub, streamState) => {
1080
- if (targetPublication && pub !== targetPublication) return;
1081
- if (streamState === Track.StreamState.Paused) pausedSinceTick.current = true;
1111
+ if (pub !== targetPublication) return;
1112
+ if (streamState === Track.StreamState.Paused) pausedSinceTick = true;
1082
1113
  };
1083
1114
  const onQuality = (q, participant) => {
1084
- if (targetParticipant && participant.sid !== targetParticipant.sid) return;
1085
- connQuality.current = qualityToSignal(q);
1115
+ if (participant.sid !== targetParticipant.sid) return;
1116
+ connQuality = qualityToSignal(q);
1086
1117
  };
1087
1118
  try {
1088
1119
  room.on(RoomEvent.TrackStreamStateChanged, onStreamState);
1089
1120
  room.on(RoomEvent.ConnectionQualityChanged, onQuality);
1090
1121
  } catch {
1122
+ try {
1123
+ room.off(RoomEvent.TrackStreamStateChanged, onStreamState);
1124
+ room.off(RoomEvent.ConnectionQualityChanged, onQuality);
1125
+ } catch {
1126
+ }
1091
1127
  return;
1092
1128
  }
1093
- let gov = initGovernor(Date.now());
1129
+ let gov = initGovernor(Date.now(), config.openingCap);
1094
1130
  const readGetStatsSignals = async () => {
1095
1131
  try {
1096
1132
  const track = targetPublication?.track;
@@ -1109,13 +1145,13 @@ function useAvatarQualityGovernor(input) {
1109
1145
  }
1110
1146
  });
1111
1147
  const now = Date.now();
1112
- const prev = lastFreezeStat.current;
1113
- lastFreezeStat.current = { frozen: frozenTotalMs, ts: now };
1114
- const trend = stepJitterBufferTrend(jitterTrend.current, {
1148
+ const prev = lastFreezeStat;
1149
+ lastFreezeStat = { frozen: frozenTotalMs, ts: now };
1150
+ const trend = stepJitterBufferTrend(jitterTrend, {
1115
1151
  delaySeconds: jitterDelaySeconds,
1116
1152
  emittedCount: jitterEmittedCount
1117
1153
  });
1118
- jitterTrend.current = trend.state;
1154
+ jitterTrend = trend.state;
1119
1155
  return {
1120
1156
  freezeMs: prev ? Math.max(0, frozenTotalMs - prev.frozen) : 0,
1121
1157
  jitterRising: trend.rising
@@ -1139,17 +1175,17 @@ function useAvatarQualityGovernor(input) {
1139
1175
  if (disposed || tickRunning) return;
1140
1176
  tickRunning = true;
1141
1177
  try {
1142
- const rvfc = freezeReading?.() ?? { freezeMsInWindow: 0, inhibited: false };
1178
+ const rvfc = freezeReadingRef.current?.() ?? { freezeMsInWindow: 0, inhibited: false };
1143
1179
  const statsSignals = await readGetStatsSignals();
1144
1180
  if (disposed) return;
1145
1181
  const signal = {
1146
- paused: pausedSinceTick.current,
1182
+ paused: pausedSinceTick,
1147
1183
  freezeMsInWindow: Math.max(rvfc.freezeMsInWindow, statsSignals.freezeMs),
1148
1184
  jitterRising: statsSignals.jitterRising,
1149
- connectionQuality: connQuality.current,
1185
+ connectionQuality: connQuality,
1150
1186
  inhibited: rvfc.inhibited
1151
1187
  };
1152
- pausedSinceTick.current = false;
1188
+ pausedSinceTick = false;
1153
1189
  const { governor, action } = step(gov, signal, Date.now(), config);
1154
1190
  gov = governor;
1155
1191
  if (action) applyCap(action.setCap);
@@ -1169,7 +1205,7 @@ function useAvatarQualityGovernor(input) {
1169
1205
  } catch {
1170
1206
  }
1171
1207
  };
1172
- }, [enabled, room, videoTrack, freezeReading, config, tickMs]);
1208
+ }, [enabled, room, targetPublication, targetParticipant, targetTrack, config, tickMs]);
1173
1209
  }
1174
1210
 
1175
1211
  // ../client/src/react/frame-recovery.ts
@@ -1771,8 +1807,7 @@ var sessionChoreographySchema = z.object({
1771
1807
  { message: "idle_dwell_min_seconds must be <= idle_dwell_max_seconds" }
1772
1808
  );
1773
1809
  var sessionBehaviorSchema = z.object({
1774
- gestures_enabled: z.boolean().optional(),
1775
- gesture_freq: z.enum(["sparse", "balanced", "lively"]).optional()
1810
+ gestures_enabled: z.boolean().optional()
1776
1811
  }).strict();
1777
1812
  var transcriptWebhookSchema = z.object({
1778
1813
  url: z.string().url().max(500),
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-BgYFwlSn.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';
3
3
  import 'zod';
package/dist/server.js CHANGED
@@ -1 +1 @@
1
- export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-5UEMZN6J.js';
1
+ export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, clipLibraryDeclarationSchema, isQueued, verifyTranscript } from './chunk-MBQ2VKLC.js';
@@ -1,5 +1,5 @@
1
- import { P as ProxyConfig } from './types-zQtYeR_l.js';
2
- import './types-BgYFwlSn.js';
1
+ import { P as ProxyConfig } from './types-DrgyCwLC.js';
2
+ import './types-FoJMJimV.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-UJQBYKPI.js';
2
- import './chunk-5UEMZN6J.js';
1
+ import { createProxyHandler } from './chunk-RVBBZCVM.js';
2
+ import './chunk-MBQ2VKLC.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-BgYFwlSn.js';
1
+ import { C as CallMode, a as CallPolicy } from './types-FoJMJimV.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";
@@ -132,8 +132,6 @@ interface components {
132
132
  };
133
133
  behavior?: {
134
134
  gestures_enabled?: boolean;
135
- /** @enum {string} */
136
- gesture_freq?: "sparse" | "balanced" | "lively";
137
135
  };
138
136
  expression_profile?: string;
139
137
  /** @enum {string} */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "realtime-avatar",
3
- "version": "0.10.0",
3
+ "version": "0.11.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",